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. --- src/client/views/nodes/DocumentView.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') 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 (
Date: Wed, 19 Jun 2019 17:36:52 -0400 Subject: Added basic keyboard controls to context menu --- src/client/views/ContextMenu.tsx | 40 ++++++++++++++++++++++++++++---- src/client/views/ContextMenuItem.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 41 +++++++++++++++++---------------- src/client/views/nodes/IconBox.tsx | 6 ++--- 4 files changed, 61 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 33de57cfa..59a0de2a0 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -14,7 +14,7 @@ library.add(faCircle); export class ContextMenu extends React.Component { static Instance: ContextMenu; - @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault(), icon: "smile" }]; + @observable private _items: Array = []; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable private _display: boolean = false; @@ -109,6 +109,10 @@ export class ContextMenu extends React.Component { return flattenItems(this._items, name => [name]); } + @computed get flatItems(): OriginalMenuProps[] { + return this.filteredItems.filter(item => !Array.isArray(item)) as OriginalMenuProps[]; + } + @computed get filteredViews() { const createGroupHeader = (contents: any) => { return ( @@ -123,7 +127,7 @@ export class ContextMenu extends React.Component { if (Array.isArray(value)) { return createGroupHeader(value.join(" -> ")); } else { - return createItem(value, ++itemIndex === this.selectedIndex); + return createItem(value, itemIndex++ === this.selectedIndex); } }); } @@ -148,18 +152,44 @@ export class ContextMenu extends React.Component { - + {this.menuItems}
); } + @action + onKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "ArrowDown") { + if (this.selectedIndex < this.flatItems.length - 1) { + this.selectedIndex++; + } + e.preventDefault(); + } else if (e.key === "ArrowUp") { + if (this.selectedIndex > 0) { + this.selectedIndex--; + } + e.preventDefault(); + } else if (e.key === "Enter") { + const item = this.flatItems[this.selectedIndex]; + item.event(); + this.closeMenu(); + } + } + @action onChange = (e: React.ChangeEvent) => { this._searchString = e.target.value; - if (this._searchString && this.selectedIndex === -1) { - this.selectedIndex = 0; + if (!this._searchString) { + this.selectedIndex = -1; + } + else { + if (this.selectedIndex === -1) { + this.selectedIndex = 0; + } else { + this.selectedIndex = Math.min(this.flatItems.length - 1, this.selectedIndex); + } } } } \ No newline at end of file diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index ebcac7428..9bbb97d7e 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -9,7 +9,7 @@ library.add(faAngleRight); export interface OriginalMenuProps { description: string; - event: (e: React.MouseEvent) => void; + event: () => void; icon?: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } @@ -37,7 +37,7 @@ export class ContextMenuItem extends React.Component) => { if ("event" in this.props) { - this.props.event(e); + this.props.event(); this.props.closeMenu && this.props.closeMenu(); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f7836d947..2062fe1b5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faUnlock, faLock, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faShare, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; +import * as fa from '@fortawesome/free-solid-svg-icons'; import { action, computed, IReactionDisposer, reaction, trace, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; @@ -34,23 +34,24 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { RouteStore } from '../../../server/RouteStore'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? -library.add(faTrash); -library.add(faShare); -library.add(faExpandArrowsAlt); -library.add(faCompressArrowsAlt); -library.add(faLayerGroup); -library.add(faAlignCenter); -library.add(faCaretSquareRight); -library.add(faSquare); -library.add(faConciergeBell); -library.add(faFolder); -library.add(faMapPin); -library.add(faLink); -library.add(faFingerprint); -library.add(faCrosshairs); -library.add(faDesktop); -library.add(faUnlock); -library.add(faLock); +library.add(fa.faTrash); +library.add(fa.faShare); +library.add(fa.faExpandArrowsAlt); +library.add(fa.faCompressArrowsAlt); +library.add(fa.faLayerGroup); +library.add(fa.faExternalLinkAlt); +library.add(fa.faAlignCenter); +library.add(fa.faCaretSquareRight); +library.add(fa.faSquare); +library.add(fa.faConciergeBell); +library.add(fa.faFolder); +library.add(fa.faMapPin); +library.add(fa.faLink); +library.add(fa.faFingerprint); +library.add(fa.faCrosshairs); +library.add(fa.faDesktop); +library.add(fa.faUnlock); +library.add(fa.faLock); const linkSchema = createSchema({ title: "string", @@ -447,7 +448,7 @@ export class DocumentView extends DocComponent(Docu this.templates = this.templates; } - freezeNativeDimensions = (e: React.MouseEvent): void => { + freezeNativeDimensions = (): void => { let proto = Doc.GetProto(this.props.Document); if (proto.ignoreAspect === undefined && !proto.nativeWidth) { proto.nativeWidth = this.props.PanelWidth(); @@ -476,7 +477,7 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); - cm.addItem({ description: "Open...", subitems: subitems }); + cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: () => this.props.Document.lockedPosition = BoolCast(this.props.Document.lockedPosition) ? undefined : true, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 00021bc78..d6ab2a34a 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -37,14 +37,14 @@ export class IconBox extends React.Component { return ; } - setLabelField = (e: React.MouseEvent): void => { + setLabelField = (): void => { this.props.Document.hideLabel = !BoolCast(this.props.Document.hideLabel); } - setUseOwnTitleField = (e: React.MouseEvent): void => { + setUseOwnTitleField = (): void => { this.props.Document.useOwnTitle = !BoolCast(this.props.Document.useTargetTitle); } - specificContextMenu = (e: React.MouseEvent): void => { + specificContextMenu = (): void => { ContextMenu.Instance.addItem({ description: BoolCast(this.props.Document.hideLabel) ? "Show label with icon" : "Remove label from icon", event: this.setLabelField -- cgit v1.2.3-70-g09d2 From 118ecb14ce519bcbade12b3d52e11b22fcc371b3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 19 Jun 2019 22:40:54 -0400 Subject: cleaned up and enhanced tree view --- src/client/documents/Documents.ts | 1 - .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionTreeView.scss | 5 +- .../views/collections/CollectionTreeView.tsx | 347 +++++++++------------ src/client/views/nodes/DocumentView.tsx | 5 +- 5 files changed, 158 insertions(+), 202 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index fcd1010c6..de6c5bc6a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -18,7 +18,6 @@ import { action } from "mobx"; import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; import { AggregateFunction } from "../northstar/model/idea/idea"; -import { Template } from "../views/Templates"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { IconBox } from "../views/nodes/IconBox"; import { Field, Doc, Opt } from "../../new_fields/Doc"; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index faea8d44d..9cc8961e3 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -385,7 +385,7 @@ interface CollectionSchemaPreviewProps { Document?: Doc; width: () => number; height: () => number; - CollectionView: CollectionView | CollectionPDFView | CollectionVideoView; + CollectionView?: CollectionView | CollectionPDFView | CollectionVideoView; getTransform: () => Transform; addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean; diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index ec78fdb80..a85604e58 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -4,10 +4,10 @@ border-width: $COLLECTION_BORDER_WIDTH; border-color: transparent; border-style: solid; - border-radius: $border-radius; + border-radius: inherit; box-sizing: border-box; height: 100%; - padding: 20px; + padding-top: 20px; padding-left: 10px; padding-right: 0px; background: $light-color-secondary; @@ -56,6 +56,7 @@ font-size: 8pt; margin-left: 3px; display:none; + background: lightgray; } .docContainer { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 1eab541b3..856430036 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,38 +1,35 @@ -import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt, faCaretSquareRight, faCaretSquareDown } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, trace, computed } from "mobx"; +import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc'; +import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; +import { List } from '../../../new_fields/List'; import { Document, listSpec } from '../../../new_fields/Schema'; -import { BoolCast, Cast, NumCast, StrCast, PromiseValue } from '../../../new_fields/Types'; +import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { emptyFunction, Utils } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; +import { SelectionManager } from '../../util/SelectionManager'; +import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from "../EditableView"; import { MainView } from '../MainView'; +import { Templates } from '../Templates'; import { CollectionViewType } from './CollectionBaseView'; import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; +import { CollectionSchemaPreview } from './CollectionSchemaView'; +import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); -import { Transform } from '../../util/Transform'; -import { SelectionManager } from '../../util/SelectionManager'; -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 { document: Doc; - deleteDoc: (doc: Doc) => void; + deleteDoc: (doc: Doc) => boolean; moveDocument: DragManager.MoveFunction; dropAction: "alias" | "copy" | undefined; addDocTab: (doc: Doc, where: string) => void; @@ -41,22 +38,18 @@ export interface TreeViewProps { addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; indentDocument?: () => void; ScreenToLocalTransform: () => Transform; - outerXf: () => number[]; + outerXf: () => { translateX: number, translateY: number }; treeViewId: string; parentKey: string; active: () => boolean; } -export enum BulletType { - Collapsed, - Collapsible, - List -} - library.add(faTrashAlt); library.add(faAngleRight); library.add(faCaretDown); library.add(faCaretRight); +library.add(faCaretSquareDown); +library.add(faCaretSquareRight); @observer /** @@ -64,25 +57,22 @@ library.add(faCaretRight); */ class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); - private treedropDisposer?: DragManager.DragDropDisposer; - private _mainEle?: HTMLDivElement; + private _treedropDisposer?: DragManager.DragDropDisposer; + private _dref = React.createRef(); + @observable _chosenKey: string = "data"; + @observable _collapsed: boolean = true; + protected createTreeDropTarget = (ele: HTMLDivElement) => { - this.treedropDisposer && this.treedropDisposer(); + this._treedropDisposer && this._treedropDisposer(); if (ele) { - this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } }); + this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } }); } - this._mainEle = ele; } - @observable _isOver: boolean = false; - @observable _collapsed: boolean = true; - @undoBatch delete = () => this.props.deleteDoc(this.props.document); @undoBatch openRight = async () => this.props.addDocTab(this.props.document, "openRight"); - @action onMouseEnter = () => { this._isOver = true; }; - @action onMouseLeave = () => { this._isOver = false; }; - + onPointerDown = (e: React.PointerEvent) => e.stopPropagation() onPointerEnter = (e: React.PointerEvent): void => { this.props.active() && (this.props.document.libraryBrush = true); if (e.buttons === 1 && SelectionManager.GetIsDragging()) { @@ -101,80 +91,60 @@ 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._bulletType === BulletType.Collapsible); + let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed); this._header!.current!.className = "treeViewItem-header"; - if (inside && this._bulletType !== BulletType.List) this._header!.current!.className += " treeViewItem-header-inside"; + if (inside) this._header!.current!.className += " treeViewItem-header-inside"; else if (before) this._header!.current!.className += " treeViewItem-header-above"; else if (!before) this._header!.current!.className += " treeViewItem-header-below"; e.stopPropagation(); } - onPointerDown = (e: React.PointerEvent) => { - e.stopPropagation(); - } @action - remove = (document: Document, key: string) => { + remove = (document: Document, key: string): boolean => { let children = Cast(this.props.document[key], listSpec(Doc), []); - children.indexOf(document) !== -1 && children.splice(children.indexOf(document), 1); + if (children.indexOf(document) !== -1) { + children.splice(children.indexOf(document), 1); + return true; + } + return false; } @action - move: DragManager.MoveFunction = (document: Doc, target: Doc, addDoc) => { - if (this.props.document !== target) { - //TODO This should check if it was removed - this.props.deleteDoc(document); - return addDoc(document); - } - return true; + move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => { + return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc); } @action - indent = () => { - this.props.addDocument(this.props.document); - this.delete(); - } - + indent = () => this.props.addDocument(this.props.document) && this.delete(); - renderBullet(type: BulletType) { - let onClicked = action(() => this._collapsed = !this._collapsed); - let bullet: IconProp | undefined = undefined; - switch (type) { - case BulletType.Collapsed: bullet = "caret-right"; break; - case BulletType.Collapsible: bullet = "caret-down"; break; - } - return
{bullet ? : ""}
; + renderBullet() { + let docList = Cast(this.props.document["data"], listSpec(Doc)); + let doc = Cast(this.props.document["data"], Doc); + let isDoc = doc instanceof Doc || docList; + return
this._collapsed = !this._collapsed)}> + {} +
; } - static loadId = ""; - editableView = (key: string, style?: string) => - ( StrCast(this.props.document[key])} - OnFillDown={(value: string) => { - Doc.GetProto(this.props.document)[key] = 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); - return true; - }} - OnTab={() => this.props.indentDocument && this.props.indentDocument()} - SetValue={(value: string) => { - Doc.GetProto(this.props.document)[key] = value; - return true; - }} - />) - /** - * Renders the EditableView title element for placement into the tree. - */ - renderTitle() { - let reference = React.createRef(); - let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true); + static loadId = ""; + editableView = (key: string, style?: string) => ( StrCast(this.props.document[key])} + SetValue={(value: string) => (Doc.GetProto(this.props.document)[key] = value) ? true : true} + OnFillDown={(value: string) => { + Doc.GetProto(this.props.document)[key] = value; + let doc = Docs.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={() => this.props.indentDocument && this.props.indentDocument()} + />) + get keyList() { let keyList: string[] = []; let keys = Array.from(Object.keys(this.props.document)); if (this.props.document.proto instanceof Doc) { @@ -192,19 +162,26 @@ class TreeView extends React.Component { 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} + return keyList; + } + /** + * Renders the EditableView title element for placement into the tree. + */ + renderTitle() { + let reference = React.createRef(); + let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true); + + let headerElements = ( + this.props.document.embed = !BoolCast(this.props.document.embed))} > + {this._chosenKey} ); let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []) : []; let openRight = dataDocs && dataDocs.indexOf(this.props.document) !== -1 ? (null) : (
- {/* */}
); return <> -
{ 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._bulletType === BulletType.Collapsible); + let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed); if (de.data instanceof DragManager.DocumentDragData) { let addDoc = (doc: Doc) => this.props.addDocument(doc, this.props.document, before); if (inside) { @@ -250,18 +227,13 @@ class TreeView extends React.Component { addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }; } } - let added = false; - if (de.data.dropAction || de.data.userDropAction) { - added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before) || added, false); - } else if (de.data.moveDocument) { - let movedDocs = de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments; - added = movedDocs.reduce((added: boolean, d) => - de.data.moveDocument(d, this.props.document, addDoc) || added, false); - } else { - added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before), false); - } e.stopPropagation(); - return added; + let movedDocs = (de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments); + return (de.data.dropAction || de.data.userDropAction) ? + de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before) || added, false) + : (de.data.moveDocument) ? + movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.props.document, addDoc) || added, false) + : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before), false); } return false; } @@ -279,62 +251,47 @@ 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[0] - translateX, outerXf[1] - translateY); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - 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)[] = []; - [this._chosenKey].map(key => { - let docList = Cast(this.props.document[key], listSpec(Doc)); - let remDoc = (doc: Doc) => this.remove(doc, key); - let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, key, doc, addBefore, before); - let doc = Cast(this.props.document[key], Doc); - if (doc instanceof Doc || (docList && (DocListCast(docList).length > 0 || key === "data"))) { - if (!this._collapsed) { - bulletType = BulletType.Collapsible; - 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; - } + let contentElement: (JSX.Element | null) = null; + let docList = Cast(this.props.document[this._chosenKey], listSpec(Doc)); + let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, this._chosenKey, doc, addBefore, before); + let doc = Cast(this.props.document[this._chosenKey], Doc); + let docWidth = () => NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 5) : this.props.panelWidth() - 5; + if (!this._collapsed) { + if (!this.props.document.embed && (docList && (DocListCast(docList).length > 0 || this._chosenKey === "data"))) { + contentElement =
    + {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this._chosenKey, addDoc, remDoc, this.move, + this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth)} +
; + } else { + contentElement =
+ + +
} - }); - this._bulletType = bulletType; - return
+ } + return
  • - {this.renderBullet(bulletType)} + {this.renderBullet()} {this.renderTitle()}
    @@ -348,17 +305,17 @@ class TreeView extends React.Component { treeViewId: string, key: string, add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean, - remove: ((doc: Doc) => void), + remove: ((doc: Doc) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => void, screenToLocalXf: () => Transform, - outerXf: () => number[], + outerXf: () => { translateX: number, translateY: number }, active: () => boolean, panelWidth: () => number, - panelHeight: () => number ) { let docList = docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized)); + let rowWidth = () => panelWidth() - 20; return docList.map((child, i) => { let indent = i === 0 ? undefined : () => { if (StrCast(docList[i - 1].layout).indexOf("CollectionView") !== -1) { @@ -368,15 +325,22 @@ class TreeView extends React.Component { remove(child); } } + let addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => { + return add(doc, relativeTo ? relativeTo : docList[i], before !== undefined ? before : false); + } + let rowHeight = () => { + let aspect = NumCast(child.nativeWidth, 0) / NumCast(child.nativeHeight, 0); + return aspect ? Math.min(child[WidthSym](), rowWidth()) / aspect : child[HeightSym](); + } return { export class CollectionTreeView extends CollectionSubView(Document) { private treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; + protected createTreeDropTarget = (ele: HTMLDivElement) => { - if (this.treedropDisposer) { - this.treedropDisposer(); - } - if (ele) { + this.treedropDisposer && this.treedropDisposer(); + if (this._mainEle = ele) { this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); } - this._mainEle = ele; + } + + componentWillUnmount() { + this.treedropDisposer && this.treedropDisposer(); } @action - remove = (document: Document) => { + remove = (document: Document): boolean => { let children = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []); - children.indexOf(document) !== -1 && children.splice(children.indexOf(document), 1); + if (children.indexOf(document) !== -1) { + children.splice(children.indexOf(document), 1); + return true; + } + return false; } onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout @@ -415,26 +385,16 @@ 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, {}); - } + outerXf = () => Utils.GetScreenTransform(this._mainEle!); + onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {}); + render() { let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; - if (!this.childDocs) { - return (null); - } 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, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, () => 25); - return ( + return !this.childDocs ? (null) : (
    this.props.isSelected() && e.stopPropagation()} onDrop={this.onTreeDrop} @@ -445,22 +405,19 @@ export class CollectionTreeView extends CollectionSubView(Document) { display={"inline"} height={72} GetValue={() => StrCast(this.props.Document.title)} + SetValue={(value: string) => (Doc.GetProto(this.props.Document).title = value) ? true : true} 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 }); + Doc.GetProto(this.props.Document).title = value; + let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); 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; - return true; + TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true); }} />
      - {childElements} + { + TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove, + moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth) + }
    ); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f7836d947..4992669df 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -72,7 +72,6 @@ export interface DocumentViewProps { ScreenToLocalTransform: () => Transform; isTopMost: boolean; ContentScaling: () => number; - useActualDimensions?: boolean; PanelWidth: () => number; PanelHeight: () => number; focus: (doc: Doc) => void; @@ -539,8 +538,8 @@ export class DocumentView extends DocComponent(Docu render() { var scaling = this.props.ContentScaling(); - 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%"; + 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%"; return (
    Date: Thu, 20 Jun 2019 16:27:44 -0400 Subject: Added hidden flag to documents --- src/client/views/nodes/DocumentView.tsx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index acd5e4cf2..280804630 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -89,6 +89,7 @@ const schema = createSchema({ nativeWidth: "number", nativeHeight: "number", backgroundColor: "string", + hidden: "boolean" }); export const positionSchema = createSchema({ @@ -538,6 +539,9 @@ export class DocumentView extends DocComponent(Docu } render() { + if (this.Document.hidden) { + return null; + } 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%"; -- cgit v1.2.3-70-g09d2 From 1f172642d12c4669960b8526324e4bd034994be4 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 20 Jun 2019 17:44:24 -0400 Subject: Added arrange documents in grid command --- .../collectionFreeForm/CollectionFreeFormView.tsx | 32 ++++++++++++++++++++-- src/client/views/nodes/DocumentView.tsx | 2 +- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 84841e469..f756fe625 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../../new_fields/Doc"; +import { Doc, HeightSym, WidthSym, DocListCastAsync } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { createSchema, makeInterface } from "../../../../new_fields/Schema"; @@ -26,6 +26,7 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import PDFMenu from "../../pdf/PDFMenu"; +import { ContextMenu } from "../../ContextMenu"; export const panZoomSchema = createSchema({ panX: "number", @@ -339,6 +340,33 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } + onContextMenu = () => { + ContextMenu.Instance.addItem({ + description: "Arrange contents in grid", + event: async () => { + const docs = await DocListCastAsync(this.Document[this.props.fieldKey]); + if (docs) { + let startX = this.Document.panX || 0; + let x = startX; + let y = this.Document.panY || 0; + let i = 0; + const width = Math.max(...docs.map(doc => NumCast(doc.width))); + const height = Math.max(...docs.map(doc => NumCast(doc.height))); + for (const doc of docs) { + doc.x = x; + doc.y = y; + x += width + 20; + if (++i === 6) { + i = 0; + x = startX; + y += height + 20; + } + } + } + } + }); + } + private childViews = () => [ , ...this.views @@ -349,7 +377,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return (
    + onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onContextMenu={this.onContextMenu}> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 280804630..522c37989 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -237,7 +237,7 @@ export class DocumentView extends DocComponent(Docu static _undoBatch?: UndoManager.Batch = undefined; @action - public collapseTargetsToPoint = async (scrpt: number[], expandedDocs: Doc[] | undefined): Promise => { + public collapseTargetsToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => { SelectionManager.DeselectAll(); if (expandedDocs) { if (!DocumentView._undoBatch) { -- cgit v1.2.3-70-g09d2