From 22472e278c5616ba86c75ed29cd5846d0cf35ff5 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Sat, 23 Nov 2019 17:29:18 -0500 Subject: auto pen ! --- .../collectionFreeForm/CollectionFreeFormView.tsx | 52 ++++++++++++++++------ 1 file changed, 38 insertions(+), 14 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3dd655b96..03f860b32 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -26,7 +26,7 @@ import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss" import { ContextMenu } from "../../ContextMenu"; import { ContextMenuProps } from "../../ContextMenuItem"; import { InkingControl } from "../../InkingControl"; -import { CreatePolyline } from "../../InkingStroke"; +import { CreatePolyline, InkingStroke } from "../../InkingStroke"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentViewProps } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/FormattedTextBox"; @@ -282,20 +282,43 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); document.addEventListener("pointerup", this.onPointerUp); - if (InkingControl.Instance.selectedTool === InkTool.None) { + // if physically using a pen or we're in pen or highlighter mode + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) { + e.stopPropagation(); + e.preventDefault(); + let point = this.getTransform().transformPoint(e.pageX, e.pageY); + this._points.push({ x: point[0], y: point[1] }); + } + // if not using a pen and in no ink mode + else if (InkingControl.Instance.selectedTool === InkTool.None) { this._lastX = e.pageX; this._lastY = e.pageY; } + // eraser or scrubber plus anything else mode else { e.stopPropagation(); e.preventDefault(); - - if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { - let point = this.getTransform().transformPoint(e.pageX, e.pageY); - this._points.push({ x: point[0], y: point[1] }); - } } } + // if (e.button === 0 && !e.shiftKey && !e.altKey && !e.ctrlKey && this.props.active(true)) { + // document.removeEventListener("pointermove", this.onPointerMove); + // document.removeEventListener("pointerup", this.onPointerUp); + // document.addEventListener("pointermove", this.onPointerMove); + // document.addEventListener("pointerup", this.onPointerUp); + // if (InkingControl.Instance.selectedTool === InkTool.None) { + // this._lastX = e.pageX; + // this._lastY = e.pageY; + // } + // else { + // e.stopPropagation(); + // e.preventDefault(); + + // if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { + // let point = this.getTransform().transformPoint(e.pageX, e.pageY); + // this._points.push({ x: point[0], y: point[1] }); + // } + // } + // } } @action @@ -308,7 +331,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerUp = (e: PointerEvent): void => { - if (InteractionUtils.IsType(e, InteractionUtils.TOUCH) && this._points.length <= 1) return; + if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && this._points.length <= 1) return; if (this._points.length > 1) { let B = this.svgBounds; @@ -364,14 +387,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerMove = (e: PointerEvent): void => { - if (InteractionUtils.IsType(e, InteractionUtils.TOUCH)) { + if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { if (this.props.active(true)) { e.stopPropagation(); } return; } if (!e.cancelBubble) { - if (InkingControl.Instance.selectedTool === InkTool.None) { + const selectedTool = InkingControl.Instance.selectedTool; + if (selectedTool === InkTool.Highlighter || selectedTool === InkTool.Pen || InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { + let point = this.getTransform().transformPoint(e.clientX, e.clientY); + this._points.push({ x: point[0], y: point[1] }); + } + else if (selectedTool === InkTool.None) { if (this._hitCluster && this.tryDragCluster(e)) { e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers e.preventDefault(); @@ -381,10 +409,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } this.pan(e); } - else if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { - let point = this.getTransform().transformPoint(e.clientX, e.clientY); - this._points.push({ x: point[0], y: point[1] }); - } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers e.preventDefault(); } -- cgit v1.2.3-70-g09d2 From 2a84a002b06bdff969483f19390bf5a6d416d3a9 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 24 Nov 2019 23:39:44 -0500 Subject: lots of fixes for full screen image/pdf/video views. fixes to image box fade image. --- src/client/documents/Documents.ts | 3 +- .../views/collections/CollectionDockingView.tsx | 4 +- .../views/nodes/ContentFittingDocumentView.tsx | 2 +- src/client/views/nodes/ImageBox.scss | 39 +-- src/client/views/nodes/ImageBox.tsx | 33 ++- src/client/views/nodes/PDFBox.scss | 306 +++++++++++---------- src/client/views/nodes/PDFBox.tsx | 25 +- src/client/views/nodes/VideoBox.scss | 5 +- src/client/views/nodes/VideoBox.tsx | 58 ++-- src/client/views/pdf/PDFViewer.scss | 4 +- src/client/views/pdf/PDFViewer.tsx | 9 +- 11 files changed, 256 insertions(+), 232 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c5bf109a1..3f223c281 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -215,7 +215,8 @@ export namespace Docs { layout: { view: PresElementBox, dataField: data } }], [DocumentType.INK, { - layout: { view: InkingStroke, dataField: data } + layout: { view: InkingStroke, dataField: data }, + options: { backgroundColor: "transparent" } }] ]); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 75d92105b..a99688017 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -649,6 +649,7 @@ export class DockedFrameRenderer extends React.Component { return Transform.Identity(); } get previewPanelCenteringOffset() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } + get widthpercent() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } addDocTab = (doc: Doc, dataDoc: Opt, location: string) => { SelectionManager.DeselectAll(); @@ -697,7 +698,8 @@ export class DockedFrameRenderer extends React.Component { (
this._mainCont = ref} style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`, - height: this.layoutDoc && this.layoutDoc.fitWidth ? undefined : "100%" + height: this.layoutDoc && this.layoutDoc.fitWidth ? undefined : "100%", + width: this.widthpercent }}> {this.docView}
); diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 573a55710..a5f96d2de 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -82,7 +82,7 @@ export class ContentFittingDocumentView extends React.Component -
- +
+ - {fadepath === srcpath ? (null) :
} + {fadepath === srcpath ? (null) :
+
}
[this.content]; render() { - return (
+ return (
this.gotoPage(Number(e.currentTarget.value))} - style={{ left: 5, top: 5, height: "30px", width: "30px", position: "absolute", pointerEvents: "all" }} + style={{ left: 5, top: 5, height: "20px", width: "20px", position: "absolute", pointerEvents: "all" }} onClick={action(() => this._pageControls = !this._pageControls)} /> {this._pageControls ? pageBtns : (null)}
e.stopPropagation()}>
@@ -193,10 +193,15 @@ export class PDFBox extends DocAnnotatableComponent ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); } + @computed get contentScaling() { return this.props.ContentScaling(); } @computed get renderTitleBox() { - let classname = "pdfBox-cont" + (this.active() ? "-interactive" : ""); - return
-
+ let classname = "pdfBox" + (this.active() ? "-interactive" : ""); + return
+
{this.props.Document.title}
; @@ -205,7 +210,7 @@ export class PDFBox extends DocAnnotatableComponent isChildActive = (outsideReaction?: boolean) => this._isChildActive; @computed get renderPdfView() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); - return
+ return
+ return ([
{"" + Math.round(curTime)} {" " + Math.round((curTime - Math.trunc(curTime)) * 100)}
, -
+
, VideoBox._showControls ? (null) : [ -
+
, -
+
F
]]); @@ -335,30 +335,32 @@ export class VideoBox extends DocAnnotatableComponent [this.youtubeVideoId ? this.youtubeContent : this.content]; render() { - return (
- - {this.contentFunc} - +
+ + {this.contentFunc} + +
{this.uIButtons}
); } diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index ac018aa0e..4f81c6f70 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -1,5 +1,5 @@ -.pdfViewer-viewer, .pdfViewer-viewer-zoomed { +.pdfViewer, .pdfViewer-zoomed { pointer-events: all; width: 100%; height: 100%; @@ -91,7 +91,7 @@ z-index: 10; } } -.pdfViewer-viewer-zoomed { +.pdfViewer-zoomed { overflow-x: scroll; } \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f1c500391..b737ce221 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -660,6 +660,7 @@ export class PDFViewer extends DocAnnotatableComponent; } + @computed get contentScaling() { return this.props.ContentScaling(); } @computed get standinViews() { return <> {this._showCover ? this.getCoverImage() : (null)} @@ -673,16 +674,16 @@ export class PDFViewer extends DocAnnotatableComponent this._marqueeing; visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96; contentZoom = () => this._zoomed; - @computed get contentScaling() { return this.props.ContentScaling(); } render() { TraceMobx(); return !this.extensionDoc ? (null) : -
+ transform: `scale(${this.props.ContentScaling()})` + }} > {this.pdfViewerDiv} {this.overlayLayer} {this.annotationLayer} -- cgit v1.2.3-70-g09d2 From eb58759c7304bb9bdce2e1c4804a2e164eb25bcc Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 25 Nov 2019 13:59:54 -0500 Subject: fixes for docking views to reliable show their panes in tree view. fixes for search to fit available space and update properly when scrolled. fixed ymargins on stacking views with titles. --- src/client/documents/Documents.ts | 4 ++- .../views/collections/CollectionDockingView.tsx | 37 ++++++++-------------- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/search/SearchBox.scss | 4 --- src/client/views/search/SearchBox.tsx | 13 ++++---- 6 files changed, 25 insertions(+), 37 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3f223c281..dea057b93 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -524,7 +524,9 @@ export namespace Docs { } export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); + let inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); + Doc.GetProto(inst).data = new List(documents); + return inst; } export function DirectoryImportDocument(options: DocumentOptions = {}) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index a99688017..3040e74b0 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -146,8 +146,6 @@ export class CollectionDockingView extends React.Component { - let docs = Cast(this.props.Document.data, listSpec(Doc)); - if (!docs) { - return false; - } - return docs.includes(document); - } - // // Creates a vertical split on the right side of the docking view, and then adds the Document to that split // @@ -187,10 +177,6 @@ export class CollectionDockingView extends React.Component { Doc.GetProto(document).lastOpened = new DateField; - let docs = Cast(this.props.Document.data, listSpec(Doc)); - if (docs) { - docs.push(document); - } let docContentConfig = CollectionDockingView.makeDocumentConfig(document, dataDocument); if (stack === undefined) { let stack: any = this._goldenLayout.root; @@ -369,15 +351,22 @@ export class CollectionDockingView extends React.Component { + let matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); + let docids = matches?.map(m => m.replace("\"documentId\":\"", "").replace("\"", "")); + + if (docids) { + let docs = (await Promise.all(docids.map(id => DocServer.GetRefField(id)))).filter(f => f).map(f => f as Doc); + Doc.GetProto(this.props.Document)[this.props.fieldKey] = new List(docs); + } + } + @undoBatch stateChanged = () => { - let docs = Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc)); - CollectionDockingView.Instance._removedDocs.map(theDoc => - docs && docs.indexOf(theDoc) !== -1 && - docs.splice(docs.indexOf(theDoc), 1)); - CollectionDockingView.Instance._removedDocs.length = 0; var json = JSON.stringify(this._goldenLayout.toConfig()); this.props.Document.dockingConfig = json; + this.updateDataField(json); + if (this.undohack && !this.hack) { this.undohack.end(); this.undohack = undefined; @@ -704,4 +693,4 @@ export class DockedFrameRenderer extends React.Component { {this.docView}
); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index be3bfca0a..7d83d5ff3 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -40,7 +40,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); } @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } - @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } + @computed get yMargin() { return Math.max(this.props.Document.showTitle ? 30 : 0, NumCast(this.props.Document.yMargin, 2 * this.gridGap)); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); } @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 39a68f51e..8486c0f34 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -658,7 +658,7 @@ export class DocumentView extends DocComponent(Docu let oldPoint2 = this.prevPoints.get(pt2.identifier); let pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!); if (pinching !== 0) { - let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX)) + let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX)); this.props.Document.width = newWidth; } } diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index bc11604a5..4eb992d36 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -69,11 +69,7 @@ top: 300px; display: flex; flex-direction: column; - // height: 560px; height: 100%; - // overflow: hidden; - // overflow-y: auto; - max-height: 560px; overflow: hidden; overflow-y: auto; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 899a35f48..5c1bd8ef9 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -145,6 +145,7 @@ export class SearchBox extends React.Component { } + private NumResults = 25; private lockPromise?: Promise; getResults = async (query: string) => { if (this.lockPromise) { @@ -152,7 +153,7 @@ export class SearchBox extends React.Component { } this.lockPromise = new Promise(async res => { while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) { - this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: 10, hl: true, "hl.fl": "*" }).then(action(async (res: SearchUtil.DocSearchResult) => { + this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*" }).then(action(async (res: SearchUtil.DocSearchResult) => { // happens at the beginning if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { @@ -186,7 +187,7 @@ export class SearchBox extends React.Component { this._curRequest = undefined; })); - this._maxSearchIndex += 10; + this._maxSearchIndex += this.NumResults; await this._curRequest; } @@ -267,9 +268,9 @@ export class SearchBox extends React.Component { @action resultsScrolled = (e?: React.UIEvent) => { let scrollY = e ? e.currentTarget.scrollTop : this.resultsRef.current ? this.resultsRef.current.scrollTop : 0; - let buffer = 4; - let startIndex = Math.floor(Math.max(0, scrollY / 70 - buffer)); - let endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (560 / 70) + buffer)); + let itemHght = 53; + let startIndex = Math.floor(Math.max(0, scrollY / itemHght)); + let endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this.resultsRef.current!.getBoundingClientRect().height / itemHght))); this._endIndex = endIndex === -1 ? 12 : endIndex; @@ -353,7 +354,7 @@ export class SearchBox extends React.Component {
)}
{this._visibleElements}
-- cgit v1.2.3-70-g09d2 From bbf482ed6446899bd29e005184ecc779470658c7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 25 Nov 2019 15:12:55 -0500 Subject: title template fixes for tree/stacking views. --- src/client/views/collections/CollectionStackingView.tsx | 6 ++++-- src/client/views/collections/CollectionTreeView.tsx | 13 ++++++++----- src/client/views/collections/CollectionView.tsx | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 7d83d5ff3..04f57df67 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -41,6 +41,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return Math.max(this.props.Document.showTitle ? 30 : 0, NumCast(this.props.Document.yMargin, 2 * this.gridGap)); } + @computed get titleSpacing() { return this.props.Document.showTitle ? Math.max(0, NumCast(this.props.Document.yMargin, 2 * this.gridGap) - this.gridGap) : 0; } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); } @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } @@ -229,7 +230,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } @computed get columnDragger() { - return
+ return
; } @@ -317,7 +319,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); return this.props.ScreenToLocalTransform(). - translate(offset[0], offset[1] + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)). + translate(offset[0], offset[1] + (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0)). scale(NumCast(doc.width, 1) / this.columnWidth); } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8b993820b..261354ba8 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -43,6 +43,7 @@ export interface TreeViewProps { pinToPres: (document: Doc) => void; panelWidth: () => number; panelHeight: () => number; + ChromeHeight: undefined | (() => number); addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; indentDocument?: () => void; ScreenToLocalTransform: () => Transform; @@ -233,8 +234,8 @@ class TreeView extends React.Component { docTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.current!); let outerXf = this.props.outerXf(); - let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); - let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY ); + let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]+ (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0)); return finalXf; } docWidth = () => { @@ -272,7 +273,7 @@ class TreeView extends React.Component { contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents), this.props.treeViewId, doc, undefined, key, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, - this.props.panelWidth, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen, + this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen, [...this.props.renderedIds, doc[Id]]); } else { contentElement = { TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document), this.templateDataDoc, expandKey, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, - this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen, + this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen, [...this.props.renderedIds, this.props.document[Id]])} ; } else if (this.treeViewExpandedView === "fields") { @@ -414,6 +415,7 @@ class TreeView extends React.Component { outerXf: () => { translateX: number, translateY: number }, active: (outsideReaction?: boolean) => boolean, panelWidth: () => number, + ChromeHeight: undefined| (() => number), renderDepth: number, showHeaderFields: () => boolean, preventTreeViewOpen: boolean, @@ -487,6 +489,7 @@ class TreeView extends React.Component { addDocument={addDocument} panelWidth={rowWidth} panelHeight={rowHeight} + ChromeHeight={ChromeHeight} moveDocument={move} dropAction={dropAction} addDocTab={addDocTab} @@ -591,7 +594,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { { TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, - this.outerXf, this.props.active, this.props.PanelWidth, this.props.renderDepth, () => !this.props.Document.hideHeaderFields, + this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => !this.props.Document.hideHeaderFields, BoolCast(this.props.Document.preventTreeViewOpen), []) } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8387e95df..4c49054d2 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -111,7 +111,7 @@ export class CollectionView extends Touchable { componentWillUnmount = () => this._reactionDisposer && this._reactionDisposer(); // bcz: Argh? What's the height of the collection chromes?? - chromeHeight = () => (this.props.ChromeHeight ? this.props.ChromeHeight() : 0) + (this.props.Document.chromeStatus === "enabled" ? -60 : 0); + chromeHeight = () => (this.props.Document.chromeStatus === "enabled" ? -60 : 0); active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0; -- cgit v1.2.3-70-g09d2 From ef4093854ac9e3b2dadc63ac183792fa49d98f7b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 25 Nov 2019 16:21:26 -0500 Subject: cleanup of stacking/masonry and fix so that masonry layout updates interactive as docs are resized. --- .../collections/CollectionMasonryViewFieldRow.tsx | 129 ++++++++++----------- .../views/collections/CollectionStackingView.scss | 5 +- .../views/collections/CollectionStackingView.tsx | 5 +- 3 files changed, 69 insertions(+), 70 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 52ebfafd3..df4b00b3a 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faPalette } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable } from "mobx"; +import { action, observable, computed } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; import { Doc } from "../../../new_fields/Doc"; @@ -20,7 +20,6 @@ import { anchorPoints, Flyout } from "../DocumentDecorations"; import { EditableView } from "../EditableView"; import { CollectionStackingView } from "./CollectionStackingView"; import "./CollectionStackingView.scss"; -import { undo } from "prosemirror-history"; library.add(faPalette); @@ -258,12 +257,44 @@ export class CollectionMasonryViewFieldRow extends React.Component "", + SetValue: this.addDocument, + contents: "+ NEW", + HeadingObject: this.props.headingObject, + HeadingsHack: this._headingsHack, + toggle: this.toggleVisibility, + color: this._color + }; + return collapsed ? (null) : +
+
list + ` ${this.props.parent.columnWidth}px`, ""), + }}> + {this.props.parent.children(this.props.docList)} + {this.props.parent.columnDragger} +
+ {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? +
+ +
: null + } +
; + } + + @computed get headingView() { let heading = this._heading; - let style = this.props.parent; + let key = StrCast(this.props.parent.props.Document.sectionFilter); let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`; let headerEditableViewProps = { GetValue: () => evContents, @@ -275,30 +306,17 @@ export class CollectionMasonryViewFieldRow extends React.Component "", - SetValue: this.addDocument, - contents: "+ NEW", - HeadingObject: this.props.headingObject, - HeadingsHack: this._headingsHack, - toggle: this.toggleVisibility, - color: this._color - }; - let headingView = this.props.parent.props.Document.miniHeaders ? -
- {} + return this.props.parent.props.Document.miniHeaders ? +
+
: - this.props.headingObject ? + !this.props.headingObject ? (null) :
- {} + style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey", }}> + {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
@@ -321,47 +339,26 @@ export class CollectionMasonryViewFieldRow extends React.Component }
-
: (null); +
; + } + render() { const background = this._background; //to account for observables in Measure - const collapsed = this._collapsed; - let chromeStatus = this.props.parent.props.Document.chromeStatus; - return ( - - {({ measureRef }) => { - return
-
- {headingView} - {collapsed ? (null) : - < div style={{ position: "relative" }}> -
list + ` ${this.props.parent.columnWidth}px`, ""), - }}> - {this.props.parent.children(this.props.docList)} - {this.props.parent.columnDragger} -
- {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? -
- -
: null - } -
- } -
-
; - }} - - ); + let contentlayout = this.contentLayout; + let headingview = this.headingView; + return + {({ measureRef }) => { + return
+
+ {headingview} + {contentlayout} +
+
; + }} +
; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 29178b909..e1577cfee 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -97,6 +97,7 @@ .collectionStackingView-columnDoc { display: inline-block; + margin: auto; } .collectionStackingView-masonryDoc { @@ -177,7 +178,9 @@ .collectionStackingView-sectionHeader-subCont { outline: none; border: 0px; - color: $light-color; + color: $light-color; + width: 100%; + color: grey; letter-spacing: 2px; font-size: 75%; transition: transform 0.2s; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 04f57df67..e564f1193 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -41,7 +41,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return Math.max(this.props.Document.showTitle ? 30 : 0, NumCast(this.props.Document.yMargin, 2 * this.gridGap)); } - @computed get titleSpacing() { return this.props.Document.showTitle ? Math.max(0, NumCast(this.props.Document.yMargin, 2 * this.gridGap) - this.gridGap) : 0; } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); } @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } @@ -65,7 +64,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let dxf = () => this.getDocTransform(layoutDoc, dref.current!); this._docXfs.push({ dxf: dxf, width: width, height: height }); let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); - let style = this.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; + let style = this.isStackingView ? { width: width(), marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; return
{this.getDisplayDoc(pair.layout || d, pair.data, dxf, width)}
; @@ -231,7 +230,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get columnDragger() { return
+ style={{ cursor: this._cursor, left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }} >
; } -- cgit v1.2.3-70-g09d2 From 4cf3b0a4673a00f0e1de107b29a0c0b658266f46 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 26 Nov 2019 13:26:34 -0500 Subject: fixed tree view sorting (a little) and kept title box editable after tabbing. --- .../views/collections/CollectionTreeView.scss | 3 + .../views/collections/CollectionTreeView.tsx | 72 +++++++++++++++------- .../views/collections/CollectionViewChromes.tsx | 15 +++-- .../CollectionFreeFormLinkView.tsx | 15 +++-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 9 +-- 6 files changed, 74 insertions(+), 42 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 7d0c900a6..8b12395a7 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -114,6 +114,9 @@ .treeViewItem-header { border: transparent 1px solid; display: flex; + .editableView-container-editing-oneLine { + min-width: 15px; + } } .treeViewItem-header-above { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 261354ba8..a21bc6c14 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,7 +1,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faExpand, faMinus, faPlus, faTrash, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from "mobx"; +import { action, computed, observable, trace, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; @@ -82,10 +82,11 @@ class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); + get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = c; } - @computed get treeViewOpen() { return (BoolCast(this.props.document.treeViewOpen) && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; } + @computed get treeViewOpen() { trace(); return (this.props.document.treeViewOpen && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; } @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); } @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; } @@ -110,7 +111,7 @@ class TreeView extends React.Component { return this.props.dataDoc; } @computed get boundsOfCollectionDocument() { - return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 ? undefined : + return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 || !DocListCast(this.props.document[this.fieldKey]).length ? undefined : Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey])); } @@ -158,22 +159,30 @@ class TreeView extends React.Component { editableView = (key: string, style?: string) => ( StrCast(this.props.document[key])} SetValue={undoBatch((value: string) => Doc.SetInPlace(this.props.document, key, value, false) || true)} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.props.document, key, value, false); - let doc = this.props.document.layoutCustom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.layoutCustom)) : undefined; - if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); + let layoutDoc = this.props.document.layoutCustom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.layoutCustom)) : undefined; + let doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; return this.props.addDocument(doc); })} - OnTab={() => { TreeView.loadId = ""; this.props.indentDocument && this.props.indentDocument(); }} + OnTab={undoBatch(() => { + TreeView.loadId = this.dataDoc[Id]; + this.props.indentDocument?.(); + setTimeout(() => { // unsetting/setting brushing for this doc will recreate & refocus this editableView after all other treeview changes have been made to the Dom (which may remove focus from this document). + Doc.UnBrushDoc(this.props.document); + Doc.BrushDoc(this.props.document); + TreeView.loadId = ""; + }, 0); + })} />) onWorkspaceContextMenu = (e: React.MouseEvent): void => { @@ -207,7 +216,7 @@ class TreeView extends React.Component { let rect = this._header!.current!.getBoundingClientRect(); let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); let before = x[1] < bounds[1]; - let inside = x[0] > bounds[0] + 75 || (!before && this.treeViewOpen); + let inside = x[0] > bounds[0] + 75 || (!before && this.treeViewOpen && DocListCast(this.dataDoc[this.fieldKey]).length); if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.document; @@ -234,8 +243,8 @@ class TreeView extends React.Component { docTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.current!); let outerXf = this.props.outerXf(); - let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY ); - let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]+ (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0)); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0)); return finalXf; } docWidth = () => { @@ -258,8 +267,10 @@ class TreeView extends React.Component { })()); } - expandedField = (doc: Doc) => { + @computed get expandedField() { + trace(); let ids: { [key: string]: string } = {}; + let doc = this.props.document; doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); let rows: JSX.Element[] = []; @@ -296,6 +307,7 @@ class TreeView extends React.Component { noOverlays = (doc: Doc) => ({ title: "", caption: "" }); @computed get renderContent() { + trace(); const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined; if (expandKey !== undefined) { let remDoc = (doc: Doc) => this.remove(doc, expandKey); @@ -311,7 +323,7 @@ class TreeView extends React.Component { ; } else if (this.treeViewExpandedView === "fields") { return
    - {this.expandedField(this.props.document)} + {this.expandedField}
; } else { let layoutDoc = Doc.Layout(this.props.document); @@ -342,6 +354,7 @@ class TreeView extends React.Component { @computed get renderBullet() { + trace(); return
{ this.treeViewOpen = !this.treeViewOpen; e.stopPropagation(); })} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}> {}
; @@ -387,6 +400,7 @@ class TreeView extends React.Component { } render() { + trace(); return
  • @@ -400,7 +414,7 @@ class TreeView extends React.Component {
    ; } public static GetChildElements( - docs: Doc[], + childDocs: Doc[], treeViewId: string, containingCollection: Doc, dataDoc: Doc | undefined, @@ -415,7 +429,7 @@ class TreeView extends React.Component { outerXf: () => { translateX: number, translateY: number }, active: (outsideReaction?: boolean) => boolean, panelWidth: () => number, - ChromeHeight: undefined| (() => number), + ChromeHeight: undefined | (() => number), renderDepth: number, showHeaderFields: () => boolean, preventTreeViewOpen: boolean, @@ -423,12 +437,27 @@ class TreeView extends React.Component { ) { const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField); if (viewSpecScript) { - docs = docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); + childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - let ascending = Cast(containingCollection.sortAscending, "boolean", null); + let docs = childDocs.slice(); + let dataExtension = containingCollection[key + "_ext"] as Doc; + let ascending = dataExtension && BoolCast(dataExtension.sortAscending, null); if (ascending !== undefined) { - docs.sort(function (a, b): 1 | -1 { + + let sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => { + var reN = /[0-9]*$/; + var aA = a.replace(reN, ""); // get rid of trailing numbers + var bA = b.replace(reN, ""); + if (aA === bA) { // if header string matches, then compare numbers numerically + var aN = parseInt(a.match(reN)![0], 10); + var bN = parseInt(b.match(reN)![0], 10); + return aN === bN ? 0 : aN > bN ? 1 : -1; + } else { + return aA > bA ? 1 : -1; + } + } + docs.sort(function (a, b): 0 | 1 | -1 { let descA = ascending ? b : a; let descB = ascending ? a : b; let first = descA.title; @@ -438,7 +467,7 @@ class TreeView extends React.Component { return (first - second) > 0 ? 1 : -1; } if (typeof first === 'string' && typeof second === 'string') { - return first > second ? 1 : -1; + return sortAlphaNum(first, second); } if (typeof first === 'boolean' && typeof second === 'boolean') { // if (first === second) { // bugfixing?: otherwise, the list "flickers" because the list is resorted during every load @@ -565,6 +594,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } render() { + trace(); let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, false, false, false); let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); @@ -584,8 +614,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { SetValue={undoBatch((value: string) => Doc.SetInPlace(this.dataDoc, "title", value, false) || true)} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.dataDoc, "title", value, false); - let doc = this.props.Document.layoutCustom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.layoutCustom)) : undefined; - if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); + let layoutDoc = this.props.Document.layoutCustom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.layoutCustom)) : undefined; + let doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, false); })} /> diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index cfc6c2a3f..06fca7c38 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -624,12 +624,19 @@ export class CollectionSchemaViewChrome extends React.Component { - @computed private get descending() { return Cast(this.props.CollectionView.props.Document.sortAscending, "boolean", null); } + get dataExtension() { + return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "_ext"] as Doc; + } + @computed private get descending() { + return this.dataExtension && Cast(this.dataExtension.sortAscending, "boolean", null); + } @action toggleSort = () => { - if (this.props.CollectionView.props.Document.sortAscending) this.props.CollectionView.props.Document.sortAscending = undefined; - else if (this.props.CollectionView.props.Document.sortAscending === undefined) this.props.CollectionView.props.Document.sortAscending = false; - else this.props.CollectionView.props.Document.sortAscending = true; + if (this.dataExtension) { + if (this.dataExtension.sortAscending) this.dataExtension.sortAscending = undefined; + else if (this.dataExtension.sortAscending === undefined) this.dataExtension.sortAscending = false; + else this.dataExtension.sortAscending = true; + } } render() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 73b45edc6..b00728079 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -6,8 +6,9 @@ import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); import { DocumentType } from "../../../documents/DocumentTypes"; -import { observable, action, reaction, IReactionDisposer } from "mobx"; +import { observable, action, reaction, IReactionDisposer, trace } from "mobx"; import { StrCast, Cast } from "../../../../new_fields/Types"; +import { TraceMobx } from "../../../../new_fields/util"; export interface CollectionFreeFormLinkViewProps { A: DocumentView; @@ -17,14 +18,14 @@ export interface CollectionFreeFormLinkViewProps { @observer export class CollectionFreeFormLinkView extends React.Component { - @observable _opacity: number = 1; - @observable _update: number = 0; + @observable _opacity: number = 0; _anchorDisposer: IReactionDisposer | undefined; @action componentDidMount() { - setTimeout(action(() => this._opacity = 0.05), 750); this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform()], - () => { + action(() => { + setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() + setTimeout(action(() => this._opacity = 0.05), 750); // this will unhighlight the link line. let acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : []; let bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : []; let adiv = (acont.length ? acont[0] : this.props.A.ContentDiv!); @@ -45,8 +46,7 @@ export class CollectionFreeFormLinkView extends React.Component(Docu let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc.viewType !== CollectionViewType.Linear; return
    { - console.log("Brush" + this.props.Document.title); - Doc.BrushDoc(this.props.Document); - }} onPointerLeave={e => { - console.log("UnBrush" + this.props.Document.title); - Doc.UnBrushDoc(this.props.Document); - - }} + onPointerEnter={e => Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)} style={{ transition: this.Document.isAnimating ? ".5s linear" : StrCast(this.Document.transition), pointerEvents: this.ignorePointerEvents ? "none" : "all", -- cgit v1.2.3-70-g09d2 From 6cd6e035fc67812afd7a40f8abd0f07f8874f04a Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 26 Nov 2019 14:34:41 -0500 Subject: fixes for tree view drag drop with images. --- src/client/views/EditableView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 62 +++++++++++++--------- src/client/views/nodes/ImageBox.scss | 25 ++++----- src/client/views/nodes/ImageBox.tsx | 59 ++++++++++---------- 4 files changed, 79 insertions(+), 71 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 8e86f58ee..f78b61892 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -21,7 +21,7 @@ export interface EditableProps { OnFillDown?(value: string): void; - OnTab?(): void; + OnTab?(shift?: boolean): void; /** * The contents to render when not editing @@ -79,7 +79,7 @@ export class EditableView extends React.Component { if (e.key === "Tab") { e.stopPropagation(); this.finalizeEdit(e.currentTarget.value, e.shiftKey); - this.props.OnTab && this.props.OnTab(); + this.props.OnTab && this.props.OnTab(e.shiftKey); } else if (e.key === "Enter") { e.stopPropagation(); if (!e.ctrlKey) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a21bc6c14..42cdd1455 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,7 +1,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faExpand, faMinus, faPlus, faTrash, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, trace, runInAction } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; @@ -34,6 +34,7 @@ export interface TreeViewProps { document: Doc; dataDoc?: Doc; containingCollection: Doc; + prevSibling?: Doc; renderDepth: number; deleteDoc: (doc: Doc) => boolean; ruleProvider: Doc | undefined; @@ -46,12 +47,13 @@ export interface TreeViewProps { ChromeHeight: undefined | (() => number); addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; indentDocument?: () => void; + outdentDocument?: () => void; ScreenToLocalTransform: () => Transform; outerXf: () => { translateX: number, translateY: number }; treeViewId: string; parentKey: string; active: (outsideReaction?: boolean) => boolean; - showHeaderFields: () => boolean; + hideHeaderFields: () => boolean; preventTreeViewOpen: boolean; renderedIds: string[]; } @@ -82,11 +84,13 @@ class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); + get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive + get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = c; } - @computed get treeViewOpen() { trace(); return (this.props.document.treeViewOpen && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; } + @computed get treeViewOpen() { return (this.props.document.treeViewOpen && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; } @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); } @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; } @@ -145,11 +149,10 @@ class TreeView extends React.Component { } onDragMove = (e: PointerEvent): void => { Doc.UnBrushDoc(this.dataDoc); - let x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); + let pt = [e.clientX, e.clientY] let rect = this._header!.current!.getBoundingClientRect(); - let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); - let before = x[1] < bounds[1]; - let inside = x[0] > bounds[0] + 75; + let before = pt[1] < rect.top + rect.height / 2; + let inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && DocListCast(this.dataDoc[this.fieldKey]).length); this._header!.current!.className = "treeViewItem-header"; if (inside) this._header!.current!.className += " treeViewItem-header-inside"; else if (before) this._header!.current!.className += " treeViewItem-header-above"; @@ -174,9 +177,9 @@ class TreeView extends React.Component { TreeView.loadId = doc[Id]; return this.props.addDocument(doc); })} - OnTab={undoBatch(() => { + OnTab={undoBatch((shift?: boolean) => { TreeView.loadId = this.dataDoc[Id]; - this.props.indentDocument?.(); + shift ? this.props.outdentDocument?.() : this.props.indentDocument?.(); setTimeout(() => { // unsetting/setting brushing for this doc will recreate & refocus this editableView after all other treeview changes have been made to the Dom (which may remove focus from this document). Doc.UnBrushDoc(this.props.document); Doc.BrushDoc(this.props.document); @@ -212,11 +215,10 @@ class TreeView extends React.Component { @undoBatch treeDrop = (e: Event, de: DragManager.DropEvent) => { - let x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + let pt = [de.x, de.y]; let rect = this._header!.current!.getBoundingClientRect(); - let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); - let before = x[1] < bounds[1]; - let inside = x[0] > bounds[0] + 75 || (!before && this.treeViewOpen && DocListCast(this.dataDoc[this.fieldKey]).length); + let before = pt[1] < rect.top + rect.height / 2; + let inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && DocListCast(this.dataDoc[this.fieldKey]).length); if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.document; @@ -268,7 +270,6 @@ class TreeView extends React.Component { } @computed get expandedField() { - trace(); let ids: { [key: string]: string } = {}; let doc = this.props.document; doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); @@ -282,9 +283,9 @@ class TreeView extends React.Component { let remDoc = (doc: Doc) => this.remove(doc, key); let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true); contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : - DocListCast(contents), this.props.treeViewId, doc, undefined, key, addDoc, remDoc, this.move, + DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, - this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen, + this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.hideHeaderFields, this.props.preventTreeViewOpen, [...this.props.renderedIds, doc[Id]]); } else { contentElement = { noOverlays = (doc: Doc) => ({ title: "", caption: "" }); @computed get renderContent() { - trace(); const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined; if (expandKey !== undefined) { let remDoc = (doc: Doc) => this.remove(doc, expandKey); @@ -316,9 +316,9 @@ class TreeView extends React.Component { return
      {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document), - this.templateDataDoc, expandKey, addDoc, remDoc, this.move, + this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, - this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen, + this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.hideHeaderFields, this.props.preventTreeViewOpen, [...this.props.renderedIds, this.props.document[Id]])}
    ; } else if (this.treeViewExpandedView === "fields") { @@ -354,7 +354,6 @@ class TreeView extends React.Component { @computed get renderBullet() { - trace(); return
    { this.treeViewOpen = !this.treeViewOpen; e.stopPropagation(); })} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}> {}
    ; @@ -394,13 +393,12 @@ class TreeView extends React.Component { }} > {this.editableView("title")}
    - {this.props.showHeaderFields() ? headerElements : (null)} + {this.props.hideHeaderFields() ? (null) : headerElements} {openRight} ; } render() { - trace(); return
  • @@ -419,6 +417,8 @@ class TreeView extends React.Component { containingCollection: Doc, dataDoc: Doc | undefined, key: string, + parentCollectionDoc: Doc | undefined, + parentPrevSibling: Doc | undefined, add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean, remove: ((doc: Doc) => boolean), move: DragManager.MoveFunction, @@ -431,7 +431,7 @@ class TreeView extends React.Component { panelWidth: () => number, ChromeHeight: undefined | (() => number), renderDepth: number, - showHeaderFields: () => boolean, + hideHeaderFields: () => boolean, preventTreeViewOpen: boolean, renderedIds: string[] ) { @@ -497,6 +497,15 @@ class TreeView extends React.Component { } } }; + let outdent = !parentCollectionDoc ? undefined : () => { + if (StrCast(parentCollectionDoc.layout).indexOf("fieldKey") !== -1) { + let fieldKeysub = StrCast(parentCollectionDoc.layout).split("fieldKey")[1]; + let fieldKey = fieldKeysub.split("\"")[1]; + Doc.AddDocToList(parentCollectionDoc, fieldKey, child, parentPrevSibling, false); + parentCollectionDoc.treeViewOpen = true; + remove(child); + } + }; let addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => { return add(doc, relativeTo ? relativeTo : docs[i], before !== undefined ? before : false); }; @@ -509,10 +518,12 @@ class TreeView extends React.Component { document={pair.layout} dataDoc={pair.data} containingCollection={containingCollection} + prevSibling={docs[i]} treeViewId={treeViewId} ruleProvider={containingCollection.isRuleProvider && pair.layout.type !== DocumentType.TEXT ? containingCollection : containingCollection.ruleProvider as Doc} key={child[Id]} indentDocument={indent} + outdentDocument={outdent} renderDepth={renderDepth} deleteDoc={remove} addDocument={addDocument} @@ -527,7 +538,7 @@ class TreeView extends React.Component { outerXf={outerXf} parentKey={key} active={active} - showHeaderFields={showHeaderFields} + hideHeaderFields={hideHeaderFields} preventTreeViewOpen={preventTreeViewOpen} renderedIds={renderedIds} />; }); @@ -594,7 +605,6 @@ export class CollectionTreeView extends CollectionSubView(Document) { } render() { - trace(); let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, false, false, false); let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); @@ -622,7 +632,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { {this.props.Document.allowClear ? this.renderClearButton : (null)}
      { - TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove, + TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => !this.props.Document.hideHeaderFields, BoolCast(this.props.Document.preventTreeViewOpen), []) diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index f28ca98f7..96ea4d0d6 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -7,7 +7,7 @@ transform-origin: top left; } -.imageBox-cont, .imageBox-cont-interactive { +.imageBox-cont, .imageBox-cont-dragging { padding: 0vw; position: absolute; text-align: center; @@ -17,10 +17,20 @@ max-height: 100%; pointer-events: none; background:transparent; + img { + height: auto; + width: 100%; + pointer-events: all; + } + .imageBox-fader { + pointer-events: all; + } } -.imageBox-fader { - pointer-events: all; +.imageBox-cont-dragging { + .imageBox-fader { + pointer-events: none; + } } .imageBox-dot { @@ -33,15 +43,6 @@ background: gray; } -.imageBox-cont img { - height: auto; - width: 100%; -} - -.imageBox-cont-interactive img { - height: auto; - width: 100%; -} #google-photos { transition: all 0.5s ease 0s; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 323b05a5a..bf82da281 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -28,6 +28,7 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { TraceMobx } from '../../../new_fields/util'; +import { SelectionManager } from '../../util/SelectionManager'; var requestImageSize = require('../../util/request-image-size'); var path = require('path'); const { Howl } = require('howler'); @@ -292,7 +293,7 @@ export class ImageBox extends DocAnnotatableComponent -
      - +
      + + {fadepath === srcpath ? (null) :
      + - {fadepath === srcpath ? (null) :
      -
      } -
      -
      - -
      - {this.considerGooglePhotosLink()} - -
      ); + onError={this.onError} />
      } +
    +
    + +
    + {this.considerGooglePhotosLink()} + +
  • ; } contentFunc = () => [this.content]; -- cgit v1.2.3-70-g09d2