From e262d9ac73af5b2cef384468c47d69917e205d44 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 7 Apr 2020 23:01:46 -0400 Subject: lots of code cleanup - removed all northstar db stuff. added scriptingBox. renamed things. made collectiontypes strings not numbers. --- src/client/views/collections/CollectionView.tsx | 52 ++++++++----------------- 1 file changed, 16 insertions(+), 36 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c7ab66c9f..5819c829f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -52,39 +52,19 @@ const path = require('path'); library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy); export enum CollectionViewType { - Invalid, - Freeform, - Schema, - Docking, - Tree, - Stacking, - Masonry, - Multicolumn, - Multirow, - Time, - Carousel, - Linear, - Staff -} - -export namespace CollectionViewType { - const stringMapping = new Map([ - ["invalid", CollectionViewType.Invalid], - ["freeform", CollectionViewType.Freeform], - ["schema", CollectionViewType.Schema], - ["docking", CollectionViewType.Docking], - ["tree", CollectionViewType.Tree], - ["stacking", CollectionViewType.Stacking], - ["masonry", CollectionViewType.Masonry], - ["multicolumn", CollectionViewType.Multicolumn], - ["multirow", CollectionViewType.Multirow], - ["time", CollectionViewType.Time], - ["carousel", CollectionViewType.Carousel], - ["linear", CollectionViewType.Linear], - ]); - - export const valueOf = (value: string) => stringMapping.get(value.toLowerCase()); - export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)?.[0]; + Invalid = "invalid", + Freeform = "freeform", + Schema = "schema", + Docking = "docking", + Tree = 'tree', + Stacking = "stacking", + Masonry = "masonry", + Multicolumn = "multicolumn", + Multirow = "multirow", + Time = "time", + Carousel = "carousel", + Linear = "linear", + Staff = "staff", } export interface CollectionRenderProps { @@ -110,7 +90,7 @@ export class CollectionView extends Touchable { protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; get collectionViewType(): CollectionViewType | undefined { - const viewField = NumCast(this.props.Document._viewType); + const viewField = StrCast(this.props.Document._viewType); if (CollectionView._safeMode) { if (viewField === CollectionViewType.Freeform) { return CollectionViewType.Tree; @@ -119,7 +99,7 @@ export class CollectionView extends Touchable { return CollectionViewType.Freeform; } } - return viewField; + return viewField as any as CollectionViewType; } active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected(outsideReaction) && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0; @@ -394,7 +374,7 @@ export class CollectionView extends Touchable { const params = { layoutDoc: Doc.name, dataDoc: Doc.name, }; newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables); } - Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); + newFacet && Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); } } -- cgit v1.2.3-70-g09d2 From d34cb78c3d42f946be62a06bed73fe1997bb25ab Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 8 Apr 2020 01:48:02 -0400 Subject: fixed bug with getDocTemplate(). fixed inPlace link following when there's no inPlaceContainer. --- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 6 ++++-- src/new_fields/Doc.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5819c829f..6e0e44d35 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -230,7 +230,7 @@ export class CollectionView extends Touchable { if (this.props.Document.childDetailed instanceof Doc) { layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" }); } - layoutItems.push({ description: "Toggle is inPlace Container", event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); + layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset":"Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f12dd76d8..df1373b14 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -4,7 +4,7 @@ import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrows import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; -import { Doc, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc"; +import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc"; import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkData, InkField, InkTool } from "../../../../new_fields/InkField"; @@ -794,7 +794,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document.scale, pt: this.Document.panTransformType }; - if (!doc.z) this.setPan(newPanX, newPanY, "Ease"); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow + if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { + if (!doc.z) this.setPan(newPanX, newPanY, "Ease"); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow + } Doc.BrushDoc(this.props.Document); this.props.focus(this.props.Document); willZoom && this.setScaleToZoom(layoutdoc, scale); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 4fc4dc1cf..a9c97fc19 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -899,7 +899,7 @@ export namespace Doc { Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); -Scripting.addGlobal(function getDocTemplate(doc?: any) { Doc.getDocTemplate(doc); }); +Scripting.addGlobal(function getDocTemplate(doc?: any) { return Doc.getDocTemplate(doc); }); Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); }); Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); -- cgit v1.2.3-70-g09d2 From 8895ea8bc50b9b69518469e24e66fad58b6bc2e7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 8 Apr 2020 14:38:56 -0400 Subject: fixed link previews to work with regions on PDFs, images etc, --- src/client/views/DocComponent.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 3 +-- src/client/views/nodes/DocumentView.tsx | 31 +++++++++++++--------- src/client/views/nodes/FormattedTextBoxComment.tsx | 17 +++++++----- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- 6 files changed, 33 insertions(+), 24 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 0c8ce28c3..bbba2712e 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -86,7 +86,7 @@ export function DocAnnotatableComponent

