From 358437eeafe42e029ffe27702bde15a3fad54a3b Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 19 Jun 2019 16:17:18 -0400 Subject: working version of embedded tree view docs. --- .../views/collections/CollectionStackingView.tsx | 2 + .../views/collections/CollectionTreeView.scss | 15 ++- .../views/collections/CollectionTreeView.tsx | 132 +++++++++++++++------ src/client/views/nodes/DocumentView.tsx | 5 +- src/client/views/nodes/FormattedTextBox.tsx | 1 + 5 files changed, 109 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index f80ba0a4b..368e94a8c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -10,6 +10,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; +import { auto } from "async"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -112,6 +113,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { style={{ width: width(), height: height(), + overflow: "auto", transformOrigin: "top left", gridRowEnd: `span ${rowSpan}`, gridColumnEnd: `span 1`, diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 2d5092980..ec78fdb80 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -12,7 +12,7 @@ padding-right: 0px; background: $light-color-secondary; font-size: 13px; - overflow: scroll; + overflow: auto; ul { list-style: none; @@ -50,10 +50,12 @@ font-size: 24px; } - .collectionTreeView-keyHeader { - font-style: italic; - font-size: 8pt; - } +} +.collectionTreeView-keyHeader { + font-style: italic; + font-size: 8pt; + margin-left: 3px; + display:none; } .docContainer { @@ -74,6 +76,9 @@ } .treeViewItem-header:hover { + .collectionTreeView-keyHeader { + display:inherit; + } .treeViewItem-openRight { display: inline-block; height:13px; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d43402e7d..1eab541b3 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,9 +1,9 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, trace } from "mobx"; +import { action, observable, trace, computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from '../../../new_fields/Doc'; +import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { Document, listSpec } from '../../../new_fields/Schema'; import { BoolCast, Cast, NumCast, StrCast, PromiseValue } from '../../../new_fields/Types'; @@ -16,14 +16,18 @@ import { EditableView } from "../EditableView"; import { MainView } from '../MainView'; import { CollectionViewType } from './CollectionBaseView'; import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionSubView } from "./CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); import { Transform } from '../../util/Transform'; import { SelectionManager } from '../../util/SelectionManager'; -import { emptyFunction } from '../../../Utils'; +import { emptyFunction, returnFalse, Utils, returnOne, returnZero } from '../../../Utils'; import { List } from '../../../new_fields/List'; import { Templates } from '../Templates'; +import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { number } from 'prop-types'; +import ReactTable from 'react-table'; +import { MainOverlayTextBox } from '../MainOverlayTextBox'; export interface TreeViewProps { @@ -32,9 +36,12 @@ export interface TreeViewProps { moveDocument: DragManager.MoveFunction; dropAction: "alias" | "copy" | undefined; addDocTab: (doc: Doc, where: string) => void; + panelWidth: () => number; + panelHeight: () => number; addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; indentDocument?: () => void; ScreenToLocalTransform: () => Transform; + outerXf: () => number[]; treeViewId: string; parentKey: string; active: () => boolean; @@ -58,11 +65,13 @@ library.add(faCaretRight); class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private treedropDisposer?: DragManager.DragDropDisposer; + private _mainEle?: HTMLDivElement; protected createTreeDropTarget = (ele: HTMLDivElement) => { this.treedropDisposer && this.treedropDisposer(); if (ele) { this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } }); } + this._mainEle = ele; } @observable _isOver: boolean = false; @@ -76,7 +85,7 @@ class TreeView extends React.Component { onPointerEnter = (e: React.PointerEvent): void => { this.props.active() && (this.props.document.libraryBrush = true); - if (e.buttons === 1) { + if (e.buttons === 1 && SelectionManager.GetIsDragging()) { this._header!.current!.className = "treeViewItem-header"; document.addEventListener("pointermove", this.onDragMove, true); } @@ -166,6 +175,28 @@ class TreeView extends React.Component { let reference = React.createRef(); let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true); + let keyList: string[] = []; + let keys = Array.from(Object.keys(this.props.document)); + if (this.props.document.proto instanceof Doc) { + keys.push(...Array.from(Object.keys(this.props.document.proto))); + while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); + } + if (keys.indexOf("data") !== -1) { + keys.splice(keys.indexOf("data"), 1); + keys.splice(0, 0, "data"); + } + keys.map(key => { + let docList = Cast(this.props.document[key], listSpec(Doc)); + let doc = Cast(this.props.document[key], Doc); + if (doc instanceof Doc || (docList && (DocListCast(docList).length > 0 || key === "data"))) { + keyList.push(key); + } + }); + let headerElements = this._bulletType === BulletType.List ? (null) : [this._chosenKey].map(key => + { this._chosenKey = key; this.props.document.embed = !BoolCast(this.props.document.embed, false) })} + style={{ background: key === this._chosenKey ? "lightgray" : undefined }}> + {key} + ); let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []) : []; let openRight = dataDocs && dataDocs.indexOf(this.props.document) !== -1 ? (null) : (
@@ -182,6 +213,7 @@ class TreeView extends React.Component { {this.editableView("title")} {/* {
} */}
+ {headerElements} {openRight} ; } @@ -244,34 +276,20 @@ class TreeView extends React.Component { return true; } + docTransform = () => { + let { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.current!); + let outerXf = this.props.outerXf(); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf[0] - translateX, outerXf[1] - translateY); + let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]); + return finalXf; + } @observable _chosenKey: string = "data"; _bulletType: BulletType = BulletType.List; + + _dref = React.createRef(); render() { let bulletType = BulletType.List; let contentElement: (JSX.Element | null)[] = []; - let keys = Array.from(Object.keys(this.props.document)); - if (this.props.document.proto instanceof Doc) { - keys.push(...Array.from(Object.keys(this.props.document.proto))); - while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); - } - if (keys.indexOf("data") !== -1) { - keys.splice(keys.indexOf("data"), 1); - keys.splice(0, 0, "data"); - } - let keyList: string[] = []; - keys.map(key => { - let docList = Cast(this.props.document[key], listSpec(Doc)); - let doc = Cast(this.props.document[key], Doc); - if (doc instanceof Doc || (docList && (DocListCast(docList).length > 0 || key === "data"))) { - keyList.push(key); - } - }); - let headerElements =
{keyList.map(key => - this._chosenKey = key)} - style={{ display: "inline", marginRight: "3px", marginTop: "7px", background: key === this._chosenKey ? "lightgray" : undefined }}> - {key} - )} -
; [this._chosenKey].map(key => { let docList = Cast(this.props.document[key], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, key); @@ -280,14 +298,31 @@ class TreeView extends React.Component { if (doc instanceof Doc || (docList && (DocListCast(docList).length > 0 || key === "data"))) { if (!this._collapsed) { bulletType = BulletType.Collapsible; - contentElement.push(
    - {headerElements} -
    - {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, key, addDoc, remDoc, this.move, - this.indent, - this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active)} -
    -
); + if (this.props.document.embed) { + contentElement.push( +
+
); + } else + contentElement.push(
    +
    + {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, key, addDoc, remDoc, this.move, + this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.panelHeight)} +
    +
); } else { bulletType = BulletType.Collapsed; } @@ -315,11 +350,13 @@ class TreeView extends React.Component { add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, - indent: () => void, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => void, screenToLocalXf: () => Transform, - active: () => boolean + outerXf: () => number[], + active: () => boolean, + panelWidth: () => number, + panelHeight: () => number ) { let docList = docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized)); return docList.map((child, i) => { @@ -338,10 +375,13 @@ class TreeView extends React.Component { indentDocument={indent} deleteDoc={remove} addDocument={add} + panelWidth={panelWidth} + panelHeight={panelHeight} moveDocument={move} dropAction={dropAction} addDocTab={addDocTab} ScreenToLocalTransform={screenToLocalXf} + outerXf={outerXf} parentKey={key} active={active} />; }); @@ -351,6 +391,7 @@ class TreeView extends React.Component { @observer export class CollectionTreeView extends CollectionSubView(Document) { private treedropDisposer?: DragManager.DragDropDisposer; + private _mainEle?: HTMLDivElement; protected createTreeDropTarget = (ele: HTMLDivElement) => { if (this.treedropDisposer) { this.treedropDisposer(); @@ -358,6 +399,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { if (ele) { this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); } + this._mainEle = ele; } @action @@ -373,6 +415,10 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } + outerXf = () => { + let outerXf = Utils.GetScreenTransform(this._mainEle!); + return [outerXf.translateX, outerXf.translateY]; + } onTreeDrop = (e: React.DragEvent) => { this.onDrop(e, {}); } @@ -384,7 +430,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before); let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); let childElements = TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove, - moveDoc, emptyFunction, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active); + moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, () => 25); return (
StrCast(this.props.Document.title)} + OnFillDown={(value: string) => { + let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; + target.title = value; + let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25 }); + TreeView.loadId = doc[Id]; + doc.templates = new List([Templates.Title.Layout]); + this.props.addDocument(doc); + }} SetValue={(value: string) => { let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; target.title = value; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4992669df..f7836d947 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -72,6 +72,7 @@ export interface DocumentViewProps { ScreenToLocalTransform: () => Transform; isTopMost: boolean; ContentScaling: () => number; + useActualDimensions?: boolean; PanelWidth: () => number; PanelHeight: () => number; focus: (doc: Doc) => void; @@ -538,8 +539,8 @@ export class DocumentView extends DocComponent(Docu render() { var scaling = this.props.ContentScaling(); - var nativeWidth = this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%"; - var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; + var nativeWidth = this.props.useActualDimensions ? NumCast(this.props.Document.width) : this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%"; + var nativeHeight = this.props.useActualDimensions ? NumCast(this.props.Document.height) : BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; return (