diff options
| author | bob <bcz@cs.brown.edu> | 2019-05-06 13:10:28 -0400 |
|---|---|---|
| committer | bob <bcz@cs.brown.edu> | 2019-05-06 13:10:28 -0400 |
| commit | a9f465a32ac538c8dcf94bd37afda730e7be3526 (patch) | |
| tree | 48fe985b4530cd500baf707820e1de0fdae986d6 /src/client/views/collections | |
| parent | f63217890738e738dfa0e8eca3f8a8996440373e (diff) | |
| parent | e96e3382104a2ae8dbe41252c0b38206b983e94a (diff) | |
Merge branch 'newDocs'
Diffstat (limited to 'src/client/views/collections')
5 files changed, 136 insertions, 83 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 278065479..6f721a0c8 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,25 +1,23 @@ -import * as GoldenLayout from "golden-layout"; import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; -import { action, observable, reaction, trace, runInAction } from "mobx"; +import { action, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; -import { Utils, returnTrue, emptyFunction, returnOne, returnZero } from "../../../Utils"; +import * as GoldenLayout from "../../../client/goldenLayout"; +import { Doc, Field, Opt } from "../../../new_fields/Doc"; +import { FieldId, Id } from "../../../new_fields/RefField"; +import { listSpec } from "../../../new_fields/Schema"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { emptyFunction, returnTrue, Utils } from "../../../Utils"; +import { DocServer } from "../../DocServer"; +import { DragLinksAsDocuments, DragManager } from "../../util/DragManager"; +import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; -import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; -import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; -import { Transform } from '../../util/Transform'; -import { Doc, Opt, Field } from "../../../new_fields/Doc"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { DocServer } from "../../DocServer"; -import { listSpec } from "../../../new_fields/Schema"; -import { Id, FieldId } from "../../../new_fields/RefField"; -import { faSignInAlt } from "@fortawesome/free-solid-svg-icons"; +import React = require("react"); @observer export class CollectionDockingView extends React.Component<SubCollectionViewProps> { @@ -72,6 +70,37 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp this.stateChanged(); } + @undoBatch + @action + public CloseRightSplit(document: Doc) { + if (this._goldenLayout.root.contentItems[0].isRow) { + this._goldenLayout.root.contentItems[0].contentItems.map((child: any, i: number) => { + if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" && + child.contentItems[0].config.props.documentId == document[Id]) { + child.contentItems[0].remove(); + //this._goldenLayout.root.contentItems[0].contentItems.splice(i, 1); + this.layoutChanged(document); + } else + child.contentItems.map((tab: any, j: number) => { + if (tab.config.component === "DocumentFrameRenderer" && tab.config.props.documentId === document[Id]) { + child.contentItems[j].remove(); + let docs = Cast(this.props.Document.data, listSpec(Doc)); + docs && docs.indexOf(document) !== -1 && docs.splice(docs.indexOf(document), 1); + } + }); + }) + } + } + + @action + layoutChanged(removed?: Doc) { + this._goldenLayout.root.callDownwards('setSize', [this._goldenLayout.width, this._goldenLayout.height]); + this._goldenLayout.emit('sbcreteChanged'); + this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); + if (removed) CollectionDockingView.Instance._removedDocs.push(removed); + this.stateChanged(); + } + // // Creates a vertical split on the right side of the docking view, and then adds the Document to that split // @@ -107,10 +136,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp newContentItem.config.height = 10; } newContentItem.callDownwards('_$init'); - this._goldenLayout.root.callDownwards('setSize', [this._goldenLayout.width, this._goldenLayout.height]); - this._goldenLayout.emit('stateChanged'); - this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); - this.stateChanged(); + this.layoutChanged(); return newContentItem; } @@ -256,25 +282,24 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp return template.content.firstChild; } - tabCreated = (tab: any) => { + tabCreated = async (tab: any) => { if (tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") { - DocServer.GetRefField(tab.contentItem.config.props.documentId).then(async f => { - if (f instanceof Doc) { - const title = Cast(f.title, "string"); - if (title !== undefined) { - tab.titleElement[0].textContent = title; - } - const lf = await Cast(f.linkedFromDocs, listSpec(Doc)); - const lt = await Cast(f.linkedToDocs, listSpec(Doc)); - let count = (lf ? lf.length : 0) + (lt ? lt.length : 0); - let counter: any = this.htmlToElement(`<div class="messageCounter">${count}</div>`); + if (tab.contentItem.config.fixed) { + tab.contentItem.parent.config.fixed = true; + } + DocServer.GetRefField(tab.contentItem.config.props.documentId).then(async doc => { + if (doc instanceof Doc) { + let counter: any = this.htmlToElement(`<div class="messageCounter">0</div>`); tab.element.append(counter); counter.DashDocId = tab.contentItem.config.props.documentId; - tab.reactionDisposer = reaction((): [List<Field> | null | undefined, List<Field> | null | undefined] => [lf, lt], - ([linkedFrom, linkedTo]) => { - let count = (linkedFrom ? linkedFrom.length : 0) + (linkedTo ? linkedTo.length : 0); + tab.reactionDisposer = reaction(() => [doc.linkedFromDocs, doc.LinkedToDocs, doc.title], + () => { + const lf = Cast(doc.linkedFromDocs, listSpec(Doc), []); + const lt = Cast(doc.linkedToDocs, listSpec(Doc), []); + let count = (lf ? lf.length : 0) + (lt ? lt.length : 0); counter.innerHTML = count; - }); + tab.titleElement[0].textContent = doc.title; + }, { fireImmediately: true }); tab.titleElement[0].DashDocId = tab.contentItem.config.props.documentId; } }); @@ -301,16 +326,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp .click(action(function () { //if (confirm('really close this?')) { stack.remove(); - //} - })); - stack.header.controlsContainer.find('.lm_popout') //get the close icon - .off('click') //unbind the current click handler - .click(action(function () { - var url = DocServer.prepend("/doc/" + stack.contentItems[0].tab.contentItem.config.props.documentId); - let win = window.open(url, stack.contentItems[0].tab.title, "width=300,height=400"); - })); - stack.header.controlsContainer.find('.lm_close') //unbind the current click handler - .click(async function () { stack.contentItems.map(async (contentItem: any) => { let doc = await DocServer.GetRefField(contentItem.config.props.documentId); if (doc instanceof Doc) { @@ -318,7 +333,15 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp CollectionDockingView.Instance._removedDocs.push(theDoc); } }); - }); + //} + })); + stack.header.controlsContainer.find('.lm_popout') //get the close icon + .off('click') //unbind the current click handler + .click(action(function () { + stack.config.fixed = !stack.config.fixed; + // var url = DocServer.prepend("/doc/" + stack.contentItems[0].tab.contentItem.config.props.documentId); + // let win = window.open(url, stack.contentItems[0].tab.title, "width=300,height=400"); + })); } render() { @@ -327,6 +350,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} ref={this._containerRef} /> ); } + } interface DockedFrameProps { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 4fee9db85..16818affd 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -19,7 +19,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { Opt, Field, Doc } from "../../../new_fields/Doc"; +import { Opt, Field, Doc, DocListCast } from "../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; @@ -111,17 +111,15 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } return applyToDoc(props.Document, script.run); }} - OnFillDown={(value: string) => { + OnFillDown={async (value: string) => { let script = CompileScript(value, { addReturn: true, params: { this: Document.name } }); if (!script.compiled) { return; } const run = script.run; //TODO This should be able to be refactored to compile the script once - const val = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)); - if (val) { - val.forEach(doc => applyToDoc(doc, run)); - } + const val = await DocListCast(this.props.Document[this.props.fieldKey]) + val && val.forEach(doc => applyToDoc(doc, run)); }}> </EditableView> </div > diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 6ce13cf56..411d67ff7 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -23,10 +23,6 @@ margin: 5px 0; } - .collection-child { - margin-top: 10px; - margin-bottom: 10px; - } .no-indent { padding-left: 0; @@ -42,24 +38,18 @@ transform: scale(1.3,1.3); } - .coll-title { - width:max-content; - display: block; - font-size: 24px; - } - .docContainer { margin-left: 10px; display: block; - width:100%;//width: max-content; + // width:100%;//width: max-content; } - .docContainer:hover { - .delete-button { - display: inline; - // width: auto; + .treeViewItem-openRight { + display:inline; } } + + .editableView-container { font-weight: bold; } @@ -71,7 +61,26 @@ // margin-top: 3px; display: inline; } + .treeViewItem-openRight { + margin-left: 5px; + display:none; + } + .docContainer:hover { + .delete-button { + display: inline; + // width: auto; + } + } + .coll-title { + width:max-content; + display: block; + font-size: 24px; + } + .collection-child { + margin-top: 10px; + margin-bottom: 10px; + } .collectionTreeView-keyHeader { font-style: italic; font-size: 8pt; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 17109508d..429d0f047 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,5 +1,5 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { faCaretDown, faCaretRight, faTrashAlt, faAngleRight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; @@ -20,6 +20,7 @@ import { CollectionDockingView } from './CollectionDockingView'; import { DocumentManager } from '../../util/DocumentManager'; import { Utils } from '../../../Utils'; import { List } from '../../../new_fields/List'; +import { indexOf } from 'typescript-collections/dist/lib/arrays'; export interface TreeViewProps { @@ -36,6 +37,7 @@ export enum BulletType { } library.add(faTrashAlt); +library.add(faAngleRight); library.add(faCaretDown); library.add(faCaretRight); @@ -47,7 +49,15 @@ class TreeView extends React.Component<TreeViewProps> { @observable _collapsed: boolean = true; - delete = () => this.props.deleteDoc(this.props.document); + @undoBatch delete = () => this.props.deleteDoc(this.props.document); + + @undoBatch openRight = () => { + if (this.props.document.dockingConfig) { + Main.Instance.openWorkspace(this.props.document); + } else { + CollectionDockingView.Instance.AddRightSplit(this.props.document); + } + }; get children() { return Cast(this.props.document.data, listSpec(Doc), []); // bcz: needed? .filter(doc => FieldValue(doc)); @@ -100,9 +110,11 @@ class TreeView extends React.Component<TreeViewProps> { }} />); return ( - <div className="docContainer" ref={reference} onPointerDown={onItemDown}> + <div className="docContainer" ref={reference} onPointerDown={onItemDown} + onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> {editableView(StrCast(this.props.document.title))} - {/* <div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div> */} + <div className="treeViewItem-openRight" onClick={this.openRight}><FontAwesomeIcon icon="angle-right" size="lg" /><FontAwesomeIcon icon="angle-right" size="lg" /></div> + {/* {<div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div>} */} </div >); } @@ -145,8 +157,7 @@ class TreeView extends React.Component<TreeViewProps> { }); return <div className="treeViewItem-container" style={{ background: BoolCast(this.props.document.libraryBrush, false) ? "#06121212" : "0" }} - onContextMenu={this.onWorkspaceContextMenu} - onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> + onContextMenu={this.onWorkspaceContextMenu}> <li className="collection-child"> {this.renderBullet(bulletType)} {this.renderTitle()} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8c81f6990..805921ad4 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -15,6 +15,8 @@ import { NumCast, Cast } from "../../../../new_fields/Types"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { Templates } from "../../Templates"; import { List } from "../../../../new_fields/List"; +import { emitKeypressEvents } from "readline"; +import { listSpec } from "../../../../new_fields/Schema"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -149,16 +151,17 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this.cleanupInteractions(false); e.stopPropagation(); } - if (e.key === "c" || e.key === "r" || e.key === "e") { + if (e.key === "c" || e.key === "r" || e.key === "R" || e.key === "e") { this._commandExecuted = true; e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { - if (e.key !== "r") + if (e.key !== "R") { this.props.removeDocument(d); - d.x = NumCast(d.x) - bounds.left - bounds.width / 2; - d.y = NumCast(d.y) - bounds.top - bounds.height / 2; - d.page = -1; + d.x = NumCast(d.x) - bounds.left - bounds.width / 2; + d.y = NumCast(d.y) - bounds.top - bounds.height / 2; + d.page = -1; + } return d; }); let ink = Cast(this.props.container.props.Document.ink, InkField); @@ -179,16 +182,23 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this.marqueeInkDelete(inkData); // SelectionManager.DeselectAll(); - if (e.key === "r") { - let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - summary.maximizedDocs = new List<Doc>(selected); - // summary.doc1 = selected[0]; - // if (selected.length > 1) - // summary.doc2 = selected[1]; - // summary.templates = new List<string>([Templates.Summary.Layout]); - this.props.addLiveTextDocument(summary); + if (e.key === "r" || e.key === "R") { e.preventDefault(); let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); + let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + + if (e.key === "r") { + summary.proto!.maximizeOnRight = true; + let list = Cast(newCollection.data, listSpec(Doc)); + if (list && list.length === 1) { + selected = list; + } else { + selected = [newCollection]; + this.props.addDocument(newCollection, false); + } + } + summary.proto!.maximizedDocs = new List<Doc>(selected); + summary.proto!.isButton = true; selected.map(maximizedDoc => { let maxx = NumCast(maximizedDoc.x, undefined); let maxy = NumCast(maximizedDoc.y, undefined); @@ -196,6 +206,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> let maxh = NumCast(maximizedDoc.height, undefined); maximizedDoc.isIconAnimating = new List<number>([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) }); + this.props.addLiveTextDocument(summary); } else { this.props.addDocument(newCollection, false); |