(schema } @action.bound addDocument(doc: Doc): boolean { - Doc.GetProto(doc).annotationOn = this.props.Document; + doc.context = Doc.GetProto(doc).annotationOn = this.props.Document; return Doc.AddDocToList(this.dataDoc, this.props.fieldKey + "-" + this._annotationKey, doc) ? true : false; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 6e0e44d35..8192e6751 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -143,7 +143,6 @@ export class CollectionView extends Touchable { // moving it into the target. @action.bound moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean { - doc.context = targetCollection; if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } @@ -230,7 +229,7 @@ export class CollectionView extends Touchable { if (this.props.Document.childDetailed instanceof Doc) { layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" }); } - layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset":"Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); + layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1a33e3000..867405d54 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -196,27 +196,31 @@ export class DocumentView extends DocComponent(Docu this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this))); // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this))); - !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.push(this); + if (!this.props.dontRegisterView) { + DocumentManager.Instance.DocumentViews.push(this); + } } @action componentDidUpdate() { - this._dropDisposer && this._dropDisposer(); - this._gestureEventDisposer && this._gestureEventDisposer(); - this.multiTouchDisposer && this.multiTouchDisposer(); - this.holdDisposer && this.holdDisposer(); - this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this))); - this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this))); - this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this))); - this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this))); + this._dropDisposer?.(); + this._gestureEventDisposer?.(); + this.multiTouchDisposer?.(); + this.holdDisposer?.(); + if (this._mainCont.current) { + this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)); + this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)); + this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)); + this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)); + } } @action componentWillUnmount() { - this._dropDisposer && this._dropDisposer(); - this._gestureEventDisposer && this._gestureEventDisposer(); - this.multiTouchDisposer && this.multiTouchDisposer(); - this.holdDisposer && this.holdDisposer(); + this._dropDisposer?.(); + this._gestureEventDisposer?.(); + this.multiTouchDisposer?.(); + this.holdDisposer?.(); Doc.UnBrushDoc(this.props.Document); if (!this.props.dontRegisterView) { const index = DocumentManager.Instance.DocumentViews.indexOf(this); @@ -982,6 +986,7 @@ export class DocumentView extends DocComponent(Docu LayoutDoc={this.props.LayoutDoc} makeLink={this.makeLink} rootSelected={this.rootSelected} + dontRegisterView={this.props.dontRegisterView} fitToBox={this.props.fitToBox} LibraryPath={this.props.LibraryPath} addDocument={this.props.addDocument} diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx index 20d734244..1e48c76e7 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/FormattedTextBoxComment.tsx @@ -2,7 +2,7 @@ import { Mark, ResolvedPos } from "prosemirror-model"; import { EditorState, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, DocCastAsync } from "../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath } from "../../../Utils"; import { DocServer } from "../../DocServer"; @@ -100,6 +100,7 @@ export class FormattedTextBoxComment { public static Hide() { FormattedTextBoxComment.textBox = undefined; FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none"); + ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); } public static SetState(textBox: any, start: number, end: number, mark: Mark) { FormattedTextBoxComment.textBox = textBox; @@ -167,14 +168,18 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltipText.textContent = "target not found..."; (FormattedTextBoxComment.tooltipText as any).href = ""; const docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0]; - docTarget && DocServer.GetRefField(docTarget).then(linkDoc => { + try { + ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); + } catch (e) { } + docTarget && DocServer.GetRefField(docTarget).then(async linkDoc => { if (linkDoc instanceof Doc) { (FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href; FormattedTextBoxComment.linkDoc = linkDoc; - const target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); - try { - ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); - } catch (e) { } + const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); + const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; + if (anchor !== target && anchor && target) { + target.scrollY = NumCast(anchor?.y); + } if (target) { ReactDOM.render( _pdfjsRequested = false; render() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null); - if (this.props.isSelected() || this.props.Document.scrollY !== undefined) this._everActive = true; + if (this.props.isSelected() || this.props.renderDepth <= 1 || this.props.Document.scrollY !== undefined) this._everActive = true; if (pdfUrl && (this._everActive || this.props.Document._scrollTop || (this.dataDoc[this.props.fieldKey + "-nativeWidth"] && this.props.ScreenToLocalTransform().Scale < 2.5))) { if (pdfUrl instanceof PdfField && this._pdf) { return this.renderPdfView; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 90cd64f3c..f93c1fa97 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -164,7 +164,7 @@ export class PDFViewer extends DocAnnotatableComponent { - this._reactionDisposer && this._reactionDisposer(); + this._reactionDisposer?.(); this._scrollTopReactionDisposer?.(); this._annotationReactionDisposer?.(); this._filterReactionDisposer?.(); -- cgit v1.2.3-70-g09d2 From e4b22138e39244728144fbdd4c06e439be1b519a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 10 Apr 2020 13:24:07 -0400 Subject: more cleanup for layoutDoc/dataDoc/rootDoc updates. fix to doc filtering checkboxes getting filtered. fix to template captions. fixes to generalize LabelDoc's buttonParms --- src/client/documents/Documents.ts | 10 ++--- src/client/util/DragManager.ts | 2 +- src/client/util/DropConverter.ts | 2 +- src/client/util/RichTextRules.ts | 2 +- src/client/views/DocComponent.tsx | 16 +++---- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/InkingStroke.tsx | 4 +- src/client/views/TemplateMenu.tsx | 6 +-- src/client/views/collections/CollectionSubView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 16 ++++--- src/client/views/collections/CollectionView.tsx | 17 ++++---- .../views/collections/CollectionViewChromes.tsx | 23 ++-------- src/client/views/nodes/AudioBox.tsx | 8 ++-- src/client/views/nodes/ColorBox.tsx | 4 +- src/client/views/nodes/DocumentBox.tsx | 6 +-- src/client/views/nodes/DocumentView.tsx | 6 +-- src/client/views/nodes/FontIconBox.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 4 +- src/client/views/nodes/LabelBox.tsx | 48 +++++++++----------- src/client/views/nodes/LinkAnchorBox.tsx | 4 +- src/client/views/nodes/LinkBox.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 4 +- src/client/views/nodes/PresBox.tsx | 4 +- src/client/views/nodes/QueryBox.tsx | 4 +- src/client/views/nodes/ScreenshotBox.tsx | 6 +-- src/client/views/nodes/ScriptingBox.tsx | 4 +- src/client/views/nodes/SliderBox.tsx | 51 ++++++++++------------ src/client/views/nodes/VideoBox.tsx | 4 +- src/client/views/nodes/WebBox.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 4 +- .../views/presentationview/PresElementBox.tsx | 4 +- src/new_fields/Doc.ts | 9 ++-- src/new_fields/RichTextField.ts | 4 ++ 34 files changed, 137 insertions(+), 159 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c823c3233..22f22cbfd 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -566,8 +566,8 @@ export namespace Docs { LinkManager.Instance.addLink(doc); - Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(this)"); - Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(this)"); + Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)"); + Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)"); return doc; } @@ -908,10 +908,10 @@ export namespace DocUtils { if (target.doc === CurrentUserUtils.UserDocument) return undefined; const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship }, id); - Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('this.anchor1.title +" (" + (this.linkRelationship||"to") +") " + this.anchor2.title'); + Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2.title'); - Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(this)"); - Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(this)"); + Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)"); + Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)"); return linkDoc; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c856bbb1e..346eb2fb4 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -222,7 +222,7 @@ export namespace DragManager { const bd = Docs.Create.ButtonDocument({ _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }); params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); initialize?.(bd); - bd.buttonParams = new List(params); + bd["onclick-params"] = new List(params); e.docDragData && (e.docDragData.droppedDocuments = [bd]); }; StartDrag(eles, new DragManager.DocumentDragData([]), downX, downY, options, finishDrag); diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index eb4d3a9b0..8cea120cd 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -35,7 +35,7 @@ export function makeTemplate(doc: Doc, first: boolean = true, rename: Opt Opt; @@ -22,15 +22,15 @@ export function DocComponent

(schemaCtor: (doc: D // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { return Doc.Layout(this.props.Document); } // This is the data part of a document -- ie, the data that is constant across all views of the document - @computed get dataDoc() { return this.props.Document[DataSym]; } + @computed get dataDoc() { return this.props.Document[DataSym] as Doc; } protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; } return Component; } -/// DocStaticProps return a base class for React document views that have data extensions but aren't annotatable (e.g. AudioBox, FormattedTextBox) -interface DocExtendableProps { +/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. AudioBox, FormattedTextBox) +interface ViewBoxBaseProps { Document: Doc; DataDoc?: Doc; fieldKey: string; @@ -38,7 +38,7 @@ interface DocExtendableProps { renderDepth: number; rootSelected: (outsideReaction?: boolean) => boolean; } -export function DocExtendableComponent

(schemaCtor: (doc: Doc) => T) { +export function ViewBoxBaseComponent

(schemaCtor: (doc: Doc) => T) { class Component extends Touchable

{ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then //@computed get Document(): T { return schemaCtor(this.props.Document); } @@ -60,8 +60,8 @@ export function DocExtendableComponent

(schemaCt } -/// DocAnnotatbleComponent return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image) -export interface DocAnnotatableProps { +/// DocAnnotatbleComponent -return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image) +export interface ViewBoxAnnotatableProps { Document: Doc; DataDoc?: Doc; fieldKey: string; @@ -71,7 +71,7 @@ export interface DocAnnotatableProps { rootSelected: (outsideReaction?: boolean) => boolean; renderDepth: number; } -export function DocAnnotatableComponent

(schemaCtor: (doc: Doc) => T) { +export function ViewBoxAnnotatableComponent

(schemaCtor: (doc: Doc) => T) { class Component extends Touchable

{ @observable _isChildActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index bd72385ef..c49fe157c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -393,7 +393,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (SelectionManager.SelectedDocuments().length === 1) { const selected = SelectionManager.SelectedDocuments()[0]; if (this._titleControlString.startsWith("=")) { - return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ this: selected.props.Document }, console.log).result?.toString() || ""; + return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || ""; } if (this._titleControlString.startsWith("#")) { return selected.props.Document[this._titleControlString.substring(1)]?.toString() || "-unset-"; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index ff63a7c33..f66c04e1f 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -4,7 +4,7 @@ import { documentSchema } from "../../new_fields/documentSchemas"; import { InkData, InkField, InkTool } from "../../new_fields/InkField"; import { makeInterface } from "../../new_fields/Schema"; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; -import { DocExtendableComponent } from "./DocComponent"; +import { ViewBoxBaseComponent } from "./DocComponent"; import { InkingControl } from "./InkingControl"; import "./InkingStroke.scss"; import { FieldView, FieldViewProps } from "./nodes/FieldView"; @@ -22,7 +22,7 @@ type InkDocument = makeInterface<[typeof documentSchema]>; const InkDocument = makeInterface(documentSchema); @observer -export class InkingStroke extends DocExtendableComponent(InkDocument) { +export class InkingStroke extends ViewBoxBaseComponent(InkDocument) { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); } private analyzeStrokes = () => { diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 8fb8e7516..4d7f1e443 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -76,7 +76,7 @@ export class TemplateMenu extends React.Component { @undoBatch @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { - this.props.docViews.forEach(d => Doc.Layout(d.Document)["_show" + template.Name] = event.target.checked ? template.Name.toLowerCase() : ""); + this.props.docViews.forEach(d => Doc.Layout(d.layoutDoc)["_show" + template.Name] = event.target.checked ? template.Name.toLowerCase() : ""); } @action @@ -87,7 +87,7 @@ export class TemplateMenu extends React.Component { @undoBatch @action toggleChrome = (): void => { - this.props.docViews.map(dv => Doc.Layout(dv.Document)).forEach(layout => + this.props.docViews.map(dv => Doc.Layout(dv.layoutDoc)).forEach(layout => layout._chromeStatus = (layout._chromeStatus !== "disabled" ? "disabled" : StrCast(layout._replacedChrome, "enabled"))); } @@ -124,7 +124,7 @@ export class TemplateMenu extends React.Component { templateMenu.push(); templateMenu.push(); if (noteTypesDoc) { - addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(this)`)); + addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(self)`)); this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push( this.toggleLayout(e, template)} />)); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 41f4fb3f0..0c00a1f22 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -120,8 +120,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: return Cast(this.dataField, listSpec(Doc)); } @computed get childDocs() { - const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), []); - const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string"), []); + const docFilters = this.props.ignoreFields?.includes("_docFilters") ? [] : Cast(this.props.Document._docFilters, listSpec("string"), []); + const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []); const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields for (let i = 0; i < docFilters.length; i += 3) { const [key, value, modifiers] = docFilters.slice(i, i + 3); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7edda5a4f..fd84c6498 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -735,16 +735,18 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as heroView._showTitle = "title"; heroView._showTitleHover = "titlehover"; - Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", + Doc.AddDocToList(Doc.UserDoc().expandingButtons as Doc, "data", Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: heroView, removeDropProperties: new List(["dropAction"]), title: "hero view", icon: "portrait" + title: "hero view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", + dragFactory: heroView, removeDropProperties: new List(["dropAction"]), icon: "portrait", + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), })); - Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", + Doc.AddDocToList(Doc.UserDoc().expandingButtons as Doc, "data", Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: detailView, removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "file-alt" + title: "detail view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", + dragFactory: detailView, removeDropProperties: new List(["dropAction"]), icon: "file-alt", + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), })); Document.childLayout = heroView; @@ -837,7 +839,7 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey Docs.Create.TextDocument("", { title: facetValue.toString(), treeViewChecked: ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", - { layoutDoc: Doc.name, facetHeader: "string", facetValue: "string" }, + {}, { layoutDoc, facetHeader, facetValue }) })); return new List(facetValueDocSet); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8192e6751..821840e0b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -354,14 +354,15 @@ export class CollectionView extends Touchable { let newFacet: Opt; if (nonNumbers / allCollectionDocs.length < .1) { newFacet = Docs.Create.SliderDocument({ title: facetHeader }); + const newFacetField = Doc.LayoutFieldKey(newFacet); const ranged = Doc.readDocRangeFilter(this.props.Document, facetHeader); Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox newFacet.treeViewExpandedView = "layout"; newFacet.treeViewOpen = true; - newFacet._sliderMin = ranged === undefined ? minVal : ranged[0]; - newFacet._sliderMax = ranged === undefined ? maxVal : ranged[1]; - newFacet._sliderMinThumb = minVal; - newFacet._sliderMaxThumb = maxVal; + newFacet[newFacetField + "-min"] = ranged === undefined ? minVal : ranged[0]; + newFacet[newFacetField + "-max"] = ranged === undefined ? maxVal : ranged[1]; + Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = minVal; + Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = maxVal; newFacet.target = this.props.Document; const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`; newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" }); @@ -370,14 +371,12 @@ export class CollectionView extends Touchable { } else { 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); + newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables); } newFacet && Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); } } - onPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); @@ -385,11 +384,11 @@ export class CollectionView extends Touchable { }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0)); } filterBackground = () => "dimGray"; + get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves) @computed get scriptField() { const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)"; return ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name }); } - @computed get treeIgnoreFields() { return ["_facetCollection", "_docFilters"]; } @computed get filterView() { const facetCollection = this.props.Document; const flyout = ( @@ -419,7 +418,7 @@ export class CollectionView extends Touchable { NativeWidth={returnZero} treeViewHideHeaderFields={true} onCheckedClick={this.scriptField!} - ignoreFields={this.treeIgnoreFields} + ignoreFields={this.ignoreFields} annotationsKey={""} dontRegisterView={true} PanelWidth={this.facetWidth} diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index b2ca3c19f..ba95dce00 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -361,28 +361,13 @@ export class CollectionViewBaseChrome extends React.Component { - this._startDragPosition = { x: e.clientX, y: e.clientY }; - document.addEventListener("pointermove", this.dragPointerMove); - document.addEventListener("pointerup", this.dragPointerUp); - e.stopPropagation(); - e.preventDefault(); - } - - dragPointerMove = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - const [dx, dy] = [e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y]; - if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) { + setupMoveUpEvents(this, e, (e, down, delta) => { this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title, { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY)); - document.removeEventListener("pointermove", this.dragPointerMove); - document.removeEventListener("pointerup", this.dragPointerUp); - } - } - dragPointerUp = (e: PointerEvent) => { - document.removeEventListener("pointermove", this.dragPointerMove); - document.removeEventListener("pointerup", this.dragPointerUp); + return true; + }, emptyFunction, emptyFunction); + this._startDragPosition = { x: e.clientX, y: e.clientY }; } render() { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index c08a2b808..7078cc01c 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import "./AudioBox.scss"; import { Cast, DateCast, NumCast } from "../../../new_fields/Types"; import { AudioField, nullAudio } from "../../../new_fields/URLField"; -import { DocExtendableComponent } from "../DocComponent"; +import { ViewBoxBaseComponent } from "../DocComponent"; import { makeInterface, createSchema } from "../../../new_fields/Schema"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero } from "../../../Utils"; @@ -39,7 +39,7 @@ type AudioDocument = makeInterface<[typeof documentSchema, typeof audioSchema]>; const AudioDocument = makeInterface(documentSchema, audioSchema); @observer -export class AudioBox extends DocExtendableComponent(AudioDocument) { +export class AudioBox extends ViewBoxBaseComponent(AudioDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); } public static Enabled = false; @@ -194,8 +194,8 @@ export class AudioBox extends DocExtendableComponent; const ColorDocument = makeInterface(documentSchema); @observer -export class ColorBox extends DocExtendableComponent(ColorDocument) { +export class ColorBox extends ViewBoxBaseComponent(ColorDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ColorBox, fieldKey); } render() { diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx index 4f2b3b656..ac562f19a 100644 --- a/src/client/views/nodes/DocumentBox.tsx +++ b/src/client/views/nodes/DocumentBox.tsx @@ -9,7 +9,7 @@ import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { emptyPath } from "../../../Utils"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; -import { DocAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; import "./DocumentBox.scss"; import { FieldView, FieldViewProps } from "./FieldView"; @@ -22,7 +22,7 @@ type DocHolderBoxSchema = makeInterface<[typeof documentSchema]>; const DocHolderBoxDocument = makeInterface(documentSchema); @observer -export class DocHolderBox extends DocAnnotatableComponent(DocHolderBoxDocument) { +export class DocHolderBox extends ViewBoxAnnotatableComponent(DocHolderBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocHolderBox, fieldKey); } _prevSelectionDisposer: IReactionDisposer | undefined; _selections: Doc[] = []; @@ -54,7 +54,7 @@ export class DocHolderBox extends DocAnnotatableComponent { - this.contentDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(this,this.excludeCollections,[_last_])?.[0]`); + this.contentDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(self,this.excludeCollections,[_last_])?.[0]`); } isSelectionLocked = () => { const kvpstring = Field.toKeyValueString(this.contentDoc, this.props.fieldKey); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1bccce054..1e22dbc0b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -298,7 +298,7 @@ export class DocumentView extends DocComponent(Docu } else if (this.onClickHandler?.script) { SelectionManager.DeselectAll(); const func = () => this.onClickHandler.script.run({ - this: this.props.Document, + this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log); @@ -512,8 +512,8 @@ export class DocumentView extends DocComponent(Docu onPointerUp = (e: PointerEvent): void => { this.cleanUpInteractions(); - if (this.onPointerUpHandler && this.onPointerUpHandler.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - this.onPointerUpHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log); + if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { + this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); document.removeEventListener("pointerup", this.onPointerUp); return; } diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index bd7ea4c92..9329cf210 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -56,7 +56,7 @@ export class FontIconBox extends DocComponent( background: StrCast(referenceLayout.backgroundColor), boxShadow: this.props.Document.ischecked ? `4px 4px 12px black` : undefined }}> - + ; } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index fb919a716..d641dc791 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -38,7 +38,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager"; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { DocAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { DocumentButtonBar } from '../DocumentButtonBar'; import { InkingControl } from "../InkingControl"; import { AudioBox } from './AudioBox'; @@ -69,7 +69,7 @@ const RichTextDocument = makeInterface(richTextSchema, documentSchema); type PullHandler = (exportState: Opt, dataDoc: Doc) => void; @observer -export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) { +export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); } public static blankState = () => EditorState.create(FormattedTextBox.Instance.config); public static Instance: FormattedTextBox; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index bb7d78ace..5b0edf34f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -24,7 +24,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenuProps } from '../ContextMenuItem'; -import { DocAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import FaceRectangles from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; @@ -65,7 +65,7 @@ const uploadIcons = { }; @observer -export class ImageBox extends DocAnnotatableComponent(ImageDocument) { +export class ImageBox extends ViewBoxAnnotatableComponent(ImageDocument) { protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject = React.createRef(); diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 0ec6af93a..b9701f923 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -7,10 +7,10 @@ import { Doc, DocListCast } from '../../../new_fields/Doc'; import { List } from '../../../new_fields/List'; import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema'; import { ScriptField } from '../../../new_fields/ScriptField'; -import { BoolCast, StrCast, Cast, FieldValue } from '../../../new_fields/Types'; +import { BoolCast, StrCast, Cast, FieldValue, NumCast } from '../../../new_fields/Types'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; -import { DocComponent } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; import './LabelBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; import { ContextMenuProps } from '../ContextMenuItem'; @@ -20,27 +20,16 @@ import { documentSchema } from '../../../new_fields/documentSchemas'; library.add(faEdit as any); -const LabelSchema = createSchema({ - onClick: ScriptField, - buttonParams: listSpec("string"), - text: "string" -}); +const LabelSchema = createSchema({}); type LabelDocument = makeInterface<[typeof LabelSchema, typeof documentSchema]>; const LabelDocument = makeInterface(LabelSchema, documentSchema); @observer -export class LabelBox extends DocComponent(LabelDocument) { +export class LabelBox extends ViewBoxBaseComponent(LabelDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); } private dropDisposer?: DragManager.DragDropDisposer; - @computed get dataDoc() { - return this.props.DataDoc && - (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) || - this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); - } - - protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer?.(); if (ele) { @@ -52,8 +41,8 @@ export class LabelBox extends DocComponent(LabelD const funcs: ContextMenuProps[] = []; funcs.push({ description: "Clear Script Params", event: () => { - const params = FieldValue(this.Document.buttonParams); - params?.map(p => this.props.Document[p] = undefined); + const params = Cast(this.dataDoc[this.fieldKey + "-params"], listSpec("string"), []); + params?.map(p => this.dataDoc[p] = undefined); }, icon: "trash" }); @@ -64,32 +53,35 @@ export class LabelBox extends DocComponent(LabelD @action drop = (e: Event, de: DragManager.DropEvent) => { const docDragData = de.complete.docDragData; - const params = this.Document.buttonParams; - const missingParams = params?.filter(p => this.props.Document[p] === undefined); + const params = Cast(this.dataDoc[this.fieldKey + "-params"], listSpec("string"), []); + const missingParams = params?.filter(p => this.dataDoc[p] === undefined); if (docDragData && missingParams?.includes((e.target as any).textContent)) { - this.props.Document[(e.target as any).textContent] = new List(docDragData.droppedDocuments.map((d, i) => + this.dataDoc[(e.target as any).textContent] = new List(docDragData.droppedDocuments.map((d, i) => d.onDragStart ? docDragData.draggedDocuments[i] : d)); e.stopPropagation(); } } // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")") render() { - const params = this.Document.buttonParams; - const missingParams = params?.filter(p => this.props.Document[p] === undefined); - params?.map(p => DocListCast(this.props.Document[p])); // bcz: really hacky form of prefetching ... + const params = Cast(this.dataDoc[this.fieldKey + "-params"], listSpec("string"), []); + const missingParams = params?.filter(p => this.dataDoc[p] === undefined); + params?.map(p => DocListCast(this.dataDoc[p])); // bcz: really hacky form of prefetching ... return (

+ style={{ boxShadow: this.layoutDoc.opacity ? StrCast(this.layoutDoc.boxShadow) : "" }}>
- {(this.Document.text || this.Document.title)} + {StrCast(this.layoutDoc.text, StrCast(this.layoutDoc.title))}
- {!missingParams || !missingParams.length ? (null) : missingParams.map(m =>
{m}
)} + {!missingParams?.length ? (null) : missingParams.map(m =>
{m}
)}
); diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index f3e099dd6..13ffc6956 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -7,7 +7,7 @@ import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { Utils, setupMoveUpEvents } from '../../../Utils'; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; -import { DocExtendableComponent } from "../DocComponent"; +import { ViewBoxBaseComponent } from "../DocComponent"; import "./LinkAnchorBox.scss"; import { FieldView, FieldViewProps } from "./FieldView"; import React = require("react"); @@ -25,7 +25,7 @@ type LinkAnchorSchema = makeInterface<[typeof documentSchema]>; const LinkAnchorDocument = makeInterface(documentSchema); @observer -export class LinkAnchorBox extends DocExtendableComponent(LinkAnchorDocument) { +export class LinkAnchorBox extends ViewBoxBaseComponent(LinkAnchorDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } _doubleTap = false; _lastTap: number = 0; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 542c86049..af4bf420f 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -4,7 +4,7 @@ import { documentSchema } from "../../../new_fields/documentSchemas"; import { makeInterface, listSpec } from "../../../new_fields/Schema"; import { returnFalse, returnZero } from "../../../Utils"; import { CollectionTreeView } from "../collections/CollectionTreeView"; -import { DocExtendableComponent } from "../DocComponent"; +import { ViewBoxBaseComponent } from "../DocComponent"; import { FieldView, FieldViewProps } from './FieldView'; import "./LinkBox.scss"; import { Cast } from "../../../new_fields/Types"; @@ -13,7 +13,7 @@ type LinkDocument = makeInterface<[typeof documentSchema]>; const LinkDocument = makeInterface(documentSchema); @observer -export class LinkBox extends DocExtendableComponent(LinkDocument) { +export class LinkBox extends ViewBoxBaseComponent(LinkDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); } render() { return
(PdfDocument) { +export class PDFBox extends ViewBoxAnnotatableComponent(PdfDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } private _keyValue: string = ""; private _valueValue: string = ""; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index bea3170ac..e428e16da 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -16,7 +16,7 @@ import { CollectionView, CollectionViewType } from "../collections/CollectionVie import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; -import { DocExtendableComponent } from "../DocComponent"; +import { ViewBoxBaseComponent } from "../DocComponent"; import { makeInterface } from "../../../new_fields/Schema"; library.add(faArrowLeft); @@ -33,7 +33,7 @@ type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @observer -export class PresBox extends DocExtendableComponent(PresBoxDocument) { +export class PresBox extends ViewBoxBaseComponent(PresBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } _childReaction: IReactionDisposer | undefined; @observable _isChildActive = false; diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx index 7016b4f04..947167200 100644 --- a/src/client/views/nodes/QueryBox.tsx +++ b/src/client/views/nodes/QueryBox.tsx @@ -6,7 +6,7 @@ import { Id } from '../../../new_fields/FieldSymbols'; import { makeInterface } from "../../../new_fields/Schema"; import { StrCast } from "../../../new_fields/Types"; import { SelectionManager } from "../../util/SelectionManager"; -import { DocAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { SearchBox } from "../search/SearchBox"; import { FieldView, FieldViewProps } from './FieldView'; import "./QueryBox.scss"; @@ -15,7 +15,7 @@ type QueryDocument = makeInterface<[typeof documentSchema]>; const QueryDocument = makeInterface(documentSchema); @observer -export class QueryBox extends DocAnnotatableComponent(QueryDocument) { +export class QueryBox extends ViewBoxAnnotatableComponent(QueryDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); } _docListChangedReaction: IReactionDisposer | undefined; componentDidMount() { diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 1a991f1eb..11b24b059 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -14,7 +14,7 @@ import { Docs, DocUtils } from "../../documents/Documents"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; -import { DocComponent } from "../DocComponent"; +import { ViewBoxBaseComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; import "./ScreenshotBox.scss"; @@ -26,7 +26,7 @@ const ScreenshotDocument = makeInterface(documentSchema, positionSchema); library.add(faVideo); @observer -export class ScreenshotBox extends DocComponent(ScreenshotDocument) { +export class ScreenshotBox extends ViewBoxBaseComponent(ScreenshotDocument) { private _reactionDisposer?: IReactionDisposer; private _videoRef: HTMLVideoElement | null = null; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } @@ -109,7 +109,7 @@ export class ScreenshotBox extends DocComponent { - const field = Cast(this.dataDoc[this.props.fieldKey], VideoField); + const field = Cast(this.dataDoc[this.fieldKey], VideoField); if (field) { const url = field.url.href; const subitems: ContextMenuProps[] = []; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 309ee3620..70f29e1dc 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -7,7 +7,7 @@ import { ScriptField } from "../../../new_fields/ScriptField"; import { StrCast, ScriptCast, Cast } from "../../../new_fields/Types"; import { InteractionUtils } from "../../util/InteractionUtils"; import { CompileScript, isCompileError, ScriptParam } from "../../util/Scripting"; -import { DocAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { EditableView } from "../EditableView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./ScriptingBox.scss"; @@ -20,7 +20,7 @@ type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentS const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema); @observer -export class ScriptingBox extends DocAnnotatableComponent(ScriptingDocument) { +export class ScriptingBox extends ViewBoxAnnotatableComponent(ScriptingDocument) { protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); } diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx index 844d95d11..746ea0b64 100644 --- a/src/client/views/nodes/SliderBox.tsx +++ b/src/client/views/nodes/SliderBox.tsx @@ -1,22 +1,20 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEdit } from '@fortawesome/free-regular-svg-icons'; -import { computed, runInAction } from 'mobx'; +import { runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Handles, Rail, Slider, Tracks, Ticks } from 'react-compound-slider'; -import { Doc } from '../../../new_fields/Doc'; +import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider'; import { documentSchema } from '../../../new_fields/documentSchemas'; -import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; +import { createSchema, makeInterface } from '../../../new_fields/Schema'; import { ScriptField } from '../../../new_fields/ScriptField'; -import { BoolCast, FieldValue, StrCast, NumCast, Cast } from '../../../new_fields/Types'; -import { DragManager } from '../../util/DragManager'; +import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { DocComponent } from '../DocComponent'; -import './SliderBox.scss'; -import { Handle, TooltipRail, Track, Tick } from './SliderBox-components'; -import { FieldView, FieldViewProps } from './FieldView'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { ScriptBox } from '../ScriptBox'; +import { FieldView, FieldViewProps } from './FieldView'; +import { Handle, Tick, TooltipRail, Track } from './SliderBox-components'; +import './SliderBox.scss'; library.add(faEdit as any); @@ -32,36 +30,33 @@ type SliderDocument = makeInterface<[typeof SliderSchema, typeof documentSchema] const SliderDocument = makeInterface(SliderSchema, documentSchema); @observer -export class SliderBox extends DocComponent(SliderDocument) { +export class SliderBox extends ViewBoxBaseComponent(SliderDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SliderBox, fieldKey); } - private dropDisposer?: DragManager.DragDropDisposer; - - @computed get dataDoc() { - return this.props.DataDoc && - (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) || - this.props.DataDoc.layout === this.Document) ? this.props.DataDoc : Doc.GetProto(this.Document); - } + get minThumbKey() { return this.fieldKey + "-minThumb"; } + get maxThumbKey() { return this.fieldKey + "-maxThumb"; } + get minKey() { return this.fieldKey + "-min"; } + get maxKey() { return this.fieldKey + "-max"; } specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Edit Thumb Change Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Thumb Change ...", this.props.Document, "onThumbChange", obj.x, obj.y) }); ContextMenu.Instance.addItem({ description: "Slider Funcs...", subitems: funcs, icon: "asterisk" }); } onChange = (values: readonly number[]) => runInAction(() => { - this.Document._sliderMinThumb = values[0]; - this.Document._sliderMaxThumb = values[1]; - Cast(this.Document.onThumbChanged, ScriptField, null)?.script.run({ range: values, this: this.props.Document }); + this.dataDoc[this.minThumbKey] = values[0]; + this.dataDoc[this.maxThumbKey] = values[1]; + Cast(this.layoutDoc.onThumbChanged, ScriptField, null)?.script.run({ self: this.rootDoc, range: values, this: this.layoutDoc }); }) render() { - const domain = [NumCast(this.props.Document._sliderMin), NumCast(this.props.Document._sliderMax)]; - const defaultValues = [NumCast(this.props.Document._sliderMinThumb), NumCast(this.props.Document._sliderMaxThumb)]; - return ( + const domain = [NumCast(this.layoutDoc[this.minKey]), NumCast(this.layoutDoc[this.maxKey])]; + const defaultValues = [NumCast(this.dataDoc[this.minThumbKey]), NumCast(this.dataDoc[this.maxThumbKey])]; + return domain[1] <= domain[0] ? (null) : (
e.stopPropagation()} - style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}> + style={{ boxShadow: this.layoutDoc.opacity === 0 ? undefined : StrCast(this.layoutDoc.boxShadow, "") }}>
(Slid {({ handles, activeHandleID, getHandleProps }) => (
{handles.map((handle, i) => { - const value = i === 0 ? this.Document._sliderMinThumb : this.Document._sliderMaxThumb; + const value = i === 0 ? defaultValues[0] : defaultValues[1]; return (
(VideoDocument) { +export class VideoBox extends ViewBoxAnnotatableComponent(VideoDocument) { static _youtubeIframeCounter: number = 0; private _reactionDisposer?: IReactionDisposer; private _youtubeReactionDisposer?: IReactionDisposer; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index ea5d601ec..55ad7eb0f 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -14,7 +14,7 @@ import { Docs } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; import { SelectionManager } from "../../util/SelectionManager"; -import { DocAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; @@ -33,7 +33,7 @@ type WebDocument = makeInterface<[typeof documentSchema]>; const WebDocument = makeInterface(documentSchema); @observer -export class WebBox extends DocAnnotatableComponent(WebDocument) { +export class WebBox extends ViewBoxAnnotatableComponent(WebDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } @observable private collapsed: boolean = true; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f93c1fa97..c49e6512a 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -23,7 +23,7 @@ import Annotation from "./Annotation"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { SelectionManager } from "../../util/SelectionManager"; import { undoBatch } from "../../util/UndoManager"; -import { DocAnnotatableComponent } from "../DocComponent"; +import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { DocumentType } from "../../documents/DocumentTypes"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { DocumentDecorations } from "../DocumentDecorations"; @@ -79,7 +79,7 @@ interface IViewerProps { * Handles rendering and virtualization of the pdf */ @observer -export class PDFViewer extends DocAnnotatableComponent(PdfDocument) { +export class PDFViewer extends ViewBoxAnnotatableComponent(PdfDocument) { static _annotationStyle: any = addStyleSheet(); @observable private _pageSizes: { width: number, height: number }[] = []; @observable private _annotations: Doc[] = []; diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index bed181ab9..dd0cbf929 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -12,7 +12,7 @@ import { Cast, NumCast } from "../../../new_fields/Types"; import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils"; import { Transform } from "../../util/Transform"; import { CollectionViewType } from '../collections/CollectionView'; -import { DocExtendableComponent } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./PresElementBox.scss"; @@ -44,7 +44,7 @@ const PresDocument = makeInterface(presSchema, documentSchema); * It involves some functionality for its buttons and options. */ @observer -export class PresElementBox extends DocExtendableComponent(PresDocument) { +export class PresElementBox extends ViewBoxBaseComponent(PresDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); } _heightDisposer: IReactionDisposer | undefined; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a9c97fc19..934ba0f60 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -645,11 +645,12 @@ export namespace Doc { Cast(templateFieldValue, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateFieldValue)); } - if (templateCaptionValue instanceof RichTextField && (templateCaptionValue.Text || templateCaptionValue.Data.toString().includes("dashField"))) { - templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`, { this: Doc.name }); + // copy the textTemplates from 'this' (not 'self') because the layout contains the template info, not the original doc + if (templateCaptionValue instanceof RichTextField && !templateCaptionValue.Empty()) { + templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`); } - if (templateFieldValue instanceof RichTextField && (templateFieldValue.Text || templateFieldValue.Data.toString().includes("dashField"))) { - templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name }); + if (templateFieldValue instanceof RichTextField && !templateFieldValue.Empty()) { + templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`); } // get the layout string that the template uses to specify its layout diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index a5a81f4a4..5cf0e0cc3 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -19,6 +19,10 @@ export class RichTextField extends ObjectField { this.Text = text; } + Empty() { + return !(this.Text || this.Data.toString().includes("dashField")); + } + [Copy]() { return new RichTextField(this.Data, this.Text); } -- cgit v1.2.3-70-g09d2 From 348e794e7ff341a4358be6ed9515fc6ae723092e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sun, 12 Apr 2020 21:36:26 -0700 Subject: rough pass at collection map view --- package-lock.json | 68 +++++++++++++++----- package.json | 6 +- src/client/Network.ts | 13 ++++ src/client/cognitive_services/CognitiveServices.ts | 1 - src/client/documents/Documents.ts | 9 ++- src/client/views/Main.tsx | 1 - .../views/collections/CollectionMapView.scss | 4 ++ src/client/views/collections/CollectionMapView.tsx | 72 ++++++++++++++++++++++ src/client/views/collections/CollectionView.tsx | 10 ++- src/new_fields/Types.ts | 1 + webpack.config.js | 55 ++++++++++------- 11 files changed, 195 insertions(+), 45 deletions(-) create mode 100644 src/client/views/collections/CollectionMapView.scss create mode 100644 src/client/views/collections/CollectionMapView.tsx (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/package-lock.json b/package-lock.json index 1949a8a5c..f40dc7b0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -584,6 +584,20 @@ "@types/node": "*" } }, + "@types/google-maps-react": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/google-maps-react/-/google-maps-react-2.0.4.tgz", + "integrity": "sha512-8EGr84L6ozODnfjWN9xVUFIxFedBbZinuDe5lBEJ757yh/lZqoKkqxrYLqvrLksDRVVwQYwWdFvfEASujmk36A==", + "requires": { + "@types/googlemaps": "*", + "@types/react": "*" + } + }, + "@types/googlemaps": { + "version": "3.39.3", + "resolved": "https://registry.npmjs.org/@types/googlemaps/-/googlemaps-3.39.3.tgz", + "integrity": "sha512-L8O9HAVFZj0TuiS8h5ORthiMsrrhjxTC8XUusp5k47oXCst4VTm+qWKvrAvmYMybZVokbp4Udco1mNwJrTNZPQ==" + }, "@types/isstream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@types/isstream/-/isstream-0.1.0.tgz", @@ -750,7 +764,7 @@ }, "@types/passport": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.2.tgz", "integrity": "sha512-Pf39AYKf8q+YoONym3150cEwfUD66dtwHJWvbeOzKxnA0GZZ/vAXhNWv9vMhKyRQBQZiQyWQnhYBEBlKW6G8wg==", "requires": { "@types/express": "*" @@ -5615,7 +5629,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5633,11 +5648,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5650,15 +5667,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5761,7 +5781,8 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5771,6 +5792,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5783,17 +5805,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.9.0", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5810,6 +5835,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5890,7 +5916,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5900,6 +5927,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5975,7 +6003,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6005,6 +6034,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6022,6 +6052,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6060,11 +6091,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.1.1", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -6344,6 +6377,11 @@ } } }, + "google-maps-react": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/google-maps-react/-/google-maps-react-2.0.2.tgz", + "integrity": "sha512-6cYauGwt22haDUrWxKQ6yoNOqjiuxHo8YYcmb+aBvNICokdXmZOUB6Ah4vD5VexMVlrwP2PFqA/D8sHpEB52KA==" + }, "google-p12-pem": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.1.tgz", @@ -14376,7 +14414,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -15990,7 +16028,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -18303,7 +18341,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/package.json b/package.json index 440646c48..c742857ad 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "scripts": { "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", - "start": "cross-env HANDWRITING='61088486d76c4b12ba578775a5f55422' NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --inspect -- src/server/index.ts", "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", "test": "mocha -r ts-node/register test/**/*.ts", @@ -83,6 +83,7 @@ "@types/express-validator": "^3.0.0", "@types/formidable": "^1.0.31", "@types/gapi": "0.0.39", + "@types/google-maps-react": "^2.0.4", "@types/jquery": "^3.3.31", "@types/jquery-awesome-cursor": "^0.3.0", "@types/jsonwebtoken": "^8.3.7", @@ -162,6 +163,7 @@ "formidable": "^1.2.1", "golden-layout": "^1.5.9", "google-auth-library": "^4.2.4", + "google-maps-react": "^2.0.2", "googleapis": "^40.0.0", "googlephotos": "^0.2.5", "howler": "^2.1.3", @@ -258,4 +260,4 @@ "xoauth2": "^1.2.0", "youtube": "^0.1.0" } -} +} \ No newline at end of file diff --git a/src/client/Network.ts b/src/client/Network.ts index 6982ecf19..bd0e6e61a 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -4,10 +4,23 @@ import { Upload } from "../server/SharedMediaTypes"; export namespace Networking { + const EnvVarCache = new Map(); + export async function FetchFromServer(relativeRoute: string) { return (await fetch(relativeRoute)).text(); } + export async function FetchEnvironmentVariable(varNameLiteral: string) { + let resolved = EnvVarCache.get(varNameLiteral); + if (!resolved) { + resolved = await FetchFromServer(`/environment/${varNameLiteral}`); + if (resolved !== undefined) { + EnvVarCache.set(varNameLiteral, resolved); + } + } + return resolved; + } + export async function PostToServer(relativeRoute: string, body?: any) { const options = { uri: Utils.prepend(relativeRoute), diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 5d83de233..3133bf4b1 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -8,7 +8,6 @@ import { UndoManager } from "../util/UndoManager"; import requestPromise = require("request-promise"); import { List } from "../../new_fields/List"; import { ClientRecommender } from "../ClientRecommender"; -import { ImageBox } from "../views/nodes/ImageBox"; type APIManager = { converter: BodyConverter, requester: RequestExecutor }; type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 703c049cd..43e379125 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -49,6 +49,8 @@ import { ContextMenuProps } from "../views/ContextMenuItem"; import { ContextMenu } from "../views/ContextMenu"; import { LinkBox } from "../views/nodes/LinkBox"; import { ScreenshotBox } from "../views/nodes/ScreenshotBox"; +import CollectionMapView from "../views/collections/CollectionMapView"; +import LocationField, { LocationData } from "../../new_fields/LocationField"; const requestImageSize = require('../util/request-image-size'); const path = require('path'); @@ -277,8 +279,7 @@ export namespace Docs { }], [DocumentType.SCREENSHOT, { layout: { view: ScreenshotBox, dataField: data }, - options: {} - }] + }], ]); // All document prototypes are initialized with at least these values @@ -624,6 +625,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Linear }, id); } + export function MapDocument(documents: Array, options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), options); + } + export function CarouselDocument(documents: Array, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Carousel }); } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 6d705aa44..b21eb9c8f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -5,7 +5,6 @@ import * as ReactDOM from 'react-dom'; import * as React from 'react'; import { DocServer } from "../DocServer"; import { AssignAllExtensions } from "../../extensions/General/Extensions"; -process.env.HANDWRITING = "61088486d76c4b12ba578775a5f55422"; AssignAllExtensions(); diff --git a/src/client/views/collections/CollectionMapView.scss b/src/client/views/collections/CollectionMapView.scss new file mode 100644 index 000000000..c74433902 --- /dev/null +++ b/src/client/views/collections/CollectionMapView.scss @@ -0,0 +1,4 @@ +.collectionMapView-contents { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx new file mode 100644 index 000000000..49411f61b --- /dev/null +++ b/src/client/views/collections/CollectionMapView.tsx @@ -0,0 +1,72 @@ +import { observer } from "mobx-react"; +import { makeInterface } from "../../../new_fields/Schema"; +import { documentSchema } from "../../../new_fields/documentSchemas"; +import React = require("react"); +import { Map, Marker, MapProps, GoogleApiWrapper } from "google-maps-react"; +import { NumCast, StrCast } from "../../../new_fields/Types"; +import { CollectionSubView } from "./CollectionSubView"; +import { Utils } from "../../../Utils"; + +type MapDocument = makeInterface<[typeof documentSchema]>; +const MapDocument = makeInterface(documentSchema); + +export type LocationData = google.maps.LatLngLiteral & { address?: string }; + +@observer +class CollectionMapView extends CollectionSubView & { google: any }>(MapDocument) { + + render() { + const { childLayoutPairs, props } = this; + const { Document } = props; + const center: LocationData = { lat: NumCast(Document.mapCenterLat), lng: NumCast(Document.mapCenterLng) }; + if (!center.lat) { + center.lat = childLayoutPairs.length ? NumCast(childLayoutPairs[0].layout.locationLat, 0) : 0; + center.lng = childLayoutPairs.length ? NumCast(childLayoutPairs[0].layout.locationLng, 0) : 0; + } + return ( +
+ + {childLayoutPairs.map(({ layout }) => { + const location: LocationData = { + lat: NumCast(childLayoutPairs[0].layout.locationLat, 0), + lng: NumCast(childLayoutPairs[0].layout.locationLng, 0) + }; + const iconSize = new google.maps.Size(NumCast(layout.mapIconWidth, 45), NumCast(layout.mapIconHeight, 45)); + return ( + { + Document.mapCenterLat = location.lat; + Document.mapCenterLng = location.lng; + }} + icon={{ + size: iconSize, + scaledSize: iconSize, + url: StrCast(Document.mapIconUrl, "https://www.pinclipart.com/picdir/middle/359-3598915_map-marker-icon-location-icon-png-clipart.png") + }} + /> + ); + })} + +
+ ); + } + +} + +declare var process: { + env: { + GOOGLE_MAPS_API_KEY: string; + } +}; + +export default GoogleApiWrapper({ apiKey: process.env.GOOGLE_MAPS_API_KEY })(CollectionMapView) as any; \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 821840e0b..d1dc32829 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,7 +1,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEye, faEdit } from '@fortawesome/free-regular-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree, faGlobeAmericas } from '@fortawesome/free-solid-svg-icons'; import { action, observable, computed } from 'mobx'; import { observer } from "mobx-react"; import * as React from 'react'; @@ -44,12 +44,15 @@ import { Docs } from '../../documents/Documents'; import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; +import CollectionMapView from './CollectionMapView'; +import { ClientUtils } from '../../util/ClientUtils'; +import { GoogleApiWrapper } from 'google-maps-react'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; 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); +library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faGlobeAmericas, faEllipsisV, faImage, faEye as any, faCopy); export enum CollectionViewType { Invalid = "invalid", @@ -65,6 +68,7 @@ export enum CollectionViewType { Carousel = "carousel", Linear = "linear", Staff = "staff", + Map = "map" } export interface CollectionRenderProps { @@ -170,6 +174,7 @@ export class CollectionView extends Touchable { case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Time: { return (); } + case CollectionViewType.Map: return (); case CollectionViewType.Freeform: default: { this.props.Document._freeformLayoutEngine = undefined; return (); } } @@ -211,6 +216,7 @@ export class CollectionView extends Touchable { 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/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); + subItems.push({ description: "Map", event: () => this.props.Document._viewType = CollectionViewType.Map, icon: "globe-americas" }); 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/new_fields/Types.ts b/src/new_fields/Types.ts index 0ca35fab2..aa44cefa0 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -87,6 +87,7 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) export function DateCast(field: FieldResult) { return Cast(field, DateField, null); } + export function ScriptCast(field: FieldResult) { return Cast(field, ScriptField, null); } diff --git a/webpack.config.js b/webpack.config.js index 6a14dfcda..655334ef2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,6 +2,14 @@ var path = require('path'); var webpack = require('webpack'); const CopyWebpackPlugin = require("copy-webpack-plugin"); const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); +const env = require('dotenv').config().parsed; +const envKeys = Object.keys(env).reduce((prev, next) => { + if (next.startsWith("DASH_")) { + const resolved = next.replace("DASH_", ""); + prev[`process.env.${resolved}`] = JSON.stringify(env[next]); + } + return prev; +}, {}); module.exports = { mode: 'development', @@ -33,17 +41,18 @@ module.exports = { extensions: ['.js', '.ts', '.tsx'] }, module: { - rules: [ - { + rules: [{ test: [/\.tsx?$/], - use: [ - { loader: 'ts-loader', options: { transpileOnly: true } } - ] + use: [{ + loader: 'ts-loader', + options: { + transpileOnly: true + } + }] }, { test: /\.scss|css$/, - use: [ - { + use: [{ loader: "style-loader" }, { @@ -56,28 +65,30 @@ module.exports = { }, { test: /\.(jpg|png|pdf)$/, - use: [ - { - loader: 'file-loader' - } - ] + use: [{ + loader: 'file-loader' + }] }, { test: /\.(png|jpg|gif)$/i, - use: [ - { - loader: 'url-loader', - options: { - limit: 8192 - } + use: [{ + loader: 'url-loader', + options: { + limit: 8192 } - ] - }] + }] + } + ] }, plugins: [ - new CopyWebpackPlugin([{ from: "deploy", to: path.join(__dirname, "build") }]), + new CopyWebpackPlugin([{ + from: "deploy", + to: path.join(__dirname, "build") + }]), + new webpack.DefinePlugin(envKeys), new ForkTsCheckerWebpackPlugin({ - tslint: true, useTypescriptIncrementalApi: true + tslint: true, + useTypescriptIncrementalApi: true }), new webpack.optimize.OccurrenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), -- cgit v1.2.3-70-g09d2 From b235c94614141752c98d24a395682a02297d9e6a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 13 Apr 2020 11:15:59 -0400 Subject: cleaned up rootSelected() to work with templates. adjusted nudge to favor moving documents over panning collection --- src/client/views/DocComponent.tsx | 4 ++-- src/client/views/PreviewCursor.tsx | 14 +++++--------- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 17 +++++++++++------ .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 16 +++++++++------- 8 files changed, 32 insertions(+), 29 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b1bd4191c..f19f9308a 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -53,7 +53,7 @@ export function ViewBoxBaseComponent

(schemaCtor: // key where data is stored @computed get fieldKey() { return this.props.fieldKey; } - active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools + active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; } return Component; @@ -114,7 +114,7 @@ export function ViewBoxAnnotatableComponent

this.props.whenActiveChanged(this._isChildActive = isActive)); active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) && - ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) + (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None || (this.props.Document.isBackground && this.props.active()) || (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) } diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index ecebadd2a..92ba13d2f 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -13,7 +13,7 @@ export class PreviewCursor extends React.Component<{}> { static _getTransform: () => Transform; static _addLiveTextDoc: (doc: Doc) => void; static _addDocument: (doc: Doc) => boolean; - static _nudge: (x: number, y: number) => void; + static _nudge: (x: number, y: number) => boolean; @observable static _clickPoint = [0, 0]; @observable public static Visible = false; constructor(props: any) { @@ -91,17 +91,13 @@ export class PreviewCursor extends React.Component<{}> { } } else if (PreviewCursor.Visible) { if (e.key === "ArrowRight") { - PreviewCursor._nudge?.(1 * (e.shiftKey ? 2 : 1), 0); - e.stopPropagation(); + PreviewCursor._nudge?.(1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation(); } else if (e.key === "ArrowLeft") { - PreviewCursor._nudge?.(-1 * (e.shiftKey ? 2 : 1), 0); - e.stopPropagation(); + PreviewCursor._nudge?.(-1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation(); } else if (e.key === "ArrowUp") { - PreviewCursor._nudge?.(0, 1 * (e.shiftKey ? 2 : 1)); - e.stopPropagation(); + PreviewCursor._nudge?.(0, 1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation(); } else if (e.key === "ArrowDown") { - PreviewCursor._nudge?.(0, -1 * (e.shiftKey ? 2 : 1)); - e.stopPropagation(); + PreviewCursor._nudge?.(0, -1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation(); } } } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 6b7c3de56..37cf942c6 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -100,7 +100,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } rootSelected = (outsideReaction?: boolean) => { - return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected(outsideReaction) : false); + return this.props.isSelected(outsideReaction) || (this.rootDoc && this.props.rootSelected(outsideReaction)); } // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc. diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 821840e0b..86df9c080 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -102,7 +102,7 @@ export class CollectionView extends Touchable { return viewField as any as CollectionViewType; } - active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected(outsideReaction) && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0; + active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.props.Document.forceActive || this._isChildActive || this.props.renderDepth === 0; whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7dca19073..a77f09163 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -15,7 +15,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types"; import { TraceMobx } from "../../../../new_fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnOne, Utils, returnZero } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; @@ -43,6 +43,7 @@ import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); +import { CollectionViewType } from "../CollectionView"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -860,7 +861,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u LibraryPath: this.libraryPath, FreezeDimensions: this.props.freezeChildDimensions, layoutKey: undefined, - rootSelected: this.rootSelected, + rootSelected: childData ? this.rootSelected : returnFalse, dropAction: StrCast(this.props.Document.childDropAction) as dropActionType, //onClick: undefined, // this.props.onClick, // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them onClick: this.onChildClickHandler, @@ -1105,10 +1106,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u _nudgeTime = 0; nudge = action((x: number, y: number) => { - this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(), - NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "Ease", true); - this._nudgeTime = Date.now(); - setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document.panTransformType = undefined), 500); + if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform) { // bcz: this isn't ideal, but want to try it out... + this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(), + NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "Ease", true); + this._nudgeTime = Date.now(); + setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document.panTransformType = undefined), 500); + return true; + } + return false; }); @computed get marqueeView() { return void; isSelected: () => boolean; isAnnotationOverlay?: boolean; - nudge:(x:number, y:number) => void; + nudge: (x: number, y: number) => boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3503af442..e7cb2c015 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -60,8 +60,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { - this.layoutDoc.x = NumCast(this.layoutDoc.x) + x; - this.layoutDoc.y = NumCast(this.layoutDoc.y) + y; + this.props.Document.x = NumCast(this.props.Document.x) + x; + this.props.Document.y = NumCast(this.props.Document.y) + y; } contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3784c5c9c..cc3c39154 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -289,13 +289,15 @@ export class DocumentView extends DocComponent(Docu let preventDefault = true; this.props.Document.isBackground === undefined && this.props.bringToFront(this.props.Document); if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click - const fullScreenAlias = Doc.MakeAlias(this.props.Document); - if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { - fullScreenAlias.layoutKey = "layout_fullScreen"; + if (!(e.nativeEvent as any).formattedHandled) { + const fullScreenAlias = Doc.MakeAlias(this.props.Document); + if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { + fullScreenAlias.layoutKey = "layout_fullScreen"; + } + UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap"); + SelectionManager.DeselectAll(); + Doc.UnBrushDoc(this.props.Document); } - UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap"); - SelectionManager.DeselectAll(); - Doc.UnBrushDoc(this.props.Document); } else if (this.onClickHandler?.script) { SelectionManager.DeselectAll(); const func = () => this.onClickHandler.script.run({ @@ -978,7 +980,7 @@ export class DocumentView extends DocComponent(Docu return typeof fallback === "string" ? fallback : "layout"; } rootSelected = (outsideReaction?: boolean) => { - return this.isSelected(outsideReaction) || (this.props.Document.forceActive && this.props.rootSelected?.(outsideReaction) ? true : false); + return this.isSelected(outsideReaction) || (this.rootDoc && this.props.rootSelected?.(outsideReaction)); } childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); panelWidth = () => this.props.PanelWidth(); -- cgit v1.2.3-70-g09d2 From 87268612b9b765d74f1a5317b0894be0ceb1dfd1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 13 Apr 2020 16:43:50 -0400 Subject: fixed map view pointer events. --- src/client/views/collections/CollectionMapView.scss | 3 +++ src/client/views/collections/CollectionMapView.tsx | 8 ++++---- src/client/views/collections/CollectionView.tsx | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionMapView.scss b/src/client/views/collections/CollectionMapView.scss index c74433902..df7853da6 100644 --- a/src/client/views/collections/CollectionMapView.scss +++ b/src/client/views/collections/CollectionMapView.scss @@ -1,4 +1,7 @@ .collectionMapView-contents { width: 100%; height: 100%; +} +.collectionMapView-contents-none { + pointer-events: none; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index b67daeb53..5075bbf7a 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -7,6 +7,7 @@ import { NumCast, StrCast } from "../../../new_fields/Types"; import { CollectionSubView } from "./CollectionSubView"; import { Utils } from "../../../Utils"; import { Opt } from "../../../new_fields/Doc"; +import "./CollectionMapView.scss"; type MapDocument = makeInterface<[typeof documentSchema]>; const MapDocument = makeInterface(documentSchema); @@ -25,11 +26,10 @@ class CollectionMapView extends CollectionSubView center.lng = childLayoutPairs.length ? NumCast(childLayoutPairs[0].layout.locationLng, 0) : 0; } return ( -

+
(this.props.active() && e.button === 0 && !e.ctrlKey) && e.stopPropagation()} > { return viewField as any as CollectionViewType; } - active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.props.Document.forceActive || this._isChildActive || this.props.renderDepth === 0; + active = (outsideReaction?: boolean) => (this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.props.Document.forceActive || this._isChildActive || this.props.renderDepth === 0) ? true : false; whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive); -- cgit v1.2.3-70-g09d2 From 130e26103461f23a2d8b57ea2eef6b17eefb8f8e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 13 Apr 2020 21:46:20 -0400 Subject: updated childDetailedView stuff for pivot view --- src/client/views/TemplateMenu.tsx | 4 ++-- src/client/views/collections/CollectionTimeView.tsx | 10 ++++++---- src/client/views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 4 ++-- src/client/views/collections/CollectionViewChromes.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 8 ++++---- src/new_fields/Doc.ts | 8 -------- src/new_fields/documentSchemas.ts | 2 +- 8 files changed, 18 insertions(+), 24 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 4d7f1e443..b76137f06 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -167,8 +167,8 @@ export class TemplateMenu extends React.Component { } } -Scripting.addGlobal(function switchView(doc: Doc, template: Doc) { - if (template.dragFactory) { +Scripting.addGlobal(function switchView(doc: Doc, template: Doc | undefined) { + if (template?.dragFactory) { template = Cast(template.dragFactory, Doc, null); } const templateTitle = StrCast(template?.title); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 53de2fbbe..31b720b81 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -5,7 +5,7 @@ import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { RichTextField } from "../../../new_fields/RichTextField"; import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; -import { NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; +import { NumCast, StrCast, BoolCast, Cast } from "../../../new_fields/Types"; import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils"; import { Scripting } from "../../util/Scripting"; import { ContextMenu } from "../ContextMenu"; @@ -19,6 +19,7 @@ const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; import React = require("react"); +import { DocumentView } from "../nodes/DocumentView"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -28,14 +29,15 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { componentWillUnmount() { this.props.Document.onChildClick = undefined; } - componentDidMount() { - 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; - const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(thisContainer.childDetailed, alias, 'layout_detailView'); alias.layoutKey='layout_detailedView'; alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + async componentDidMount() { + const childText = "const alias = getAlias(this); switchView(alias, thisContainer.childDetailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", thisContainer: Doc.name, shiftKey: "boolean" }); this.props.Document._fitToBox = true; if (!this.props.Document.onViewDefClick) { this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); } + this.props.Document.childDetailView = Cast(this.props.Document.childDetailView, Doc, null) ||// bcz: needs to be here to make sure the childDetailView layout template has been loaded when the first item is clicked; + DocumentView.findTemplate("detailView", StrCast(this.props.Document.type), ""); } layoutEngine = () => this._layoutEngine; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 23fb259fc..b96ee4bc4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -754,7 +754,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as })); Document.childLayout = heroView; - Document.childDetailed = detailView; + Document.childDetailView = detailView; Document._viewType = CollectionViewType.Time; Document._forceActive = true; Document._pivotField = "company"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8cc5146d5..f94277862 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -232,8 +232,8 @@ export class CollectionView extends Touchable { if (this.props.Document.childLayout instanceof Doc) { layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" }); } - if (this.props.Document.childDetailed instanceof Doc) { - layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" }); + if (this.props.Document.childDetailView instanceof Doc) { + layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailView as Doc, "onRight"), icon: "project-diagram" }); } layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index ba95dce00..e494c337a 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -48,8 +48,8 @@ export class CollectionViewBaseChrome extends React.Component click item view", - script: "this.target.childDetailed = getDocTemplate(this.source?.[0])", - immediate: (source: Doc[]) => this.target.childDetailed = Doc.getDocTemplate(source?.[0]), + script: "this.target.childDetailView = getDocTemplate(this.source?.[0])", + immediate: (source: Doc[]) => this.target.childDetailView = Doc.getDocTemplate(source?.[0]), initialize: emptyFunction, }; _contentCommand = { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cc3c39154..5b6478e66 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -541,7 +541,7 @@ export class DocumentView extends DocComponent(Docu deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument?.(this.props.Document); } // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView) - static makeCustomViewClicked = (doc: Doc, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { + static makeCustomViewClicked = (doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { const batch = UndoManager.StartBatch("makeCustomViewClicked"); runInAction(() => { doc.layoutKey = "layout_" + templateSignature; @@ -563,7 +563,7 @@ export class DocumentView extends DocComponent(Docu !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); return docLayoutTemplate; } - static createCustomView = (doc: Doc, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { + static createCustomView = (doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { const templateName = templateSignature.replace(/\(.*\)/, ""); docLayoutTemplate = docLayoutTemplate || DocumentView.findTemplate(templateName, StrCast(doc.type), templateSignature); @@ -584,10 +584,10 @@ export class DocumentView extends DocComponent(Docu } else if (doc.data instanceof ImageField) { fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); } - const docTemplate = docLayoutTemplate || creator(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); + const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate)); - Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); + docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); } @undoBatch diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 92abb7a71..bcf0d1aec 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -603,14 +603,6 @@ export namespace Doc { return undefined; } export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) { - if (!templateDoc) { - target.layout = undefined; - target._nativeWidth = undefined; - target._nativeHeight = undefined; - target.type = undefined; - return; - } - if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) { if (target.resolvedDataDoc) { target[targetKey] = new PrefetchProxy(templateDoc); diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index b11941f40..bc63e9df8 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -74,7 +74,7 @@ export const positionSchema = createSchema({ export const collectionSchema = createSchema({ childLayout: Doc, // layout template for children of a collecion - childDetailed: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field) + childDetailView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field) onChildClick: ScriptField, // script to run for each child when its clicked onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view }); -- cgit v1.2.3-70-g09d2 From a9613d73947ee9b000c695b8f3d7685feed96a27 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 14 Apr 2020 17:37:20 -0400 Subject: fixed goldenlayout borders. made filter flyout semistransparent. fixed map to stay inbounds when filter is expanded. --- src/client/goldenLayout.js | 4 +++- src/client/views/collections/CollectionMapView.scss | 3 +++ src/client/views/collections/CollectionView.scss | 1 - src/client/views/collections/CollectionView.tsx | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index b510385ff..2d4283b02 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -1551,7 +1551,7 @@ }, dimensions: { borderWidth: 5, - borderGrabWidth: 15, + borderGrabWidth: 5, minItemHeight: 10, minItemWidth: 10, headerHeight: 20, @@ -2796,11 +2796,13 @@ if (this._isVertical) { dragHandle.css('top', -handleExcessPos); dragHandle.css('height', this._size + handleExcessSize); + element.css('cursor', 'row-resize'); element.addClass('lm_vertical'); element['height'](this._size); } else { dragHandle.css('left', -handleExcessPos); dragHandle.css('width', this._size + handleExcessSize); + element.css('cursor', 'col-resize'); element.addClass('lm_horizontal'); element['width'](this._size); } diff --git a/src/client/views/collections/CollectionMapView.scss b/src/client/views/collections/CollectionMapView.scss index cb58b1750..7e4f9a0f4 100644 --- a/src/client/views/collections/CollectionMapView.scss +++ b/src/client/views/collections/CollectionMapView.scss @@ -4,6 +4,9 @@ .collectionMapView-contents { width: 100%; height: 100%; + > div { + position: unset !important; // when the sidebar filter flys out, this prevents the map from extending outside the document box + } } } diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss index b92c5fdd1..a0b73b90f 100644 --- a/src/client/views/collections/CollectionView.scss +++ b/src/client/views/collections/CollectionView.scss @@ -11,7 +11,6 @@ height: 100%; overflow: hidden; // bcz: used to be 'auto' which would create scrollbars when there's a floating doc that's not visible. not sure if that's better, but the scrollbars are annoying... - .collectionTimeView-dragger { background-color: lightgray; height: 40px; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index f94277862..13a657800 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -389,7 +389,7 @@ export class CollectionView extends Touchable { return false; }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0)); } - filterBackground = () => "dimGray"; + filterBackground = () => "rgba(105, 105, 105, 0.432)"; get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves) @computed get scriptField() { const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)"; -- cgit v1.2.3-70-g09d2 From b9483279f4a778e0cc997e304b4f0b87e6ec1e5d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 00:29:00 -0400 Subject: changed collection chrome filter to just open filter sidebar. fixed scrollbar to make sure that all datapoints are included. simplified filter documents to have only a datadocument. --- src/client/documents/Documents.ts | 1 - .../views/collections/CollectionTreeView.tsx | 11 +- src/client/views/collections/CollectionView.tsx | 20 +- .../views/collections/CollectionViewChromes.scss | 3 +- .../views/collections/CollectionViewChromes.tsx | 316 ++++++--------------- 5 files changed, 100 insertions(+), 251 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e6f3b21ca..129ab0403 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -142,7 +142,6 @@ export interface DocumentOptions { treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. treeViewOpen?: boolean; // whether this document is expanded in a tree view treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked - 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; pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index b96ee4bc4..9ec8c4c5b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -840,12 +840,11 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey } }); const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => - Docs.Create.TextDocument("", { - title: facetValue.toString(), - treeViewChecked: ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", - {}, - { layoutDoc, facetHeader, facetValue }) - })); + { const doc = new Doc(); + doc.title = facetValue.toString(); + doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)",{},{ layoutDoc, facetHeader, facetValue }); + return doc; + }); return new List(facetValueDocSet); }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 13a657800..831691f8c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -45,8 +45,6 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; import CollectionMapView from './CollectionMapView'; -import { ClientUtils } from '../../util/ClientUtils'; -import { GoogleApiWrapper } from 'google-maps-react'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -279,7 +277,8 @@ export class CollectionView extends Touchable { onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)} onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />); } - @observable _facetWidth = 0; + get _facetWidth() { return NumCast(this.props.Document._facetWidth) } + set _facetWidth(value) { this.props.Document._facetWidth = value; } bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth(); getTransform = () => this.props.ScreenToLocalTransform().translate(-this.facetWidth(), 0); @@ -365,17 +364,22 @@ export class CollectionView extends Touchable { Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox newFacet.treeViewExpandedView = "layout"; newFacet.treeViewOpen = true; - newFacet[newFacetField + "-min"] = ranged === undefined ? minVal : ranged[0]; - newFacet[newFacetField + "-max"] = ranged === undefined ? maxVal : ranged[1]; - Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = minVal; - Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = maxVal; + const extendedMinVal = minVal - Math.min(1, Math.abs(maxVal - minVal) * .05); + const extendedMaxVal = maxVal + Math.min(1, Math.abs(maxVal - minVal) * .05); + newFacet[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0]; + newFacet[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1]; + Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = extendedMinVal; + Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal; newFacet.target = this.props.Document; const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`; newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" }); Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); } else { - newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true }); + newFacet = new Doc(); + newFacet.title = facetHeader; + newFacet.treeViewOpen = true; + newFacet.type = DocumentType.COL; const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc }; newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables); } diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index a691b4805..9529ef525 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -67,10 +67,11 @@ color:grey; margin-top:auto; margin-bottom:auto; + margin-left: 5px; } .collectionViewBaseChrome-viewSpecs { - margin-left: 10px; + margin-left: 25px; display: grid; .collectionViewBaseChrome-filterIcon { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 66f627083..cef85e148 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -6,7 +6,6 @@ import { Doc, DocListCast } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { Utils, emptyFunction, setupMoveUpEvents } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; @@ -16,8 +15,6 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss"; import { CollectionViewType } from "./CollectionView"; import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; -import * as Autosuggest from 'react-autosuggest'; -import KeyRestrictionRow from "./KeyRestrictionRow"; const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { @@ -84,62 +81,10 @@ export class CollectionViewBaseChrome extends React.Component(); private _viewRef = React.createRef(); - private _autosuggestRef = React.createRef(); @observable private _currentKey: string = ""; - @observable private _viewSpecsOpen: boolean = false; - @observable private _dateWithinValue: string = ""; - @observable private _dateValue: Date | string = ""; - @observable private _keyRestrictions: [JSX.Element, string][] = []; - @observable private suggestions: string[] = []; - @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); } - - getFilters = (script: string) => { - const re: any = /(!)?\(\(\(doc\.(\w+)\s+&&\s+\(doc\.\w+\s+as\s+\w+\)\.includes\(\"(\w+)\"\)/g; - const arr: any[] = re.exec(script); - const toReturn: Filter[] = []; - if (arr !== null) { - const filter: Filter = { - key: arr[2], - value: arr[3], - contains: (arr[1] === "!") ? false : true, - }; - toReturn.push(filter); - script = script.replace(arr[0], ""); - if (re.exec(script) !== null) { - toReturn.push(...this.getFilters(script)); - } - else { return toReturn; } - } - return toReturn; - } - - addKeyRestrictions = (fields: Filter[]) => { - - if (fields.length !== 0) { - for (let i = 0; i < fields.length; i++) { - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[i][1] = value)} />, ""]); - - } - if (this._keyRestrictions.length === 1) { - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); - } - } - else { - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]); - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); - } - } componentDidMount = () => { - - let fields: Filter[] = []; - if (this.filterValue) { - const string = this.filterValue.script.originalScript; - fields = this.getFilters(string); - } - runInAction(() => { - this.addKeyRestrictions(fields); // chrome status is one of disabled, collapsed, or visible. this determines initial state from document const chromeStatus = this.props.CollectionView.props.Document._chromeStatus; if (chromeStatus) { @@ -158,7 +103,7 @@ export class CollectionViewBaseChrome extends React.Component { //@ts-ignore - this.props.CollectionView.props.Document._viewType = e.target.selectedOptions[0].value; + this.document._viewType = e.target.selectedOptions[0].value; } commandChanged = (e: React.ChangeEvent) => { @@ -167,104 +112,93 @@ export class CollectionViewBaseChrome extends React.Component { - if (this._viewSpecsOpen) this.closeViewSpecs(); - else { - this._viewSpecsOpen = true; - - //@ts-ignore - if (!e.target?.classList[0]?.startsWith("qs")) { - this.closeDatePicker(); - } - - e.stopPropagation(); - document.removeEventListener("pointerdown", this.closeViewSpecs); - document.addEventListener("pointerdown", this.closeViewSpecs); - } + toggleViewSpecs = (e: React.SyntheticEvent) => { + this.document._facetWidth = this.document._facetWidth ? 0 : 200; + e.stopPropagation(); } @action closeViewSpecs = () => { - this._viewSpecsOpen = false; - document.removeEventListener("pointerdown", this.closeViewSpecs); - } - - @action - openDatePicker = (e: React.PointerEvent) => { - this.openViewSpecs(e); - if (this._picker) { - this._picker.alwaysShow = true; - this._picker.show(); - // TODO: calendar is offset when zoomed in/out - // this._picker.calendar.style.position = "absolute"; - // let transform = this.props.CollectionView.props.ScreenToLocalTransform(); - // let x = parseInt(this._picker.calendar.style.left) / transform.Scale; - // let y = parseInt(this._picker.calendar.style.top) / transform.Scale; - // this._picker.calendar.style.left = x; - // this._picker.calendar.style.top = y; - - e.stopPropagation(); - } - } - - @action - addKeyRestriction = (e: React.MouseEvent) => { - const index = this._keyRestrictions.length; - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[index][1] = value)} />, ""]); - - this.openViewSpecs(e); - } - - @action.bound - applyFilter = (e: React.MouseEvent) => { - - this.openViewSpecs(e); - - const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")"; - const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0; - const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0; - const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0; - const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7; - let dateRestrictionScript = ""; - if (this._dateValue instanceof Date) { - const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset); - const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1); - dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; - } - else { - const createdDate = new Date(this._dateValue); - if (!isNaN(createdDate.getTime())) { - const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset); - const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1); - dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; - } - } - const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ? - `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` : - `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` : - "true"; + this.document._facetWidth = 0; + } + + // @action + // openDatePicker = (e: React.PointerEvent) => { + // if (this._picker) { + // this._picker.alwaysShow = true; + // this._picker.show(); + // // TODO: calendar is offset when zoomed in/out + // // this._picker.calendar.style.position = "absolute"; + // // let transform = this.props.CollectionView.props.ScreenToLocalTransform(); + // // let x = parseInt(this._picker.calendar.style.left) / transform.Scale; + // // let y = parseInt(this._picker.calendar.style.top) / transform.Scale; + // // this._picker.calendar.style.left = x; + // // this._picker.calendar.style.top = y; + + // e.stopPropagation(); + // } + // } + + // runInAction(() => this._dateValue = e.target.value)} + // onPointerDown={this.openDatePicker} + // placeholder="Value" /> + // @action.bound + // applyFilter = (e: React.MouseEvent) => { + // const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")"; + // const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0; + // const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0; + // const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0; + // const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7; + // let dateRestrictionScript = ""; + // if (this._dateValue instanceof Date) { + // const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset); + // const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1); + // dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; + // } + // else { + // const createdDate = new Date(this._dateValue); + // if (!isNaN(createdDate.getTime())) { + // const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset); + // const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1); + // dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; + // } + // } + // const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ? + // `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` : + // `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` : + // "true"; + + // this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name }); + // } + + // datePickerRef = (node: HTMLInputElement) => { + // if (node) { + // try { + // this._picker = datepicker("#" + node.id, { + // disabler: (date: Date) => date > new Date(), + // onSelect: (instance: any, date: Date) => runInAction(() => {}), // this._dateValue = date), + // dateSelected: new Date() + // }); + // } catch (e) { + // console.log("date picker exception:" + e); + // } + // } + // } - this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name }); - } - - @action - closeDatePicker = () => { - if (this._picker) { - this._picker.alwaysShow = false; - this._picker.hide(); - } - document.removeEventListener("pointerdown", this.closeDatePicker); - } @action toggleCollapse = () => { - this.props.CollectionView.props.Document._chromeStatus = this.props.CollectionView.props.Document._chromeStatus === "enabled" ? "collapsed" : "enabled"; + this.document._chromeStatus = this.document._chromeStatus === "enabled" ? "collapsed" : "enabled"; if (this.props.collapse) { this.props.collapse(this.props.CollectionView.props.Document._chromeStatus !== "enabled"); } } subChrome = () => { - const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled"; + const collapsed = this.document._chromeStatus !== "enabled"; if (collapsed) return null; switch (this.props.type) { case CollectionViewType.Stacking: return (); @@ -279,13 +213,6 @@ export class CollectionViewBaseChrome extends React.Component { - this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name }); - this._keyRestrictions = []; - this.addKeyRestrictions([]); - } - private dropDisposer?: DragManager.DragDropDisposer; protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer && this.dropDisposer(); @@ -304,48 +231,6 @@ export class CollectionViewBaseChrome extends React.Component { - if (node) { - try { - this._picker = datepicker("#" + node.id, { - disabler: (date: Date) => date > new Date(), - onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date), - dateSelected: new Date() - }); - } catch (e) { - console.log("date picker exception:" + e); - } - } - } - - renderSuggestion = (suggestion: string) => { - return

{suggestion}

; - } - getSuggestionValue = (suggestion: string) => suggestion; - - @action - onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { - this._currentKey = newValue; - } - onSuggestionFetch = async ({ value }: { value: string }) => { - const sugg = await this.getKeySuggestions(value); - runInAction(() => this.suggestions = sugg); - } - @action - onSuggestionClear = () => { - this.suggestions = []; - } - getKeySuggestions = async (value: string): Promise => { - return this._buttonizableCommands.filter(c => c.title.indexOf(value) !== -1).map(c => c.title); - } - - autoSuggestDown = (e: React.PointerEvent) => { - e.stopPropagation(); - } - - private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 }; - private _sensitivity: number = 16; - dragViewDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e, down, delta) => { const vtype = this.props.CollectionView.collectionViewType; @@ -367,7 +252,6 @@ export class CollectionViewBaseChrome extends React.Component -
+
+
+ +
+
+
@@ -414,49 +303,6 @@ export class CollectionViewBaseChrome extends React.Component
-
-
- -
-
- {this._keyRestrictions.map(i => i[0])} -
-
- CREATED WITHIN: -
- - runInAction(() => this._dateValue = e.target.value)} - onPointerDown={this.openDatePicker} - placeholder="Value" /> -
-
- - - -
-
-
-- cgit v1.2.3-70-g09d2 From d5c0ed9a29593583a4180973f854106dc10d4b30 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 02:32:47 -0400 Subject: moved filter to right side of collection. got rid of back button in pivot view - click background. --- src/Utils.ts | 10 +++-- .../views/collections/CollectionTimeView.tsx | 30 +++++++-------- src/client/views/collections/CollectionView.scss | 4 +- src/client/views/collections/CollectionView.tsx | 43 +++++++++++++++------- .../views/collections/CollectionViewChromes.scss | 8 +++- .../views/collections/CollectionViewChromes.tsx | 12 +++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- 8 files changed, 69 insertions(+), 43 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index a8cde0624..58f272ba5 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -475,7 +475,9 @@ export function setupMoveUpEvents( e: React.PointerEvent, moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean, upEvent: (e: PointerEvent) => void, - clickEvent: (e: PointerEvent) => void) { + clickEvent: (e: PointerEvent) => void, + stopPropagation: boolean = true +) { (target as any)._downX = (target as any)._lastX = e.clientX; (target as any)._downY = (target as any)._lastY = e.clientY; @@ -499,8 +501,10 @@ export function setupMoveUpEvents( document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); }; - e.stopPropagation(); - e.preventDefault(); + if (stopPropagation) { + e.stopPropagation(); + e.preventDefault(); + } document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); document.addEventListener("pointermove", _moveEvent); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 31b720b81..1760e2419 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -72,8 +72,22 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { }), returnFalse, emptyFunction); } + contentsDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, returnFalse, returnFalse, action(() => { + let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex); + if (prevFilterIndex > 0) { + prevFilterIndex--; + this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField); + this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField); + this.props.Document._prevFilterIndex = prevFilterIndex; + } else { + this.props.Document._docFilters = new List([]); + } + }), false); + } + @computed get contents() { - return
+ return
; } @@ -132,20 +146,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; }; return
-
; } diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss index a0b73b90f..d43dd387a 100644 --- a/src/client/views/collections/CollectionView.scss +++ b/src/client/views/collections/CollectionView.scss @@ -20,7 +20,7 @@ top: 55%; border: 1px black solid; z-index: 2; - left: -10px; + right: -10px; } .collectionTimeView-treeView { display: flex; @@ -28,7 +28,7 @@ width: 200px; height: 100%; position: absolute; - left: 0; + right: 0; top: 0; .collectionTimeView-addfacet { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 831691f8c..0a3577bc7 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,7 +13,7 @@ import { List } from '../../../new_fields/List'; import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types'; import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; -import { Utils, setupMoveUpEvents, returnFalse, returnZero } from '../../../Utils'; +import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; @@ -45,6 +45,7 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; import CollectionMapView from './CollectionMapView'; +import { Transform } from 'prosemirror-transform'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -281,7 +282,6 @@ export class CollectionView extends Touchable { set _facetWidth(value) { this.props.Document._facetWidth = value; } bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth(); - getTransform = () => this.props.ScreenToLocalTransform().translate(-this.facetWidth(), 0); facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth)); @computed get dataDoc() { @@ -389,7 +389,7 @@ export class CollectionView extends Touchable { onPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); + this._facetWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); return false; }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0)); } @@ -415,27 +415,44 @@ export class CollectionView extends Touchable {
e.stopPropagation()}>
- Facet Filters + Facet Filters
- @@ -461,7 +478,7 @@ export class CollectionView extends Touchable { }} onContextMenu={this.onContextMenu}> {this.showIsTagged()} -
+
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
{this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d => @@ -471,9 +488,7 @@ export class CollectionView extends Touchable { : ""))} {!this.props.isSelected() || this.props.PanelHeight() < 100 || this.props.Document.hideFilterView ? (null) : -
- -
+
} {this.filterView}
); diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 9529ef525..5203eb55f 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -61,7 +61,8 @@ pointer-events: all; // margin-top: 10px; } - .collectionViewBaseChrome-template { + .collectionViewBaseChrome-template, + .collectionViewBaseChrome-viewModes { display: grid; background: rgb(238, 238, 238); color:grey; @@ -69,9 +70,12 @@ margin-bottom:auto; margin-left: 5px; } + .collectionViewBaseChrome-viewModes { + margin-left: 25px; + } .collectionViewBaseChrome-viewSpecs { - margin-left: 25px; + margin-left: 5px; display: grid; .collectionViewBaseChrome-filterIcon { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index cef85e148..7315d2c4e 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -276,12 +276,7 @@ export class CollectionViewBaseChrome extends React.Component -
-
- -
-
-
+
@@ -303,6 +298,11 @@ export class CollectionViewBaseChrome extends React.Component
+
+
+ +
+
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a77f09163..d98fe190c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -907,6 +907,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u onViewDefDivClick = (e: React.MouseEvent, payload: any) => { (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload }); + e.stopPropagation(); } private viewDefToJSX(viewDef: ViewDefBounds): Opt { const { x, y, z } = viewDef; @@ -991,6 +992,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u {...this.getChildDocumentViewProps(pair.layout, pair.data)} dataProvider={this.childDataProvider} LayoutDoc={this.childLayoutDocFunc} + pointerEvents={this.props.layoutEngine?.() !== undefined ? "none" : undefined} jitterRotation={NumCast(this.props.Document.jitterRotation)} fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} FreezeDimensions={BoolCast(this.props.freezeChildDimensions)} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index e7cb2c015..05ad98c43 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -22,6 +22,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { width?: number; height?: number; jitterRotation: number; + pointerEvents?: "none"; transition?: string; fitToBox?: boolean; } @@ -92,7 +93,7 @@ export class CollectionFreeFormDocumentView extends DocComponent {!this.props.fitToBox ? -- cgit v1.2.3-70-g09d2 From a6d17ef79fb94334735998d3d11f7ea068dea93a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 03:15:25 -0400 Subject: cleaned up some more of the pivot view event handling api --- .../views/collections/CollectionTimeView.tsx | 23 ++++++++++------------ src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 +++++-- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 1760e2419..e05223ca0 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,6 +1,6 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, Opt, DocCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { RichTextField } from "../../../new_fields/RichTextField"; @@ -26,18 +26,15 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { _changing = false; @observable _layoutEngine = "pivot"; @observable _collapsed: boolean = false; - componentWillUnmount() { - this.props.Document.onChildClick = undefined; - } + @observable _childClickedScript: Opt; + @observable _viewDefDivClick: Opt; async componentDidMount() { - const childText = "const alias = getAlias(this); switchView(alias, thisContainer.childDetailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; - this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", thisContainer: Doc.name, shiftKey: "boolean" }); - this.props.Document._fitToBox = true; - if (!this.props.Document.onViewDefClick) { - this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); - } - this.props.Document.childDetailView = Cast(this.props.Document.childDetailView, Doc, null) ||// bcz: needs to be here to make sure the childDetailView layout template has been loaded when the first item is clicked; - DocumentView.findTemplate("detailView", StrCast(this.props.Document.type), ""); + const detailView = (await DocCastAsync(this.props.Document.childDetailView)) || DocumentView.findTemplate("detailView", StrCast(this.props.Document.type), ""); + const childText = "const alias = getAlias(this); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + runInAction(() => { + this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! }); + this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); + }); } layoutEngine = () => this._layoutEngine; @@ -88,7 +85,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @computed get contents() { return
- +
; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0a3577bc7..19e235ff2 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -278,7 +278,7 @@ export class CollectionView extends Touchable { onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)} onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />); } - get _facetWidth() { return NumCast(this.props.Document._facetWidth) } + get _facetWidth() { return NumCast(this.props.Document._facetWidth); } set _facetWidth(value) { this.props.Document._facetWidth = value; } bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d98fe190c..f19181a20 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -44,6 +44,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CollectionViewType } from "../CollectionView"; +import { Script } from "vm"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -69,6 +70,8 @@ type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchem const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema); export type collectionFreeformViewProps = { forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) + childClickScript?: ScriptField; + viewDefDivClick?: ScriptField; }; @observer @@ -847,7 +850,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u } @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; } - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } + @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); } backgroundHalo = () => BoolCast(this.Document.useClusters); getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { @@ -906,7 +909,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u } onViewDefDivClick = (e: React.MouseEvent, payload: any) => { - (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload }); + (this.props.viewDefDivClick || ScriptCast(this.props.Document.onViewDefDivClick))?.script.run({ this: this.props.Document, payload }); e.stopPropagation(); } private viewDefToJSX(viewDef: ViewDefBounds): Opt { -- cgit v1.2.3-70-g09d2 From 67c56296339bd1c760b704c1d14710ec6f575d49 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Apr 2020 22:55:10 -0400 Subject: added freeze button for web boxes. cleaned up pointerevent setting throughout code. --- src/client/views/InkingStroke.scss | 8 +++- src/client/views/InkingStroke.tsx | 5 +-- src/client/views/Main.scss | 1 - src/client/views/MainView.scss | 1 + .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/MarqueeView.scss | 1 - src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/FormattedTextBox.scss | 1 - src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.scss | 1 - src/client/views/nodes/KeyValueBox.scss | 1 - src/client/views/nodes/LabelBox.scss | 1 - src/client/views/nodes/LinkAnchorBox.scss | 1 - src/client/views/nodes/PresBox.scss | 1 - src/client/views/nodes/QueryBox.scss | 1 - src/client/views/nodes/ScreenshotBox.scss | 5 --- src/client/views/nodes/ScriptingBox.scss | 1 - src/client/views/nodes/SliderBox.scss | 1 - src/client/views/nodes/VideoBox.scss | 7 ++-- src/client/views/nodes/WebBox.scss | 15 ++++---- src/client/views/nodes/WebBox.tsx | 44 +++++++++------------- 22 files changed, 42 insertions(+), 64 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/InkingStroke.scss b/src/client/views/InkingStroke.scss index cdbfdcff3..433433a42 100644 --- a/src/client/views/InkingStroke.scss +++ b/src/client/views/InkingStroke.scss @@ -1,3 +1,7 @@ -.inkingStroke-marker { - mix-blend-mode: multiply +.inkingStroke { + mix-blend-mode: multiply; + stroke-linejoin: round; + stroke-linecap: round; + overflow: visible !important; + transform-origin: top left; } \ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index f66c04e1f..7a318d5c2 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,4 +1,3 @@ -import { computed } from "mobx"; import { observer } from "mobx-react"; import { documentSchema } from "../../new_fields/documentSchemas"; import { InkData, InkField, InkTool } from "../../new_fields/InkField"; @@ -47,14 +46,12 @@ export class InkingStroke extends ViewBoxBaseComponent { ContextMenu.Instance.addItem({ diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 4709e7ef2..a2a9ceca5 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -24,7 +24,6 @@ body { .jsx-parser { width: 100%; height: 100%; - pointer-events: none; border-radius: inherit; position: inherit; // background: inherit; diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index e95802e54..e9f2248ad 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -28,6 +28,7 @@ width: 100%; height: 100%; position: absolute; + pointer-events: all; top: 0; left: 0; z-index: 1; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d2c8cc3ad..510c9924b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -453,7 +453,7 @@ class TreeView extends React.Component { fontWeight: this.props.document.searchMatch ? "bold" : undefined, textDecoration: Doc.GetT(this.props.document, "title", "string", true) ? "underline" : undefined, outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined, - pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none" + pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? undefined : "none" }} > {Doc.GetT(this.props.document, "editTitle", "boolean", true) ? this.editableView("title") : diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 19e235ff2..877e4355f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -472,7 +472,7 @@ export class CollectionView extends Touchable { }; return (
(Docu const titleView = (!showTitle ? (null) :
(Docu transformOrigin: this._animate ? "center center" : undefined, transform: this._animate ? `scale(${this._animate})` : undefined, transition: !this._animate ? StrCast(this.Document.transition) : this._animate < 1 ? "transform 0.5s ease-in" : "transform 0.5s ease-out", - pointerEvents: this.ignorePointerEvents ? "none" : "all", + pointerEvents: this.ignorePointerEvents ? "none" : undefined, color: StrCast(this.layoutDoc.color, "inherit"), outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 7d40b3149..7a05ec3a3 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -25,7 +25,6 @@ overflow-x: hidden; color: initial; height: 100%; - pointer-events: all; max-height: 100%; display: flex; flex-direction: row; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d641dc791..62911dc5c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1185,7 +1185,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"]), opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1, color: this.props.hideOnLeave ? "white" : "inherit", - pointerEvents: interactive ? "none" : "all", + pointerEvents: interactive ? "none" : undefined, fontSize: NumCast(this.layoutDoc.fontSize, 13), fontFamily: StrCast(this.layoutDoc.fontFamily, "Crimson Text"), }} diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 7bbf4a368..49425c2c2 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -1,6 +1,5 @@ .imageBox, .imageBox-dragging { - pointer-events: all; border-radius: inherit; width: 100%; height: 100%; diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss index a26880c9e..eb7c2f32b 100644 --- a/src/client/views/nodes/KeyValueBox.scss +++ b/src/client/views/nodes/KeyValueBox.scss @@ -8,7 +8,6 @@ border-radius: $border-radius; box-sizing: border-box; display: inline-block; - pointer-events: all; cursor: default; .imageBox-cont img { width: auto; diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss index ab5b2c6b3..56dd86ff9 100644 --- a/src/client/views/nodes/LabelBox.scss +++ b/src/client/views/nodes/LabelBox.scss @@ -1,7 +1,6 @@ .labelBox-outerDiv { width: 100%; height: 100%; - pointer-events: all; border-radius: inherit; display: flex; flex-direction: column; diff --git a/src/client/views/nodes/LinkAnchorBox.scss b/src/client/views/nodes/LinkAnchorBox.scss index 7b6093ebd..24f9c1ea0 100644 --- a/src/client/views/nodes/LinkAnchorBox.scss +++ b/src/client/views/nodes/LinkAnchorBox.scss @@ -4,7 +4,6 @@ width: 15; height: 15; border-radius: 20px; - pointer-events: all; user-select: none; .linkAnchorBox-linkCloser { diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index ba8389fda..6676d8cd2 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -10,7 +10,6 @@ letter-spacing: 2px; overflow: hidden; transition: 0.7s opacity ease; - pointer-events: all; .presBox-buttons { padding: 10px; diff --git a/src/client/views/nodes/QueryBox.scss b/src/client/views/nodes/QueryBox.scss index 82f64054c..b5f90aa1e 100644 --- a/src/client/views/nodes/QueryBox.scss +++ b/src/client/views/nodes/QueryBox.scss @@ -2,5 +2,4 @@ width: 100%; height: 100%; position: absolute; - pointer-events: all; } \ No newline at end of file diff --git a/src/client/views/nodes/ScreenshotBox.scss b/src/client/views/nodes/ScreenshotBox.scss index 6cc184948..141960f60 100644 --- a/src/client/views/nodes/ScreenshotBox.scss +++ b/src/client/views/nodes/ScreenshotBox.scss @@ -1,5 +1,4 @@ .screenshotBox { - pointer-events: all; transform-origin: top left; background: white; color: black; @@ -21,10 +20,6 @@ height: Auto; } -.screenshotBox-content-interactive, .screenshotBox-content-fullScreen { - pointer-events: all; -} - .screenshotBox-uiButtons { background:dimgray; border: orange solid 1px; diff --git a/src/client/views/nodes/ScriptingBox.scss b/src/client/views/nodes/ScriptingBox.scss index 678a1a22d..43695f00d 100644 --- a/src/client/views/nodes/ScriptingBox.scss +++ b/src/client/views/nodes/ScriptingBox.scss @@ -3,7 +3,6 @@ height: 100%; display: flex; flex-direction: column; - pointer-events: all; background-color: rgb(241, 239, 235); padding: 10px; .scriptingBox-inputDiv { diff --git a/src/client/views/nodes/SliderBox.scss b/src/client/views/nodes/SliderBox.scss index 4ef277d8c..78015bd70 100644 --- a/src/client/views/nodes/SliderBox.scss +++ b/src/client/views/nodes/SliderBox.scss @@ -1,7 +1,6 @@ .sliderBox-outerDiv { width: 100%; height: 100%; - pointer-events: all; border-radius: inherit; display: flex; flex-direction: column; diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index fabbf5196..0c0854ac2 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -1,5 +1,4 @@ .videoBox { - pointer-events: all; transform-origin: top left; .videoBox-viewer { opacity: 0.99; // hack! overcomes some kind of Chrome weirdness where buttons (e.g., snapshot) disappear at some point as the video is resized larger @@ -24,9 +23,9 @@ height: 100%; } -.videoBox-content-interactive, .videoBox-content-fullScreen, .videoBox-content-YouTube-fullScreen { - pointer-events: all; -} +// .videoBox-content-interactive, .videoBox-content-fullScreen, .videoBox-content-YouTube-fullScreen { +// pointer-events: all; +// } .videoBox-time{ color : white; diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 3014b9425..cdeac4bd1 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -18,8 +18,7 @@ display:none; } } -.webBox-cont, -.webBox-cont-dragging { +.webBox-cont { padding: 0vw; position: absolute; top: 0; @@ -32,8 +31,6 @@ } .webBox-cont-interactive { - pointer-events: all; - span { user-select: text !important; } @@ -49,7 +46,6 @@ width: 100%; height: 100%; position: absolute; - pointer-events: all; } .webBox-button { @@ -59,7 +55,7 @@ height: 100%; } -.webView-urlEditor { +.webBox-urlEditor { position: relative; opacity: 0.9; z-index: 9001; @@ -74,6 +70,12 @@ padding-bottom: 10px; overflow: hidden; + .webBox-freeze { + display: flex; + align-items: center; + justify-content: center; + } + .editorBase { display: flex; @@ -115,7 +117,6 @@ width: 100%; height: 100%; position: absolute; - pointer-events: all; .indicator { position: absolute; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index b48437464..26e947f5b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,5 +1,5 @@ import { library } from "@fortawesome/fontawesome-svg-core"; -import { faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { faStickyNote, faLock, faUnlock } from '@fortawesome/free-solid-svg-icons'; import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, FieldResult } from "../../../new_fields/Doc"; @@ -23,6 +23,7 @@ import React = require("react"); import * as WebRequest from 'web-request'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; +import { DocumentView } from "./DocumentView"; const htmlToText = require("html-to-text"); library.add(faStickyNote); @@ -116,31 +117,21 @@ export class WebBox extends ViewBoxAnnotatableComponent { - let url: string = ""; - const field = Cast(this.rootDoc[this.props.fieldKey], WebField); - if (field) url = field.url.href; - - const newBox = Docs.Create.TextDocument(url, { - x: NumCast(this.rootDoc.x), - y: NumCast(this.rootDoc.y), - title: url, - _width: 200, - _height: 70, - }); - - SelectionManager.SelectedDocuments().map(dv => { - dv.props.addDocument?.(newBox); - dv.props.removeDocument?.(dv.rootDoc); - }); - - Doc.BrushDoc(newBox); + toggleNativeDimensions = () => { + if (this.Document._nativeWidth || this.Document._nativeHeight) { + DocumentView.unfreezeNativeDimensions(this.layoutDoc); + this.layoutDoc.lockedTransform = false; + } + else { + Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight()); + this.layoutDoc.lockedTransform = true; + } } urlEditor() { + const frozen = this.layoutDoc._nativeWidth && this.layoutDoc._nativeHeight; return ( -
+
-
- +
+
@@ -331,7 +322,8 @@ export class WebBox extends ViewBoxAnnotatableComponent {!frozen ? (null) : -
+
@@ -350,7 +342,7 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.content}
e.stopPropagation()} onScroll={e => { if (this._iframeRef.current!.contentDocument!.children[0].scrollTop !== this._outerRef.current!.scrollTop) { -- cgit v1.2.3-70-g09d2 From 0bc20bc8c1f2b6b77624d37047d63a31fa0cf299 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Apr 2020 11:25:30 -0400 Subject: added additional rendition menu item --- src/client/views/collections/CollectionView.tsx | 67 ++++++++++++++----------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 877e4355f..178c3189b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -192,38 +192,45 @@ export class CollectionView extends Touchable { } + setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) { + const existingVm = ContextMenu.Instance.findByDescription(category); + const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; + + subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" }); + if (addExtras && CollectionView._safeMode) { + ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" }); + } + subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" }); + subItems.push({ description: "Treeview", event: () => func(CollectionViewType.Tree), icon: "tree" }); + subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" }); + subItems.push({ description: "Stacking (AutoHeight)", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" }); + subItems.push({ description: "Staff", event: () => func(CollectionViewType.Staff), icon: "music" }); + subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" }); + subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" }); + subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" }); + subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); + subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); + subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); + if (addExtras) switch (this.props.Document._viewType) { + case CollectionViewType.Freeform: { + subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); + break; + } + } + addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); + !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" }); + } + onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - const existingVm = ContextMenu.Instance.findByDescription("View Modes..."); - const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; - subItems.push({ description: "Freeform", event: () => { this.props.Document._viewType = CollectionViewType.Freeform; }, icon: "signature" }); - if (CollectionView._safeMode) { - ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document._viewType = CollectionViewType.Invalid, icon: "project-diagram" }); - } - subItems.push({ description: "Schema", event: () => this.props.Document._viewType = CollectionViewType.Schema, icon: "th-list" }); - subItems.push({ description: "Treeview", event: () => this.props.Document._viewType = CollectionViewType.Tree, icon: "tree" }); - subItems.push({ description: "Stacking", event: () => this.props.Document._viewType = CollectionViewType.Stacking, icon: "ellipsis-v" }); - subItems.push({ - description: "Stacking (AutoHeight)", event: () => { - this.props.Document._viewType = CollectionViewType.Stacking; - this.props.Document._autoHeight = true; - }, icon: "ellipsis-v" - }); - 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/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); - subItems.push({ description: "Map", event: () => this.props.Document._viewType = CollectionViewType.Map, icon: "globe-americas" }); - switch (this.props.Document._viewType) { - case CollectionViewType.Freeform: { - subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); - break; - } - } - subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); - !existingVm && ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" }); + + this.setupViewTypes("View Modes ...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); + this.setupViewTypes("Additional Rendition ...", vtype => { + const newRendition = Doc.MakeAlias(this.props.Document); + newRendition._viewType = vtype; + this.props.addDocTab(newRendition, "onRight"); + return newRendition; + }, false); const existing = ContextMenu.Instance.findByDescription("Layout..."); const layoutItems = existing && "subitems" in existing ? existing.subitems : []; -- cgit v1.2.3-70-g09d2 From 3d629495644631e6b614b1b48f1d32d6c7aeefc6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Apr 2020 17:25:17 -0400 Subject: added parameterization capability to layout strings. added Div's that can take Dash field values --- src/client/util/RichTextSchema.tsx | 6 ++-- src/client/views/DocumentDecorations.tsx | 4 +-- src/client/views/collections/CollectionView.tsx | 7 ++-- src/client/views/nodes/DocumentContentsView.tsx | 45 +++++++++++++++++++++---- 4 files changed, 46 insertions(+), 16 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 1522f5e21..d23962d5c 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -852,9 +852,9 @@ export class DashDocView { }; this._renderDisposer?.(); this._renderDisposer = reaction(() => { - if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { - finalLayout.rootDocument = dashDoc.aliasOf; // bcz: check on this ... why is it here? - } + // if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { + // finalLayout.rootDocument = dashDoc.aliasOf; // bcz: check on this ... why is it here? + // } const layoutKey = StrCast(finalLayout.layoutKey); const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; if (finalLayout !== dashDoc && finalKey) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c8766a6b3..bd41788d4 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -3,7 +3,7 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faT import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym } from "../../new_fields/Doc"; +import { Doc, DataSym, Field } from "../../new_fields/Doc"; import { PositionDocument } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; @@ -366,7 +366,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || ""; } if (this._titleControlString.startsWith("#")) { - return selected.props.Document[this._titleControlString.substring(1)]?.toString() || "-unset-"; + return Field.toString(selected.props.Document[this._titleControlString.substring(1)] as Field) || "-unset-"; } return this._accumulatedTitle; } else if (SelectionManager.SelectedDocuments().length > 1) { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 178c3189b..4448fcf21 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -211,11 +211,8 @@ export class CollectionView extends Touchable { subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); - if (addExtras) switch (this.props.Document._viewType) { - case CollectionViewType.Freeform: { - subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); - break; - } + if (addExtras && this.props.Document._viewType === CollectionViewType.Freeform) { + subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); } addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" }); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 7522af3a3..765416658 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,8 +1,8 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt } from "../../../new_fields/Doc"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { OmitKeys, Without } from "../../../Utils"; +import { Doc, Opt, Field } from "../../../new_fields/Doc"; +import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; +import { OmitKeys, Without, emptyPath } from "../../../Utils"; import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; @@ -53,6 +53,31 @@ class ObserverJsxParser1 extends JsxParser { const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; + +interface DivProps { + Document: Doc; +} + +@observer +export class Div extends React.Component { + render() { + const style: { [key: string]: any } = {}; + const divKeys = OmitKeys(this.props, ["children", "Document", "key", "__proto__"]).omit; + Object.keys(divKeys).map((prop: string) => { + let p = (this.props as any)[prop] as string; + if (p?.startsWith("@")) { // bcz: extend this to support expression -- is this really a script? + const key = p.substring(1); + const n = Cast(this.props.Document[key], "number", null); + p = n ? n.toString() : StrCast(this.props.Document[key], p); + } + style[prop] = p; + }); + return
+ {this.props.children} +
; + } +} + @observer export class DocumentContentsView extends React.Component boolean, @@ -102,21 +127,29 @@ export class DocumentContentsView extends React.Component 12 || !this.layout || !this.layoutDoc) ? (null) : + let layoutFrame = this.layout; + const replacer = (match: any, p1: string, offset: any, string: any) => { + const n = Cast(this.props.Document[p1], "number", null); + return n !== undefined ? n.toString() : StrCast(this.props.Document[p1], p1); + }; + layoutFrame = layoutFrame.replace(/\{([a-zA-Z0-9_-]+)\}/g, replacer); + return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) : this.props.forceLayout === "FormattedTextBox" && this.props.forceFieldKey ? : { console.log(test); }} -- cgit v1.2.3-70-g09d2 From 04bc902ad31eaf07e3a5edc34854744a88ffb3bc Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 14:08:19 -0400 Subject: fixed clicking gear icon on doc decorations. moved repl to Drag items. Removed Open... menu. Added Open FIelds & Full SCreen to Open New Persepectives. --- src/client/views/DocumentDecorations.tsx | 4 ++-- src/client/views/MainView.tsx | 3 ++- src/client/views/OverlayView.tsx | 6 +++++- src/client/views/collections/CollectionView.tsx | 8 ++------ src/client/views/nodes/DocumentView.tsx | 11 ++--------- src/server/authentication/models/current_user_utils.ts | 9 +++++---- 6 files changed, 18 insertions(+), 23 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index bd41788d4..5d6242201 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -144,8 +144,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onSettingsClick = (e: PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey) { let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; - while (child.children.length && child.className !== "jsx-parser") child = child.children[0]; - simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + while (child.children.length) child = child.children[0]; + simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f8e246315..8fb67c435 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faTerminal, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; +import { faTerminal, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -103,6 +103,7 @@ export class MainView extends React.Component { } library.add(faTerminal); + library.add(faCalculator); library.add(faWindowMaximize); library.add(faFileAlt); library.add(faAddressCard); diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 614217bc8..20aa14f84 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -9,6 +9,8 @@ import { Transform } from "../util/Transform"; import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView"; import { DocumentView } from "./nodes/DocumentView"; import './OverlayView.scss'; +import { Scripting } from "../util/Scripting"; +import { ScriptingRepl } from './ScriptingRepl'; export type OverlayDisposer = () => void; @@ -210,4 +212,6 @@ export class OverlayView extends React.Component {
); } -} \ No newline at end of file +} +// bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error +Scripting.addGlobal(function addOverlayWindow(Tag: string, options: OverlayElementOptions) { const x = ; OverlayView.Instance.addWindow(x, options); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4448fcf21..ade54f2c9 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -221,8 +221,8 @@ export class CollectionView extends Touchable { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - this.setupViewTypes("View Modes ...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); - this.setupViewTypes("Additional Rendition ...", vtype => { + this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); + this.setupViewTypes("Open New Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; this.props.addDocTab(newRendition, "onRight"); @@ -242,10 +242,6 @@ export class CollectionView extends Touchable { !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); - const open = ContextMenu.Instance.findByDescription("Open..."); - const openItems = open && "subitems" in open ? open.subitems : []; - !open && ContextMenu.Instance.addItem({ description: "Open...", subitems: openItems, icon: "hand-point-right" }); - const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }]; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 286044ab2..d8783c458 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -40,8 +40,6 @@ import { DocComponent } from "../DocComponent"; import { EditableView } from '../EditableView'; import { InkingControl } from '../InkingControl'; import { KeyphraseQueryView } from '../KeyphraseQueryView'; -import { OverlayView } from '../OverlayView'; -import { ScriptingRepl } from '../ScriptingRepl'; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import { RadialMenu } from './RadialMenu'; @@ -737,17 +735,12 @@ export class DocumentView extends DocComponent(Docu layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); - const open = ContextMenu.Instance.findByDescription("Open..."); + const open = cm.findByDescription("Open New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" }); - openItems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, "inTab", this.props.LibraryPath), icon: "folder" }); - openItems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, "onRight", this.props.LibraryPath), icon: "caret-square-right" }); - openItems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" }); - openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); - openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" }); + !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); const existingOnClick = cm.findByDescription("OnClick..."); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 3955f64fc..b4f9ead53 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -84,7 +84,7 @@ export class CurrentUserUtils { if (doc["template-buttons"] === undefined) { doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, doc["template-button-query"] as Doc], { - title: "Template Item Creators", _xMargin: 0, _showTitle: "title", + title: "Compound Item Creators", _xMargin: 0, _showTitle: "title", _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), })); @@ -186,6 +186,7 @@ export class CurrentUserUtils { { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, + { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, @@ -194,10 +195,10 @@ export class CurrentUserUtils { // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, - { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, { title: "Drag a document previewer", label: "Prev", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, - // { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" }, + { title: "Drag a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, ]; + } // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools @@ -229,7 +230,7 @@ export class CurrentUserUtils { if (dragCreatorSet === undefined) { doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Standard Item Creators", _showTitle: "title", _xMargin: 0, + title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), })); -- cgit v1.2.3-70-g09d2 From 72f614f023a4bac6a2f0b63a1b1a16e6f4545c7a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 23 Apr 2020 00:53:08 -0400 Subject: fixed browser back after link navigation. simplified menus more. fixed jitter mode to be seeded. fixed menu gear for collections. . --- src/client/util/History.ts | 6 +++- src/client/util/ProsemirrorExampleTransfer.ts | 4 +-- src/client/views/DocumentDecorations.tsx | 6 +++- .../views/collections/CollectionDockingView.tsx | 6 +++- .../views/collections/CollectionStackingView.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 4 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 +++++------ src/client/views/nodes/AudioBox.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 +++-- src/client/views/nodes/DocumentBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 41 ++++++++++++++++++++-- src/client/views/nodes/KeyValueBox.tsx | 23 ++++++++---- src/client/views/nodes/LinkAnchorBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/SliderBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- 20 files changed, 103 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 545e8acb4..2c53d7e52 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -40,8 +40,12 @@ export namespace HistoryUtil { // } } + let _lastStatePush = 0; export function pushState(state: ParsedUrl) { - history.pushState(state, "", createUrl(state)); + if (Date.now() - _lastStatePush > 1000) { + history.pushState(state, "", createUrl(state)); + } + _lastStatePush = Date.now(); } export function replaceState(state: ParsedUrl) { diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 42247f177..680f48f70 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -154,7 +154,7 @@ export default function buildKeymap>(schema: S, props: any const originalDoc = layoutDoc.rootDocument || layoutDoc; if (originalDoc instanceof Doc) { const newDoc = Docs.Create.TextDocument("", { - title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), + layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x), y: NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10, _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -172,7 +172,7 @@ export default function buildKeymap>(schema: S, props: any const originalDoc = layoutDoc.rootDocument || layoutDoc; if (force || props.Document._singleLine) { const newDoc = Docs.Create.TextDocument("", { - title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), + layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10, y: NumCast(originalDoc.y), _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); FormattedTextBox.SelectOnLoad = newDoc[Id]; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 43c7751fa..6e699bc68 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -134,7 +134,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onSettingsClick = (e: PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey) { let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; - while (child.children.length) child = child.children[0]; + while (child.children.length) { + const next = Array.from(child.children).find(c => !c.className.includes("collectionViewChrome")); + if (next) child = next; + else break; + } simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); } } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5e77bc0bb..0d859c3f1 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -29,6 +29,7 @@ import "./CollectionDockingView.scss"; import { SubCollectionViewProps } from "./CollectionSubView"; import { DockingViewButtonSelector } from './ParentDocumentSelector'; import React = require("react"); +import { CollectionViewType } from './CollectionView'; library.add(faFile); const _global = (window /* browser */ || global /* node */) as any; @@ -93,6 +94,9 @@ export class CollectionDockingView extends React.Component { addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { SelectionManager.DeselectAll(); - if (doc.dockingConfig) { + if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") { return MainView.Instance.openWorkspace(doc); } else if (location === "onRight") { return CollectionDockingView.AddRightSplit(doc, libraryPath); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b15649d83..24a3119cc 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -397,7 +397,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (!e.isPropagationStopped()) { const subItems: ContextMenuProps[] = []; subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" }); - ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" }); } } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 742a818bc..06ebf6d2d 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -102,7 +102,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); } @computed get _allFacets() { const facets = new Set(); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f589c2c76..a052d045c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -711,7 +711,7 @@ export class CollectionTreeView extends CollectionSubView this.props.Document.treeViewPreventOpen = !this.props.Document.treeViewPreventOpen, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" }); - ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); } ContextMenu.Instance.addItem({ description: "Buxton Layout", icon: "eye", event: () => { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ade54f2c9..4f1242c33 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -229,7 +229,7 @@ export class CollectionView extends Touchable { return newRendition; }, false); - const existing = ContextMenu.Instance.findByDescription("Layout..."); + const existing = ContextMenu.Instance.findByDescription("Options..."); const layoutItems = existing && "subitems" in existing ? existing.subitems : []; layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); if (this.props.Document.childLayout instanceof Doc) { @@ -240,7 +240,7 @@ export class CollectionView extends Touchable { } layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); - !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); + !existing && ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3b5101a4d..55e55e56c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1048,16 +1048,17 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.children && this.props.annotationsKey) return; - const layoutItems: ContextMenuProps[] = []; - - layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); - layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); - layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); - layoutItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); + const options = ContextMenu.Instance.findByDescription("Options..."); + const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; + + optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); + optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); + optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); - layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); - layoutItems.push({ + optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); + optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); input.type = "file"; @@ -1085,7 +1086,7 @@ export class CollectionFreeFormView extends CollectionSubView { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8f40ea2be..6ff6d1b42 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -162,7 +162,7 @@ export class AudioBox extends ViewBoxBaseComponent this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Audio Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } stopRecording = action(() => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3a7e005ac..615b05e43 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,3 @@ -import anime from "animejs"; import { computed, IReactionDisposer, observable, reaction, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; @@ -29,8 +28,14 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { @observer export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { @observable _animPos: number[] | undefined = undefined; + random(min: number, max: number) { // min should not be equal to max + const mseed = Math.abs(this.X * this.Y); + const seed = (mseed * 9301 + 49297) % 233280; + var rnd = seed / 233280; + return min + rnd * (max - min); + } get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive - get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${anime.random(-1, 1) * this.props.jitterRotation}deg)`; } + get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; } get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); } diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx index ac562f19a..7583aa070 100644 --- a/src/client/views/nodes/DocumentBox.tsx +++ b/src/client/views/nodes/DocumentBox.tsx @@ -45,7 +45,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent Doc.GetProto(this.props.Document).excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" }); funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); - ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @computed get contentDoc() { return (this.props.Document.isTemplateDoc || this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document)); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a19ba6506..cab7b965a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -741,7 +741,7 @@ export class DocumentView extends DocComponent(Docu const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); - onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); + onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 2c89d53d8..1329f7dcf 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from " import { ReplaceStep } from 'prosemirror-transform'; import { EditorView } from "prosemirror-view"; import { DateField } from '../../../new_fields/DateField'; -import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym, DocListCast } from "../../../new_fields/Doc"; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { InkTool } from '../../../new_fields/InkField'; @@ -48,6 +48,7 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './Format import React = require("react"); import { PrefetchProxy } from '../../../new_fields/Proxy'; import { makeTemplate } from '../../util/DropConverter'; +import { DocumentView } from './DocumentView'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -396,6 +397,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null); } specificContextMenu = (e: React.MouseEvent): void => { + const cm = ContextMenu.Instance; + const funcs: ContextMenuProps[] = []; this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); @@ -407,10 +410,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); + + const highlighting: ContextMenuProps[] = []; ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => - funcs.push({ + highlighting.push({ description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { e.stopPropagation(); if (FormattedTextBox._highlights.indexOf(option) === -1) { @@ -421,8 +426,38 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.updateHighlights(); }, icon: "expand-arrows-alt" })); + funcs.push({ description: "highlighting...", subitems: highlighting, icon: "hand-point-right" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); + + const change = cm.findByDescription("Change Perspective..."); + const changeItems: ContextMenuProps[] = change && "subitems" in change ? change.subitems : []; + + const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null); + const noteTypes = DocListCast(noteTypesDoc?.data); + noteTypes.forEach(note => { + changeItems.push({ + description: StrCast(note.title), event: () => { + Doc.setNativeView(this.props.Document); + DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); + }, icon: "eye" + }) + }); + changeItems.push({ description: "FreeForm", event: () => DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" }) + !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); + + const open = cm.findByDescription("Open New Perspective..."); + const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; + + openItems.push({ + description: "FreeForm", event: () => { + const alias = Doc.MakeAlias(this.rootDoc); + DocumentView.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform"); + this.props.addDocTab(alias, "onRight"); + }, icon: "eye" + }) + !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); + } recordDictation = () => { diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 7aad6f90e..2970674a2 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -16,6 +16,8 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; import React = require("react"); +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; export type KVPScript = { script: CompiledScript; @@ -34,11 +36,7 @@ export class KeyValueBox extends React.Component { @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; } - - constructor(props: FieldViewProps) { - super(props); - } + get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; } @action onEnterKey = (e: React.KeyboardEvent): void => { @@ -234,13 +232,26 @@ export class KeyValueBox extends React.Component { return new Doc; } + specificContextMenu = (e: React.MouseEvent): void => { + const cm = ContextMenu.Instance; + const open = cm.findByDescription("Change Perspective..."); + const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; + openItems.push({ + description: "Default Perspective", event: () => { + this.props.addDocTab(this.fieldDocToLayout, "inTab"); + this.props.addDocTab(this.props.Document, "close"); + }, icon: "image" + }); + !open && cm.addItem({ description: "Change Perspective...", subitems: openItems, icon: "external-link-alt" }); + } + render() { const dividerDragger = this.splitPercentage === 0 ? (null) :
; - return (
+ return (
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 8e3c15908..eb647d0e4 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -109,7 +109,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent this.openLinkEditor(e), icon: "eye" }); funcs.push({ description: "Toggle Always Show Link", event: () => this.props.Document.linkDisplay = !this.props.Document.linkDisplay, icon: "eye" }); - ContextMenu.Instance.addItem({ description: "Link Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } render() { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 6db36e43c..3712c648e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -210,7 +210,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent Utils.CopyText(pdfUrl.url.pathname), icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Fit Width " + (this.Document._fitWidth ? "Off" : "On"), event: () => this.Document._fitWidth = !this.Document._fitWidth, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @computed get contentScaling() { return this.props.ContentScaling(); } diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 11b24b059..125690dc7 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -120,7 +120,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Edit Thumb Change Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Thumb Change ...", this.props.Document, "onThumbChange", obj.x, obj.y) }); - ContextMenu.Instance.addItem({ description: "Slider Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } onChange = (values: readonly number[]) => runInAction(() => { this.dataDoc[this.minThumbKey] = values[0]; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 588068334..613929bca 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -209,7 +209,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent Date: Fri, 24 Apr 2020 13:28:05 -0400 Subject: fixed presbox navigation bar layout height. --- src/client/views/collections/CollectionView.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 4 ++-- src/client/views/nodes/FormattedTextBox.tsx | 4 ++-- src/client/views/nodes/PresBox.scss | 5 +++++ 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4f1242c33..47e79f088 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -201,7 +201,7 @@ export class CollectionView extends Touchable { ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" }); } subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" }); - subItems.push({ description: "Treeview", event: () => func(CollectionViewType.Tree), icon: "tree" }); + subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" }); subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" }); subItems.push({ description: "Stacking (AutoHeight)", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" }); subItems.push({ description: "Staff", event: () => func(CollectionViewType.Staff), icon: "music" }); @@ -222,7 +222,7 @@ export class CollectionView extends Touchable { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); - this.setupViewTypes("Open New Perspective...", vtype => { + this.setupViewTypes("New Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; this.props.addDocTab(newRendition, "onRight"); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cc8773ed5..4bbdde3ea 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -687,11 +687,11 @@ export class DocumentView extends DocComponent(Docu layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); !existing && cm.addItem({ description: "Options...", subitems: layoutItems, icon: "compass" }); - const open = cm.findByDescription("Open New Perspective..."); + const open = cm.findByDescription("New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); - !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); + !open && cm.addItem({ description: "New Perspective...", subitems: openItems, icon: "external-link-alt" }); const existingOnClick = cm.findByDescription("OnClick..."); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f71343176..a018f17e8 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -444,7 +444,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp changeItems.push({ description: "FreeForm", event: undoBatch(() => Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), "change view"), icon: "eye" }); !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); - const open = cm.findByDescription("Open New Perspective..."); + const open = cm.findByDescription("New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ @@ -454,7 +454,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.props.addDocTab(alias, "onRight"); }), icon: "eye" }); - !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); + !open && cm.addItem({ description: "New Perspective...", subitems: openItems, icon: "external-link-alt" }); } diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index 6676d8cd2..78c19f351 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -11,6 +11,11 @@ overflow: hidden; transition: 0.7s opacity ease; + .presBox-listCont { + position: absolute; + height: calc(100% - 25px); + width: 100%; + } .presBox-buttons { padding: 10px; width: 100%; -- cgit v1.2.3-70-g09d2 From efd038bd12de35abc80141b130be523e3fea077a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Apr 2020 03:42:51 -0400 Subject: hopefully final cleanup of pile up collection view. added doubleTap support in setupMoveUpEvents --- src/Utils.ts | 12 ++- src/client/documents/Documents.ts | 4 + .../views/collections/CollectionPileView.scss | 8 ++ .../views/collections/CollectionPileView.tsx | 97 ++++++++++++++++++++++ src/client/views/collections/CollectionSubView.tsx | 4 +- .../views/collections/CollectionTimeView.tsx | 3 +- src/client/views/collections/CollectionView.tsx | 5 +- .../CollectionFreeFormLayoutEngines.tsx | 95 ++++++++++----------- .../collectionFreeForm/CollectionFreeFormView.tsx | 19 +++-- .../collections/collectionFreeForm/MarqueeView.tsx | 16 ++-- src/new_fields/Doc.ts | 35 ++------ 11 files changed, 189 insertions(+), 109 deletions(-) create mode 100644 src/client/views/collections/CollectionPileView.scss create mode 100644 src/client/views/collections/CollectionPileView.tsx (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 9acdc8731..ad12c68a1 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -504,8 +504,9 @@ export function setupMoveUpEvents( e: React.PointerEvent, moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean, upEvent: (e: PointerEvent) => void, - clickEvent: (e: PointerEvent) => void, - stopPropagation: boolean = true + clickEvent: (e: PointerEvent, doubleTap?: boolean) => void, + stopPropagation: boolean = true, + stopMovePropagation: boolean = true ) { (target as any)._downX = (target as any)._lastX = e.clientX; (target as any)._downY = (target as any)._lastY = e.clientY; @@ -520,12 +521,15 @@ export function setupMoveUpEvents( } (target as any)._lastX = e.clientX; (target as any)._lastY = e.clientY; - e.stopPropagation(); + stopMovePropagation && e.stopPropagation(); }; + (target as any)._doubleTap = false; const _upEvent = (e: PointerEvent): void => { + (target as any)._doubleTap = (Date.now() - (target as any)._lastTap < 300); + (target as any)._lastTap = Date.now(); upEvent(e); if (Math.abs(e.clientX - (target as any)._downX) < 4 && Math.abs(e.clientY - (target as any)._downY) < 4) { - clickEvent(e); + clickEvent(e, (target as any)._doubleTap); } document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 578d337d6..1268c97b0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -612,6 +612,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Freeform }, id); } + export function PileDocument(documents: Array, options: DocumentOptions, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Pile }, id); + } + export function LinearDocument(documents: Array, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Linear }, id); } diff --git a/src/client/views/collections/CollectionPileView.scss b/src/client/views/collections/CollectionPileView.scss new file mode 100644 index 000000000..ac874b663 --- /dev/null +++ b/src/client/views/collections/CollectionPileView.scss @@ -0,0 +1,8 @@ +.collectionPileView { + display: flex; + flex-direction: row; + position: absolute; + height: 100%; + width: 100%; + overflow: visible; +} diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx new file mode 100644 index 000000000..511efe0a7 --- /dev/null +++ b/src/client/views/collections/CollectionPileView.tsx @@ -0,0 +1,97 @@ +import { action, computed, observable, runInAction } from "mobx"; +import { observer } from "mobx-react"; +import { HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { CollectionSubView } from "./CollectionSubView"; +import "./CollectionPileView.scss"; +import React = require("react"); +import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils"; +import { SelectionManager } from "../../util/SelectionManager"; + +@observer +export class CollectionPileView extends CollectionSubView(doc => doc) { + _lastTap = 0; + _doubleTap: boolean | undefined = false; + _originalChrome: string = ""; + @observable _contentsActive = true; + @observable _layoutEngine = "pass"; + @observable _collapsed: boolean = false; + @observable _childClickedScript: Opt; + componentDidMount() { + this._originalChrome = StrCast(this.layoutDoc._chromeStatus); + this.layoutDoc._chromeStatus = "disabled"; + this.layoutDoc.hideFilterView = true; + } + componentWillUnmount() { + this.layoutDoc.hideFilterView = false; + this.layoutDoc._chromeStatus = this._originalChrome; + } + + layoutEngine = () => this._layoutEngine; + + @computed get contents() { + return
+ +
; + } + + specificMenu = (e: React.MouseEvent) => { + const layoutItems: ContextMenuProps[] = []; + const doc = this.props.Document; + + ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); + } + + toggleStarburst = action(() => { + if (this._layoutEngine === 'starburst') { + const defaultSize = 110; + this.layoutDoc.overflow = undefined; + this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2; + this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; + this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize); + this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize); + this._layoutEngine = 'pass'; + } else { + const defaultSize = 25; + this.layoutDoc.overflow = 'visible'; + !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500); + !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5); + if (this._layoutEngine === 'pass') { + this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2; + this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2; + this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym](); + this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym](); + } + this.layoutDoc._width = this.layoutDoc._height = defaultSize; + this._layoutEngine = 'starburst'; + } + }); + + pointerDown = (e: React.PointerEvent) => { + // this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header + setupMoveUpEvents(this, e, returnFalse, emptyFunction, emptyFunction, false, false); // this sets _doubleTap + } + + onClick = (e: React.MouseEvent) => { + if (e.button === 0 && (this._doubleTap || this.layoutEngine() === "starburst")) { + SelectionManager.DeselectAll(); + this.toggleStarburst(); + e.stopPropagation(); + } else if (this.layoutEngine() === "pass") { + runInAction(() => this._contentsActive = false); + setTimeout(action(() => this._contentsActive = true), 300); + } + } + + render() { + + return
+ {this.contents} +
; + } +} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 78ba3d6e6..c530b24fb 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -400,9 +400,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: if (generatedDocuments.length) { const set = generatedDocuments.length > 1 && generatedDocuments.map(d => Doc.iconify(d)); if (set) { - const pile = Docs.Create.FreeformDocument(generatedDocuments, { ...options, title: "pile", _LODdisable: true, }); - Doc.pileup(pile, generatedDocuments); - addDocument(pile); + addDocument(Doc.pileup(generatedDocuments, options.x!, options.y!)); } else { generatedDocuments.forEach(addDocument); } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 63498cea1..045134225 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -19,7 +19,6 @@ const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; import React = require("react"); -import { DocumentView } from "../nodes/DocumentView"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -84,7 +83,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } @computed get contents() { - return
+ return
; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 47e79f088..f82c6d8a6 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -46,6 +46,7 @@ import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; import CollectionMapView from './CollectionMapView'; import { Transform } from 'prosemirror-transform'; +import { CollectionPileView } from './CollectionPileView'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -67,7 +68,8 @@ export enum CollectionViewType { Carousel = "carousel", Linear = "linear", Staff = "staff", - Map = "map" + Map = "map", + Pile = "pileup" } export interface CollectionRenderProps { @@ -169,6 +171,7 @@ export class CollectionView extends Touchable { case CollectionViewType.Multicolumn: return (); case CollectionViewType.Multirow: return (); case CollectionViewType.Linear: { return (); } + case CollectionViewType.Pile: { return (); } case CollectionViewType.Carousel: { return (); } case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index d8bd18ec7..9ca747113 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -13,10 +13,11 @@ import { listSpec } from "../../../../new_fields/Schema"; export interface ViewDefBounds { type: string; - text?: string; + payload: any; x: number; y: number; z?: number; + text?: string; zIndex?: number; width?: number; height?: number; @@ -24,14 +25,13 @@ export interface ViewDefBounds { fontSize?: number; highlight?: boolean; color?: string; - payload: any; replica?: string; pair?: { layout: Doc, data?: Doc }; } export interface PoolData { - x?: number; - y?: number; + x: number; + y: number; z?: number; zIndex?: number; width?: number; @@ -40,7 +40,7 @@ export interface PoolData { transition?: string; highlight?: boolean; replica?: string; - pair: { layout: Doc, data?: Doc } + pair: { layout: Doc, data?: Doc }; } export interface ViewDefResult { @@ -84,96 +84,88 @@ interface PivotColumn { export function computerPassLayout( poolData: Map, pivotDoc: Doc, - filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { - const docMap = new Map(); + const docMap = new Map(); childPairs.forEach(({ layout, data }, i) => { docMap.set(layout[Id], { - type: "doc", x: NumCast(layout.x), y: NumCast(layout.y), width: layout[WidthSym](), height: layout[HeightSym](), - payload: undefined, pair: { layout, data }, replica: "" }); }); - return normalizeResults(panelDim, 12, childPairs, docMap, poolData, viewDefsToJSX, [], 0, [], childPairs.filter(c => !filterDocs.includes(c.layout))); + return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []); } export function computerStarburstLayout( poolData: Map, pivotDoc: Doc, - filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { - const docMap = new Map(); + const docMap = new Map(); const burstRadius = [NumCast(pivotDoc._starburstRadius, panelDim[0]), NumCast(pivotDoc._starburstRadius, panelDim[1])]; const docScale = NumCast(pivotDoc._starburstDocScale); const docSize = docScale * 100; // assume a icon sized at 100 const scaleDim = [burstRadius[0] + docSize, burstRadius[1] + docSize]; - childPairs.forEach((pair, i) => { + childPairs.forEach(({ layout, data }, i) => { const deg = i / childPairs.length * Math.PI * 2; - docMap.set(pair.layout[Id], { - type: "doc", - x: Math.cos(deg) * (burstRadius[0] / 3) - docScale * pair.layout[WidthSym]() / 2, - y: Math.sin(deg) * (burstRadius[1] / 3) - docScale * pair.layout[HeightSym]() / 2, - width: docScale * pair.layout[WidthSym](), - height: docScale * pair.layout[HeightSym](), - payload: undefined, + docMap.set(layout[Id], { + x: Math.cos(deg) * (burstRadius[0] / 3) - docScale * layout[WidthSym]() / 2, + y: Math.sin(deg) * (burstRadius[1] / 3) - docScale * layout[HeightSym]() / 2, + width: docScale * layout[WidthSym](), + height: docScale * layout[HeightSym](), + pair: { layout, data }, replica: "" }); }); - return normalizeResults(scaleDim, 12, childPairs, docMap, poolData, viewDefsToJSX, [], 0, [], childPairs.filter(c => !filterDocs.includes(c.layout))); + return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []); } export function computePivotLayout( poolData: Map, pivotDoc: Doc, - filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { - const docMap = new Map(); + const docMap = new Map(); const fieldKey = "data"; const pivotColumnGroups = new Map, PivotColumn>(); const pivotFieldKey = toLabel(pivotDoc._pivotField); - for (const doc of filterDocs) { - const lval = Cast(doc[pivotFieldKey], listSpec("string"), null); - const val = Field.toString(doc[pivotFieldKey] as Field); + childPairs.map(pair => { + const lval = Cast(pair.layout[pivotFieldKey], listSpec("string"), null); + const val = Field.toString(pair.layout[pivotFieldKey] as Field); if (lval) { lval.forEach((val, i) => { !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] }); - pivotColumnGroups.get(val)!.docs.push(doc); + pivotColumnGroups.get(val)!.docs.push(pair.layout); pivotColumnGroups.get(val)!.replicas.push(i.toString()); }); } else if (val) { !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] }); - pivotColumnGroups.get(val)!.docs.push(doc); + pivotColumnGroups.get(val)!.docs.push(pair.layout); pivotColumnGroups.get(val)!.replicas.push(""); } else { - docMap.set(doc[Id], { - type: "doc", + docMap.set(pair.layout[Id], { x: 0, y: 0, zIndex: -99, width: 0, height: 0, - payload: undefined, - pair: { layout: doc }, + pair, replica: "" - }) + }); } - } + }); let nonNumbers = 0; childPairs.map(pair => { const num = toNumber(pair.layout[pivotFieldKey]); @@ -252,12 +244,10 @@ export function computePivotLayout( wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth; } docMap.set(doc[Id] + (val.replicas || ""), { - type: "doc", x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? (numCols - val.docs.length) * pivotAxisWidth / 2 : 0), y: -y + (pivotAxisWidth - hgt) / 2, width: wid, height: hgt, - payload: undefined, pair: { layout: doc }, replica: val.replicas[i] }); @@ -273,7 +263,7 @@ export function computePivotLayout( const dividers = sortedPivotKeys.map((key, i) => ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); groupNames.push(...dividers); - return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childPairs.filter(c => !filterDocs.includes(c.layout))); + return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } function toNumber(val: FieldResult) { @@ -283,14 +273,13 @@ function toNumber(val: FieldResult) { export function computeTimelineLayout( poolData: Map, pivotDoc: Doc, - filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { const fieldKey = "data"; const pivotDateGroups = new Map(); - const docMap = new Map(); + const docMap = new Map(); const groupNames: ViewDefBounds[] = []; const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field); const curTime = toNumber(pivotDoc[fieldKey + "-timelineCur"]); @@ -306,11 +295,11 @@ export function computeTimelineLayout( let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq; let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq; - filterDocs.map(doc => { - const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey]))); + childPairs.forEach(pair => { + const num = NumCast(pair.layout[timelineFieldKey], Number(StrCast(pair.layout[timelineFieldKey]))); if (!Number.isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) { !pivotDateGroups.get(num) && pivotDateGroups.set(num, []); - pivotDateGroups.get(num)!.push(doc); + pivotDateGroups.get(num)!.push(pair.layout); minTime = Math.min(num, minTime); maxTime = Math.max(num, maxTime); } @@ -369,7 +358,7 @@ export function computeTimelineLayout( } const divider = { type: "div", color: Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "dimGray" : "black", x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined }; - return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider], childPairs.filter(c => !filterDocs.includes(c.layout))); + return normalizeResults(panelDim, fontHeight, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]); function layoutDocsAtTime(keyDocs: Doc[], key: number) { keyDocs.forEach(doc => { @@ -382,13 +371,11 @@ export function computeTimelineLayout( wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth; } docMap.set(doc[Id], { - type: "doc", x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2, zIndex: (curTime === key ? 1000 : zind++), highlight: curTime === key, width: wid / (Math.max(stack, 1)), height: hgt / (Math.max(stack, 1)), - payload: undefined, pair: { layout: doc }, replica: "" }); @@ -397,12 +384,19 @@ export function computeTimelineLayout( } } -function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map, - poolData: Map, viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[], - extraDocs: { data?: Doc, layout: Doc }[]): ViewDefResult[] { +function normalizeResults( + panelDim: number[], + fontHeight: number, + docMap: Map, + poolData: Map, + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], + groupNames: ViewDefBounds[], + minWidth: number, + extras: ViewDefBounds[] +): ViewDefResult[] { const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds); const docEles = Array.from(docMap.entries()).map(ele => ele[1]); - const aggBounds = aggregateBounds(docEles.concat(grpEles).filter(e => e.zIndex !== -99), 0, 0); + const aggBounds = aggregateBounds(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" }))).filter(e => e.zIndex !== -99), 0, 0); 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; @@ -420,12 +414,11 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { zIndex: newPosRaw.zIndex, width: (newPosRaw.width || 0) * scale, height: newPosRaw.height! * scale, - pair: ele[1].pair! + pair: ele[1].pair }; poolData.set(newPos.pair.layout[Id] + (newPos.replica || ""), { transition: "transform 1s", ...newPos }); } }); - extraDocs.map(ed => poolData.set(ed.layout[Id], { x: 0, y: 0, zIndex: -99, pair: ed })); return viewDefsToJSX(extras.concat(groupNames).map(gname => ({ type: gname.type, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5555d9e84..af9d3c5be 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -902,7 +902,7 @@ export class CollectionFreeFormView extends CollectionSubView, pivotDoc: Doc, - filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], - viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[]) { - return engine(poolData, this.props.Document, this.childDocs, - this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); + viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[] + ) { + return engine(poolData, this.props.Document, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } doFreeformLayout(poolData: Map) { @@ -977,7 +976,7 @@ export class CollectionFreeFormView extends CollectionSubView(); - const engine = StrCast(this.layoutDoc._layoutEngine) || this.props.layoutEngine?.(); + const engine = this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine); switch (engine) { case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; @@ -1001,6 +1000,7 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k[0], k[1])); const elements: ViewDefResult[] = computedElementData.slice(); + const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry => elements.push({ ele: , @@ -1082,7 +1083,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.Document.jitterRotation = (this.props.Document.jitterRotation ? 0 : 10)), icon: "paint-brush" }); + optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document._jitterRotation = (this.props.Document._jitterRotation ? 0 : 10)), icon: "paint-brush" }); optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index ab8174ba1..cd8166309 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,12 +1,12 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, DataSym, WidthSym, HeightSym } from "../../../../new_fields/Doc"; +import { Doc, DocListCast, DataSym, WidthSym, HeightSym, Opt } from "../../../../new_fields/Doc"; import { InkField, InkData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types"; import { Utils } from "../../../../Utils"; -import { Docs, DocUtils } from "../../../documents/Documents"; +import { Docs, DocUtils, DocumentOptions } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; @@ -310,11 +310,10 @@ export class MarqueeView extends React.Component { + getCollection = (selected: Doc[], creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => { const bounds = this.Bounds; // const inkData = this.ink ? this.ink.inkData : undefined; - const creator = asTemplate ? Docs.Create.StackingDocument : Docs.Create.FreeformDocument; - const newCollection = creator(selected, { + const newCollection = (creator || Docs.Create.FreeformDocument)(selected, { x: bounds.left, y: bounds.top, _panX: 0, @@ -338,8 +337,7 @@ export class MarqueeView extends React.Component this.props.removeDocument(d)); - const newCollection = this.getCollection(selected, false); - Doc.pileup(newCollection, selected); + const newCollection = Doc.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2); this.props.addDocument(newCollection); this.props.selectDocuments([newCollection], []); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -359,7 +357,7 @@ export class MarqueeView extends React.Component { - const newCollection = this.getCollection([], false, true); + const newCollection = this.getCollection([], undefined, true); this.props.addDocument(newCollection); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 18ffc38f5..337274774 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -976,7 +976,8 @@ export namespace Doc { if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", ""); } - export function pileup(newCollection: Doc, selected: Doc[]) { + export function pileup(selected: Doc[], x: number, y: number) { + const newCollection = Docs.Create.PileDocument(selected, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true }); let w = 0, h = 0; selected.forEach((d, i) => { Doc.iconify(d); @@ -993,12 +994,10 @@ export namespace Doc { newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; newCollection._width = newCollection._height = 110; //newCollection.borderRounding = "40px"; - newCollection.jitterRotation = 10; + newCollection._jitterRotation = 10; newCollection._backgroundColor = "gray"; - - newCollection._layoutEngine = "pass"; newCollection.overflow = "visible"; - newCollection.onClick = ScriptField.MakeScript("toggleStarburst(self, this)", { self: Doc.name, this: Doc.name }); + return newCollection; } @@ -1055,28 +1054,4 @@ Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: bo return docs.length ? new List(docs) : prevValue; }); Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); }); -Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); -Scripting.addGlobal(function toggleStarburst(self: Doc, tLayout: Doc) { - if (self._layoutEngine === 'starburst') { - const defaultSize = 110; - tLayout.overflow = undefined; - self.x = NumCast(self.x) + tLayout[WidthSym]() / 2 - NumCast(tLayout._starburstPileWidth, defaultSize) / 2; - self.y = NumCast(self.y) + tLayout[HeightSym]() / 2 - NumCast(tLayout._starburstPileHeight, defaultSize) / 2; - tLayout._width = NumCast(tLayout._starburstPileWidth, defaultSize); - tLayout._height = NumCast(tLayout._starburstPileHeight, defaultSize); - self._layoutEngine = 'pass'; - } else { - const defaultSize = 25; - tLayout.overflow = 'visible'; - !tLayout._starburstRadius && (tLayout._starburstRadius = 500); - !tLayout._starburstDocScale && (tLayout._starburstDocScale = 2.5); - if (self._layoutEngine === 'pass') { - self.x = NumCast(self.x) + tLayout[WidthSym]() / 2 - defaultSize / 2; - self.y = NumCast(self.y) + tLayout[HeightSym]() / 2 - defaultSize / 2; - tLayout._starburstPileWidth = tLayout[WidthSym](); - tLayout._starburstPileHeight = tLayout[HeightSym](); - } - tLayout._width = tLayout._height = defaultSize; - self._layoutEngine = 'starburst'; - } -}); \ No newline at end of file +Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 308ae1521cbd58126d35239cfdd5a138f6fa1fe0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Apr 2020 15:40:07 -0400 Subject: got rid of focus mechanism on click. fixed shift-click to multiselect. fixed pile view interactions. added FollowLink on click menu items. --- src/client/util/DragManager.ts | 9 +++- src/client/util/ProsemirrorExampleTransfer.ts | 18 +++++-- src/client/views/ContextMenu.tsx | 9 ++++ src/client/views/TemplateMenu.tsx | 5 +- .../views/collections/CollectionPileView.tsx | 38 +++++++++++-- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 20 +++---- src/client/views/nodes/DocumentView.tsx | 63 +++++++++++++++------- src/client/views/nodes/FormattedTextBox.tsx | 4 +- src/client/views/nodes/FormattedTextBoxComment.tsx | 1 - src/client/views/nodes/LinkAnchorBox.tsx | 1 - src/client/views/pdf/Annotation.tsx | 1 - 12 files changed, 124 insertions(+), 47 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 42a78a4bf..6bb44f7d6 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -83,6 +83,7 @@ export namespace DragManager { } export let AbortDrag: () => void = emptyFunction; export type MoveFunction = (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + export type RemoveFunction = (document: Doc) => boolean; export interface DragDropDisposer { (): void; } export interface DragOptions { @@ -138,6 +139,7 @@ export namespace DragManager { userDropAction: dropActionType; embedDoc?: boolean; moveDocument?: MoveFunction; + removeDocument?: RemoveFunction; isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts } export class LinkDragData { @@ -351,12 +353,17 @@ export namespace DragManager { let lastX = downX; let lastY = downY; + let alias = "alias"; const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined; } if (e.shiftKey && CollectionDockingView.Instance && dragData.droppedDocuments.length === 1) { + !dragData.dropAction && (dragData.dropAction = alias); + if (dragData.dropAction === "move") { + dragData.removeDocument?.(dragData.draggedDocuments[0]); + } AbortDrag(); finishDrag?.(new DragCompleteEvent(true, dragData)); CollectionDockingView.Instance.StartOtherDrag({ @@ -366,7 +373,7 @@ export namespace DragManager { button: 0 }, dragData.droppedDocuments); } - //TODO: Why can't we use e.movementX and e.movementY? + alias = "move"; const moveX = e.pageX - lastX; const moveY = e.pageY - lastY; lastX = e.pageX; diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 680f48f70..356f20ce6 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -7,7 +7,7 @@ import { splitListItem, wrapInList, } from "prosemirror-schema-list"; import { EditorState, Transaction, TextSelection } from "prosemirror-state"; import { SelectionManager } from "./SelectionManager"; import { Docs } from "../documents/Documents"; -import { NumCast, BoolCast, Cast } from "../../new_fields/Types"; +import { NumCast, BoolCast, Cast, StrCast } from "../../new_fields/Types"; import { Doc } from "../../new_fields/Doc"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { Id } from "../../new_fields/FieldSymbols"; @@ -153,10 +153,16 @@ export default function buildKeymap>(schema: S, props: any const layoutDoc = props.Document; const originalDoc = layoutDoc.rootDocument || layoutDoc; if (originalDoc instanceof Doc) { + const layoutKey = StrCast(originalDoc.layoutKey); const newDoc = Docs.Create.TextDocument("", { - layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), + layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, + layoutKey, + _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x), y: NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10, _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); + if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) { + newDoc[layoutKey] = originalDoc[layoutKey]; + } FormattedTextBox.SelectOnLoad = newDoc[Id]; props.addDocument(newDoc); } @@ -171,10 +177,16 @@ export default function buildKeymap>(schema: S, props: any const layoutDoc = props.Document; const originalDoc = layoutDoc.rootDocument || layoutDoc; if (force || props.Document._singleLine) { + const layoutKey = StrCast(originalDoc.layoutKey); const newDoc = Docs.Create.TextDocument("", { - layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), + layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, + layoutKey, + _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10, y: NumCast(originalDoc.y), _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); + if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) { + newDoc[layoutKey] = originalDoc[layoutKey]; + } FormattedTextBox.SelectOnLoad = newDoc[Id]; props.addDocument(newDoc); return true; diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 4d04d4e89..5b66b63ed 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -99,6 +99,15 @@ export class ContextMenu extends React.Component { } } @action + moveAfter(item: ContextMenuProps, after: ContextMenuProps) { + if (this.findByDescription(after.description)) { + const curInd = this._items.findIndex((i) => i.description === item.description); + this._items.splice(curInd, 1); + const afterInd = this._items.findIndex((i) => i.description === after.description); + this._items.splice(afterInd + 1, 0, item); + } + } + @action setDefaultItem(prefix: string, item: (name: string) => void) { this._defaultPrefix = prefix; this._defaultItem = item; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 4c84a22ad..665ab4e41 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -14,6 +14,7 @@ import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZer import { Transform } from "../util/Transform"; import { ScriptField, ComputedField } from "../../new_fields/ScriptField"; import { Scripting } from "../util/Scripting"; +import { List } from "../../new_fields/List"; @observer class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent, template: Template) => void }> { @@ -106,8 +107,8 @@ export class TemplateMenu extends React.Component { return100 = () => 100; @computed get scriptField() { - return ScriptField.MakeScript("switchView(firstDoc, this)", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name }, - { firstDoc: this.props.docViews[0].props.Document }); + return ScriptField.MakeScript("docs.map(d => switchView(d, this))", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name }, + { docs: new List(this.props.docViews.map(dv => dv.props.Document)) }); } render() { const firstDoc = this.props.docViews[0].props.Document; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 511efe0a7..410b16ec7 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -11,6 +11,7 @@ import "./CollectionPileView.scss"; import React = require("react"); import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils"; import { SelectionManager } from "../../util/SelectionManager"; +import { UndoManager } from "../../util/UndoManager"; @observer export class CollectionPileView extends CollectionSubView(doc => doc) { @@ -34,7 +35,10 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { layoutEngine = () => this._layoutEngine; @computed get contents() { - return
+ return
; } @@ -71,9 +75,32 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { } }); + _undoBatch: UndoManager.Batch | undefined; pointerDown = (e: React.PointerEvent) => { + let dist = 0; // this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header - setupMoveUpEvents(this, e, returnFalse, emptyFunction, emptyFunction, false, false); // this sets _doubleTap + setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => { + if (this.layoutEngine() === "pass" && this.childDocs.length && this.props.isSelected(true)) { + dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]); + if (dist > 100) { + if (!this._undoBatch) { + this._undoBatch = UndoManager.StartBatch("layout pile"); + } + const doc = this.childDocs[0]; + doc.x = e.clientX; + doc.y = e.clientY; + this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc); + dist = 0; + } + } + return false; + }, () => { + this._undoBatch?.end(); + this._undoBatch = undefined; + if (!this.childDocs.length) { + this.props.ContainingCollectionView?.removeDocument(this.props.Document); + } + }, emptyFunction, false, this.layoutEngine() === "pass" && this.props.isSelected(true)); // this sets _doubleTap } onClick = (e: React.MouseEvent) => { @@ -81,10 +108,11 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { SelectionManager.DeselectAll(); this.toggleStarburst(); e.stopPropagation(); - } else if (this.layoutEngine() === "pass") { - runInAction(() => this._contentsActive = false); - setTimeout(action(() => this._contentsActive = true), 300); } + // else if (this.layoutEngine() === "pass") { + // runInAction(() => this._contentsActive = false); + // setTimeout(action(() => this._contentsActive = true), 300); + // } } render() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index f82c6d8a6..2bd37bda5 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -225,7 +225,7 @@ export class CollectionView extends Touchable { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); - this.setupViewTypes("New Perspective...", vtype => { + this.setupViewTypes("Add a Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; this.props.addDocTab(newRendition, "onRight"); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index af9d3c5be..6a3764bb7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -821,18 +821,18 @@ export class CollectionFreeFormView extends CollectionSubView { if (afterFocus?.()) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 06bd40992..f9d9ca9a1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -234,6 +234,7 @@ export class DocumentView extends DocComponent(Docu const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0); dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); dragData.dropAction = dropAction; + dragData.removeDocument = this.props.removeDocument; dragData.moveDocument = this.props.moveDocument;// this.Document.onDragStart ? undefined : this.props.moveDocument; dragData.dragDivName = this.props.dragDivName; DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.Document.onDragStart }); @@ -309,19 +310,19 @@ export class DocumentView extends DocComponent(Docu } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"); //ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click"); - } else if (this.Document.isLinkButton) { + } else if (this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); } else { if ((this.props.Document.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { - if (this.props.Document.type === DocumentType.RTF) { - DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; - DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; + // if (this.props.Document.type === DocumentType.RTF) { + // DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; + // DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; - this.props.focus(this.props.Document, false); - } - SelectionManager.SelectDoc(this, e.ctrlKey); + // this.props.focus(this.props.Document, false); + // } + SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey); } preventDefault = false; } @@ -329,7 +330,6 @@ export class DocumentView extends DocComponent(Docu preventDefault && e.preventDefault(); } } - static _focusHack: number[] = []; // bcz :this will get fixed... // follows a link - if the target is on screen, it highlights/pans to it. // if the target isn't onscreen, then it will open up the target in a tab, on the right, or in place @@ -344,11 +344,11 @@ export class DocumentView extends DocComponent(Docu finished && setTimeout(finished, 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout. return false; // we must return false here so that the zoom to the document is not reversed. If it weren't for needing to call finished(), we wouldn't need this function at all since not having it is equivalent to returning false }; - this.props.addDocTab(doc, where) && this.props.focus(doc, true, undefined, hackToCallFinishAfterFocus); // add the target and focus on it. + this.props.addDocTab(doc, where) && this.props.focus(doc, BoolCast(this.Document.followLinkZoom, true), undefined, hackToCallFinishAfterFocus); // add the target and focus on it. return where !== "inPlace"; // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target) }; // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target - this.props.focus(this.props.Document, true, 1, targetFocusAfterDocFocus); + this.props.focus(this.props.Document, BoolCast(this.Document.followLinkZoom, true), 1, targetFocusAfterDocFocus); }; await DocumentManager.Instance.FollowLink(undefined, this.props.Document, createViewFunc, shiftKey, this.props.ContainingCollectionDoc, batch.end, altKey ? true : undefined); } @@ -569,6 +569,7 @@ export class DocumentView extends DocComponent(Docu this.Document.onClick = undefined; } else { this.Document.isLinkButton = true; + this.Document.followLinkZoom = false; this.Document.followLinkLocation = undefined; } } @@ -579,10 +580,24 @@ export class DocumentView extends DocComponent(Docu this.Document.isLinkButton = false; } else { this.Document.isLinkButton = true; + this.Document.followLinkZoom = true; this.Document.followLinkLocation = "inPlace"; } } + @undoBatch + toggleFollowOnRight = (): void => { + if (this.Document.isLinkButton) { + this.Document.isLinkButton = false; + } else { + this.Document.isLinkButton = true; + this.Document.followLinkZoom = false; + const first = DocListCast(this.Document.links).find(d => d instanceof Doc); + first && (first.hidden = true); + this.Document.followLinkLocation = "onRight"; + } + } + @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { @@ -679,20 +694,27 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" })); - const existing = cm.findByDescription("Options..."); - const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; - layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); - layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); - layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); - !existing && cm.addItem({ description: "Options...", subitems: layoutItems, icon: "compass" }); - - const open = cm.findByDescription("New Perspective..."); + let open = cm.findByDescription("Add a Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); - !open && cm.addItem({ description: "New Perspective...", subitems: openItems, icon: "external-link-alt" }); + if (!open) { + open = { description: "Add a Perspective....", subitems: openItems, icon: "external-link-alt" }; + cm.addItem(open); + } + + let options = cm.findByDescription("Options..."); + const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; + optionItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); + optionItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); + optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); + optionItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); + if (!options) { + options = { description: "Options...", subitems: optionItems, icon: "compass" }; + cm.addItem(options); + } + cm.moveAfter(options, open); const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; @@ -700,6 +722,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); + onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a018f17e8..d7cfbae9f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -444,7 +444,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp changeItems.push({ description: "FreeForm", event: undoBatch(() => Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), "change view"), icon: "eye" }); !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); - const open = cm.findByDescription("New Perspective..."); + const open = cm.findByDescription("Add a Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ @@ -454,7 +454,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.props.addDocTab(alias, "onRight"); }), icon: "eye" }); - !open && cm.addItem({ description: "New Perspective...", subitems: openItems, icon: "external-link-alt" }); + !open && cm.addItem({ description: "Add a Perspective...", subitems: openItems, icon: "external-link-alt" }); } diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx index 41df5b3c1..a9f76ae8f 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/FormattedTextBoxComment.tsx @@ -88,7 +88,6 @@ export class FormattedTextBoxComment { if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); } else { - DocumentView._focusHack = []; DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); } diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index eb647d0e4..707b9d12a 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -75,7 +75,6 @@ export class LinkAnchorBox extends ViewBoxBaseComponent { - DocumentView._focusHack = []; DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, "inTab")), false); this._editing = false; }), 300 - (Date.now() - this._lastTap)); diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index eaf80d252..672d3adb8 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -98,7 +98,6 @@ class RegionAnnotation extends React.Component { else if (e.button === 0) { const annoGroup = await Cast(this.props.document.group, Doc); if (annoGroup) { - DocumentView._focusHack = []; DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation), false, undefined); e.stopPropagation(); } -- cgit v1.2.3-70-g09d2 From c6d8ac7eef3480a7e19687b066456d9d34519587 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Apr 2020 20:25:50 -0400 Subject: several fixes for performance and for working with isBackground objects. --- .../CollectionStackingViewFieldColumn.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../CollectionFreeFormLayoutEngines.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 ++++++++++++++------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 21 ++++++++++++++------- src/client/views/nodes/ImageBox.scss | 9 +-------- src/client/views/nodes/ImageBox.tsx | 8 ++++---- src/new_fields/util.ts | 2 +- 9 files changed, 39 insertions(+), 32 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 5d926b7c7..8992de9d1 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -364,7 +364,7 @@ export class CollectionStackingViewFieldColumn extends React.Component diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2bd37bda5..801704673 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -493,7 +493,7 @@ export class CollectionView extends Touchable { {!this.props.isSelected() || this.props.PanelHeight() < 100 || this.props.Document.hideFilterView ? (null) :
} - {this.filterView} + {this.facetWidth() < 10 ? (null) : this.filterView}
); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 9ca747113..9a864078a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -39,7 +39,7 @@ export interface PoolData { color?: string; transition?: string; highlight?: boolean; - replica?: string; + replica: string; pair: { layout: Doc, data?: Doc }; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6a3764bb7..a13c81a15 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -508,7 +508,7 @@ export class CollectionFreeFormView extends CollectionSubView BoolCast(this.Document.useClusters); - + @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); } + parentActive = () => this.props.active() || this.backgroundActive ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { ...this.props, @@ -879,7 +880,7 @@ export class CollectionFreeFormView extends CollectionSubView) { + childDataProvider = computedFn(function childDataProvider(this: any, doc: Doc, replica: string) { return this._layoutPoolData.get(doc[Id] + (replica || "")); }.bind(this)); @@ -975,6 +976,9 @@ export class CollectionFreeFormView extends CollectionSubView(); const engine = this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine); switch (engine) { @@ -1009,8 +1013,10 @@ export class CollectionFreeFormView extends CollectionSubView { x: number, y: number, zIndex?: number, highlight?: boolean, width: number, height: number, z: number, transition?: string, replica: string } | undefined; + dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, highlight?: boolean, width: number, height: number, z: number, transition?: string, replica: string } | undefined; x?: number; y?: number; z?: number; @@ -23,7 +23,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { jitterRotation: number; transition?: string; fitToBox?: boolean; - replica?: string; + replica: string; } @observer diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f9d9ca9a1..7ae77fc65 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -281,12 +281,12 @@ export class DocumentView extends DocComponent(Docu } } - onClick = (e: React.MouseEvent | React.PointerEvent) => { + onClick = action((e: React.MouseEvent | React.PointerEvent) => { if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { let stopPropagate = true; let preventDefault = true; - this.props.Document.isBackground === undefined && this.props.bringToFront(this.props.Document); + !this.props.Document.isBackground && this.props.bringToFront(this.props.Document); if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (!(e.nativeEvent as any).formattedHandled) { const fullScreenAlias = Doc.MakeAlias(this.props.Document); @@ -329,7 +329,7 @@ export class DocumentView extends DocComponent(Docu stopPropagate && e.stopPropagation(); preventDefault && e.preventDefault(); } - } + }); // follows a link - if the target is on screen, it highlights/pans to it. // if the target isn't onscreen, then it will open up the target in a tab, on the right, or in place @@ -347,8 +347,12 @@ export class DocumentView extends DocComponent(Docu this.props.addDocTab(doc, where) && this.props.focus(doc, BoolCast(this.Document.followLinkZoom, true), undefined, hackToCallFinishAfterFocus); // add the target and focus on it. return where !== "inPlace"; // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target) }; - // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target - this.props.focus(this.props.Document, BoolCast(this.Document.followLinkZoom, true), 1, targetFocusAfterDocFocus); + if (!this.Document.followLinkZoom) { + targetFocusAfterDocFocus(); + } else { + // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target + this.props.focus(this.props.Document, BoolCast(this.Document.followLinkZoom, true), 1, targetFocusAfterDocFocus); + } }; await DocumentManager.Instance.FollowLink(undefined, this.props.Document, createViewFunc, shiftKey, this.props.ContainingCollectionDoc, batch.end, altKey ? true : undefined); } @@ -642,6 +646,7 @@ export class DocumentView extends DocComponent(Docu const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), title: StrCast(this.props.Document.title) + ".portal" }); DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to"); } + this.Document.followLinkZoom = true; this.Document.isLinkButton = true; } @@ -1069,7 +1074,7 @@ export class DocumentView extends DocComponent(Docu const titleView = (!showTitle ? (null) :
(Docu
; } @computed get ignorePointerEvents() { - return this.props.pointerEvents === false || (this.Document.isBackground && !this.isSelected() && !SelectionManager.GetIsDragging()) || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None); + return this.props.pointerEvents === false || + (this.Document.isBackground && !this.isSelected() && !SelectionManager.GetIsDragging()) || + (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None); } @undoBatch @action diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 49425c2c2..15148d01d 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -1,5 +1,4 @@ -.imageBox, -.imageBox-dragging { +.imageBox { border-radius: inherit; width: 100%; height: 100%; @@ -11,12 +10,6 @@ } } -.imageBox-dragging { - .imageBox-fader { - pointer-events: none; - } -} - #upload-icon { position: absolute; bottom: 0; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index e189f5814..14b367868 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -360,7 +360,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url.href).filter(url => url); // access the primary layout data of the alternate documents + const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; return paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; } @@ -438,8 +439,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent [this.content]; render() { TraceMobx(); - const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging"; - return (