diff options
| author | Tyler Schicke <tyler_schicke@brown.edu> | 2019-04-25 15:36:32 -0400 |
|---|---|---|
| committer | Tyler Schicke <tyler_schicke@brown.edu> | 2019-04-25 15:36:32 -0400 |
| commit | c318c6cb44b26b780e94e0f0854e5ec4c14634a9 (patch) | |
| tree | 5c6bcb413f771988bd89efe3551007bd6d0f160c /src/client/views/collections | |
| parent | e1a65c5fa52dd094cc48c0c85b3c92ae8789666d (diff) | |
| parent | 430dfa3afbfd38fe0db869b962da45903b888264 (diff) | |
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web into newDocs
Diffstat (limited to 'src/client/views/collections')
10 files changed, 163 insertions, 161 deletions
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 058893198..4807dc40a 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; -import { Cast, FieldValue, PromiseValue } from '../../../new_fields/Types'; +import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types'; import { Doc, FieldResult, Opt, Id } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; @@ -87,51 +87,24 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { let props = this.props; var curPage = Cast(props.Document.curPage, "number", -1); Doc.SetOnPrototype(doc, "page", curPage); - if (true || this.isAnnotationOverlay) { - doc.zoom = Cast(this.props.Document.scale, "number", 1); - } if (curPage >= 0) { Doc.SetOnPrototype(doc, "annotationOn", props.Document); } - const data = props.Document[props.fieldKey]; - if (data !== undefined) { + if (!this.createsCycle(doc, props.Document)) { //TODO This won't create the field if it doesn't already exist - const value = Cast(data, listSpec(Doc)); - if (!this.createsCycle(doc, props.Document) && value !== undefined) { + const value = Cast(props.Document[props.fieldKey], listSpec(Doc)); + if (value !== undefined) { if (allowDuplicates || !value.some(v => v.Id === doc.Id)) { value.push(doc); } + } else { + this.props.Document[this.props.fieldKey] = new List([doc]); } - else { - return false; - } - } else { - let proto = FieldValue(props.Document.proto); - if (!proto || !this.createsCycle(proto, doc)) { - const field = new List([doc]); - // const script = CompileScript(` - // if(added) { - // console.log("added " + field.Title + " " + doc.Title); - // } else { - // console.log("removed " + field.Title + " " + doc.Title); - // } - // `, { - // addReturn: false, - // params: { - // field: Document.name, - // added: "boolean" - // }, - // capturedVariables: { - // doc: this.props.Document - // } - // }); - // if (script.compiled) { - // field.addScript(new ScriptField(script)); - // } - Doc.SetOnPrototype(props.Document, props.fieldKey, field); - } - else { - return false; + // set the ZoomBasis only if hasn't already been set -- bcz: maybe set/resetting the ZoomBasis should be a parameter to addDocument? + if (this.collectionViewType === CollectionViewType.Freeform || this.collectionViewType === CollectionViewType.Invalid) { + let zoom = NumCast(this.props.Document.scale, 1); + let screen = this.props.ScreenToLocalTransform().inverse().Scale / (this.props as any).ContentScaling() * zoom; + doc.zoomBasis = screen; } } return true; @@ -186,7 +159,9 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { }; const viewtype = this.collectionViewType; return ( - <div className={this.props.className || "collectionView-cont"} onContextMenu={this.props.onContextMenu} ref={this.props.contentRef}> + <div className={this.props.className || "collectionView-cont"} + style={{ borderRadius: "inherit", pointerEvents: "all" }} + onContextMenu={this.props.onContextMenu} ref={this.props.contentRef}> {viewtype !== undefined ? this.props.children(viewtype, props) : (null)} </div> ); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 86ee7cea9..ec5f823b0 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -5,7 +5,7 @@ import { action, observable, reaction, trace } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; -import { Utils, returnTrue, emptyFunction, returnOne } from "../../../Utils"; +import { Utils, returnTrue, emptyFunction, returnOne, returnZero } from "../../../Utils"; import { Server } from "../../Server"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; @@ -16,9 +16,10 @@ import { ServerUtils } from "../../../server/ServerUtil"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; -import { Cast } from "../../../new_fields/Types"; +import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; +import { listSpec } from "../../../new_fields/Schema"; @observer export class CollectionDockingView extends React.Component<SubCollectionViewProps> { @@ -256,8 +257,8 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp if (tfield !== undefined) { tab.titleElement[0].textContent = f.Title; } - const lf = await Cast(f.linkedFromDocs, List); - const lt = await Cast(f.linkedToDocs, List); + 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>`); tab.element.append(counter); @@ -322,8 +323,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => this._document = f as Doc)); } - nativeWidth = () => Cast(this._document!.nativeWidth, "number", this._panelWidth); - nativeHeight = () => Cast(this._document!.nativeHeight, "number", this._panelHeight); + nativeWidth = () => NumCast(this._document!.nativeWidth, this._panelWidth); + nativeHeight = () => NumCast(this._document!.nativeHeight, this._panelHeight); contentScaling = () => { const nativeH = this.nativeHeight(); const nativeW = this.nativeWidth(); @@ -349,6 +350,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { <div className="collectionDockingView-content" ref={this._mainCont} style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}> <DocumentView key={this._document![Id]} Document={this._document!} + toggleMinimized={emptyFunction} addDocument={undefined} removeDocument={undefined} ContentScaling={this.contentScaling} @@ -361,7 +363,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { whenActiveChanged={emptyFunction} focus={emptyFunction} ContainingCollectionView={undefined} /> - </div>); + </div >); } render() { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index e556151f9..2e1175f28 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -7,10 +7,9 @@ import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' import "react-table/react-table.css"; -import { emptyFunction, returnFalse } from "../../../Utils"; -import { Server } from "../../Server"; +import { emptyFunction, returnFalse, returnZero } from "../../../Utils"; import { SetupDrag } from "../../util/DragManager"; -import { CompileScript, ToField } from "../../util/Scripting"; +import { CompileScript } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss"; import { anchorPoints, Flyout } from "../DocumentDecorations"; @@ -21,7 +20,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { Opt, Field, Doc, Id } from "../../../new_fields/Doc"; -import { Cast, FieldValue } from "../../../new_fields/Types"; +import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; @@ -57,7 +56,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @observable _keys: string[] = []; @observable _newKeyName: string = ""; - @computed get splitPercentage() { return Cast(this.props.Document.schemaSplitPercentage, "number", 0); } + @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage); } @computed get columns() { return Cast(this.props.Document.columns, listSpec("string"), []); } @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } @@ -74,6 +73,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { focus: emptyFunction, active: returnFalse, whenActiveChanged: emptyFunction, + PanelHeight: returnZero, + PanelWidth: returnZero, }; let contents = ( <FieldView {...props} /> @@ -256,6 +257,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { <div className="collectionSchemaView-previewRegion" style={{ width: `${this.previewRegionWidth}px` }}> <div className="collectionSchemaView-previewDoc" style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}> <DocumentView Document={this.previewDocument} isTopMost={false} selectOnLoad={false} + toggleMinimized={emptyFunction} addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} ScreenToLocalTransform={this.getPreviewTransform} ContentScaling={this.previewContentScaling} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 642e5aed6..558a8728f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -4,11 +4,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DragManager } from "../../util/DragManager"; import { Docs, DocumentOptions } from "../../documents/Documents"; import { RouteStore } from "../../../server/RouteStore"; -import { TupleField } from "../../../fields/TupleField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { NumberField } from "../../../fields/NumberField"; -import { ServerUtils } from "../../../server/ServerUtil"; -import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; @@ -85,7 +81,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { if (de.data instanceof DragManager.DocumentDragData) { if (de.data.aliasOnDrop || de.data.copyOnDrop) { ["width", "height", "curPage"].map(key => - de.data.draggedDocuments.map((draggedDocument: Document, i: number) => + de.data.draggedDocuments.map((draggedDocument: Doc, i: number) => PromiseValue(Cast(draggedDocument[key], "number")).then(f => f && (de.data.droppedDocuments[i][key] = f)))); } let added = false; @@ -148,7 +144,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { return undefined; } ctor = Docs.WebDocument; - options = { height: options.width, ...options, title: path }; + options = { height: options.width, ...options, title: path, nativeWidth: undefined }; } return ctor ? ctor(path, options) : undefined; } @@ -166,9 +162,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { e.preventDefault(); if (html && html.indexOf("<img") !== 0 && !html.startsWith("<a")) { - console.log("not good"); - let htmlDoc = Docs.HtmlDocument(html, { ...options, width: 300, height: 300 }); - htmlDoc.documentText = text; + let htmlDoc = Docs.HtmlDocument(html, { ...options, width: 300, height: 300, documentText: text }); this.props.addDocument(htmlDoc, false); return; } @@ -182,7 +176,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { if (item.kind === "string" && item.type.indexOf("uri") !== -1) { let str: string; let prom = new Promise<string>(resolve => e.dataTransfer.items[i].getAsString(resolve)) - .then(action((s: string) => rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + (str = s))))) + .then(action((s: string) => rp.head(DocServer.prepend(RouteStore.corsProxy + "/" + (str = s))))) .then(result => { let type = result.headers["content-type"]; if (type) { @@ -210,15 +204,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { let path = window.location.origin + file; let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 600, width: 300, title: dropFileName }); - docPromise.then(async doc => { - let docs = await Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)); - if (!docs) { - this.props.Document[this.props.fieldKey] = docs = new List(); - } - if (doc) { - docs.push(doc); - } - }); + docPromise.then(doc => doc && this.props.addDocument(doc)); })); }); promises.push(prom); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e0387f4b4..905b48db7 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -136,7 +136,10 @@ export class CollectionTreeView extends CollectionSubView { ); return ( - <div id="body" className="collectionTreeView-dropTarget" onWheel={(e: React.WheelEvent) => e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget}> + <div id="body" className="collectionTreeView-dropTarget" + style={{ borderRadius: "inherit" }} + onWheel={(e: React.WheelEvent) => e.stopPropagation()} + onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget}> <div className="coll-title"> <EditableView contents={this.props.Document.Title} diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 29fb342c6..779dc8fc3 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -37,10 +37,13 @@ export class CollectionVideoView extends React.Component<FieldViewProps> { ]); } + _ele: HTMLDivElement | null = null; @action mainCont = (ele: HTMLDivElement | null) => { + this._ele = ele; if (ele) { this._player = ele.getElementsByTagName("video")[0]; + console.log(this._player); if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) { this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1); } @@ -57,9 +60,12 @@ export class CollectionVideoView extends React.Component<FieldViewProps> { @action updateTimecode = () => { + this._player = this._player ? this._player : this._ele ? this._ele.getElementsByTagName("video")[0] : undefined; if (this._player) { - if ((this._player as any).AHackBecauseSomethingResetsTheVideoToZero !== -1) { - this._player.currentTime = (this._player as any).AHackBecauseSomethingResetsTheVideoToZero; + let timecode = (this._player as any).hasOwnProperty("AHackBecauseSomethingResetsTheVideoToZero") ? + (this._player as any).AHackBecauseSomethingResetsTheVideoToZero : -1; + if (timecode !== -1 && Object) { + this._player.currentTime = timecode; (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; } else { this._currentTimecode = this._player.currentTime; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index cd74d3a84..ebdb0c75c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -18,7 +18,7 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP componentDidMount() { this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)), () => { - let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); + let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc.GetText(KeyStore.BackgroundLayout, "").indexOf("istogram") !== -1); for (let i = 0; i < views.length; i++) { for (let j = 0; j < views.length; j++) { let srcDoc = views[j]; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 57706b51e..67a0e532c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -6,6 +6,7 @@ width: 100%; height: 100%; transform-origin: left top; + pointer-events: none; } .collectionfreeformview-container { .collectionfreeformview > .jsx-parser { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3a9c9780b..80900c450 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable, trace } from "mobx"; +import { action, computed } from "mobx"; import { observer } from "mobx-react"; import { emptyFunction, returnFalse, returnOne } from "../../../../Utils"; import { DocumentManager } from "../../../util/DocumentManager"; @@ -8,7 +8,6 @@ import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"; import { InkingCanvas } from "../../InkingCanvas"; -import { MainOverlayTextBox } from "../../MainOverlayTextBox"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps, positionSchema } from "../../nodes/DocumentView"; @@ -21,7 +20,7 @@ import React = require("react"); import v5 = require("uuid/v5"); import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; import { Doc, Id } from "../../../../new_fields/Doc"; -import { FieldValue, Cast } from "../../../../new_fields/Types"; +import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; import { List } from "../../../../new_fields/List"; @@ -36,6 +35,7 @@ const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema) @observer export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { + public static RIGHT_BTN_DRAG = false; private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type) private _lastX: number = 0; private _lastY: number = 0; @@ -46,7 +46,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } - private childViews = () => this.views; private panX = () => FieldValue(this.Document.panX, 0); private panY = () => FieldValue(this.Document.panY, 0); private zoomScaling = () => FieldValue(this.Document.scale, 1); @@ -60,10 +59,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { - newBox.zoom = FieldValue(this.Document.scale, 1); - return this.props.addDocument(this.bringToFront(newBox), false); + this.props.addDocument(newBox, false); + this.bringToFront(newBox); + return true; } - private selectDocuments = (docs: Document[]) => { + private selectDocuments = (docs: Doc[]) => { SelectionManager.DeselectAll; docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv => SelectionManager.SelectDoc(dv!, true)); @@ -80,23 +80,24 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action drop = (e: Event, de: DragManager.DropEvent) => { if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { - const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { let dragDoc = de.data.droppedDocuments[0]; - let dropX = Cast(dragDoc.x, "number", 0); - let dropY = Cast(dragDoc.y, "number", 0); + let zoom = NumCast(dragDoc.zoomBasis, 1); + let [xp, yp] = this.getTransform().transformPoint(de.x, de.y); + let x = xp - de.data.xOffset / zoom; + let y = yp - de.data.yOffset / zoom; + let dropX = NumCast(de.data.droppedDocuments[0].x); + let dropY = NumCast(de.data.droppedDocuments[0].y); de.data.droppedDocuments.map(d => { - d.x = x + Cast(d.x, "number", 0) - dropX; - d.y = y + Cast(d.y, "number", 0) - dropY; - if (!Cast(d.isMinimized, "boolean", false)) { - if (!Cast(d.width, "number", 0)) { - d.width = 300; - } - if (!Cast(d.height, "number", 0)) { - let nw = Cast(d.nativeWidth, "number", 0); - let nh = Cast(d.nativeHeight, "number", 0); - d.height = nw && nh ? nh / nw * Cast(d.width, "number", 0) : 300; - } + d.x = x + NumCast(d.x) - dropX; + d.y = y + NumCast(d.y) - dropY; + if (!NumCast(d.width)) { + d.width = 300; + } + if (!NumCast(d.height)) { + let nw = NumCast(d.nativeWidth); + let nh = NumCast(d.nativeHeight); + d.height = nw && nh ? nh / nw * d.Width() : 300; } this.bringToFront(d); }); @@ -119,20 +120,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { var dv = DocumentManager.Instance.getDocumentView(doc); return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false); }, false); - if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) { - document.removeEventListener("pointermove", this.onPointerMove); + if ((CollectionFreeFormView.RIGHT_BTN_DRAG && + (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || + (e.button === 0 && e.altKey)) && (childSelected || this.props.active()))) || + (!CollectionFreeFormView.RIGHT_BTN_DRAG && + ((e.button === 0 && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && (childSelected || this.props.active())))) { + this.cleanupInteractions(); document.addEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); this._lastX = e.pageX; this._lastY = e.pageY; } } - @action onPointerUp = (e: PointerEvent): void => { - e.stopPropagation(); - this.cleanupInteractions(); } @@ -166,7 +167,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.setPan(x - dx, y - dy); this._lastX = e.pageX; this._lastY = e.pageY; - e.stopPropagation(); + 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(); } } @@ -196,10 +197,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // if (modes[e.deltaMode] === 'pixels') coefficient = 50; // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height?? let deltaScale = (1 - (e.deltaY / coefficient)); - if (deltaScale < 0) deltaScale = -deltaScale; if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling(); } + if (deltaScale < 0) deltaScale = -deltaScale; let [x, y] = this.getTransform().transformPoint(e.clientX, e.clientY); let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y); @@ -212,7 +213,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action setPan(panX: number, panY: number) { - MainOverlayTextBox.Instance.SetTextDoc(); var scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY)); @@ -229,13 +229,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onDragOver = (): void => { } - @action bringToFront(doc: Doc) { - (this.children || []).slice().sort((doc1, doc2) => { + const docs = (this.children || []); + docs.slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; if (doc2 === doc) return -1; - return Cast(doc1.zIndex, "number", 0) - Cast(doc2.zIndex, "number", 0); + return NumCast(doc1.zIndex) - NumCast(doc2.zIndex); }).forEach((doc, index) => doc.zIndex = index + 1); + doc.zIndex = docs.length + 1; return doc; } @@ -249,6 +250,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getDocumentViewProps(document: Doc): DocumentViewProps { return { Document: document, + toggleMinimized: emptyFunction, addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, @@ -289,17 +291,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } + private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.getDocumentViewProps(this.props.Document)} />]; render() { const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; return ( <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel} + style={{ borderRadius: "inherit" }} onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} > + {/* <svg viewBox="0 0 180 18" style={{ top: "50%", opacity: 0.05, position: "absolute" }}> + <text y="15" > + {this.props.Document.Title} + </text> + </svg> */} <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}> <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}> - <CollectionFreeFormBackgroundView {...this.getDocumentViewProps(this.props.Document)} /> <CollectionFreeFormLinksView {...this.props} key="freeformLinks"> <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} > {this.childViews} @@ -356,7 +364,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF const panx = -this.props.panX(); const pany = -this.props.panY(); const zoom = this.props.zoomScaling();// needs to be a variable outside of the <Measure> otherwise, reactions won't fire - return <div className="collectionfreeformview" style={{ transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}> + return <div className="collectionfreeformview" style={{ borderRadius: "inherit", transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}> {this.props.children} </div>; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index bf918beba..c6681e014 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -11,9 +11,9 @@ import { undoBatch } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; -import { MINIMIZED_ICON_SIZE } from '../../../views/globalCssVariables.scss' import "./MarqueeView.scss"; import React = require("react"); +import { Utils } from "../../../../Utils"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -33,18 +33,13 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @observable _lastY: number = 0; @observable _downX: number = 0; @observable _downY: number = 0; - @observable _used: boolean = false; @observable _visible: boolean = false; - _showOnUp: boolean = false; - static DRAG_THRESHOLD = 4; @action cleanupInteractions = (all: boolean = false) => { if (all) { document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); - } else { - this._used = true; } document.removeEventListener("keydown", this.marqueeCommand, true); this._visible = false; @@ -52,34 +47,25 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @action onKeyPress = (e: KeyboardEvent) => { - // Mixing events between React and Native is finicky. In FormattedTextBox, we set the - // DASHFormattedTextBoxHandled flag when a text box consumes a key press so that we can ignore - // the keyPress here. - //if not these keys, make a textbox if preview cursor is active! - if (!e.ctrlKey && !e.altKey && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { - //make textbox and add it to this collection - let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY); - let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "typed text" }); - this.props.addLiveTextDocument(newBox); - PreviewCursor.Visible = false; - e.stopPropagation(); - } - } - hideCursor = () => { - document.removeEventListener("keypress", this.onKeyPress, false); + //make textbox and add it to this collection + let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY); + let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); + this.props.addLiveTextDocument(newBox); + e.stopPropagation(); } @action onPointerDown = (e: React.PointerEvent): void => { - if (e.buttons === 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { - this._downX = this._lastX = e.pageX; - this._downY = this._lastY = e.pageY; - this._used = false; - this._showOnUp = true; - document.removeEventListener("keypress", this.onKeyPress, false); + this._downX = this._lastX = e.pageX; + this._downY = this._lastY = e.pageY; + PreviewCursor.Visible = false; + if ((CollectionFreeFormView.RIGHT_BTN_DRAG && e.button === 0 && !e.altKey && !e.metaKey && this.props.container.props.active()) || + (!CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && this.props.container.props.active())) { document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); } + if (e.altKey) + e.preventDefault(); } @action @@ -87,33 +73,41 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this._lastX = e.pageX; this._lastY = e.pageY; if (!e.cancelBubble) { - if (Math.abs(this._downX - e.clientX) > 4 || Math.abs(this._downY - e.clientY) > 4) { - this._showOnUp = false; - PreviewCursor.Visible = false; - } - if (!this._used && e.buttons === 1 && !e.altKey && !e.metaKey && - (Math.abs(this._lastX - this._downX) > MarqueeView.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > MarqueeView.DRAG_THRESHOLD)) { + if (Math.abs(this._lastX - this._downX) > Utils.DRAG_THRESHOLD || + Math.abs(this._lastY - this._downY) > Utils.DRAG_THRESHOLD) { this._visible = true; + e.stopPropagation(); + e.preventDefault(); } - e.stopPropagation(); - e.preventDefault(); } + if (e.altKey) + e.preventDefault(); } @action onPointerUp = (e: PointerEvent): void => { - this.cleanupInteractions(true); - this._visible = false; - if (this._showOnUp) { - PreviewCursor.Show(this.hideCursor, this._downX, this._downY); - document.addEventListener("keypress", this.onKeyPress, false); - } else { + if (this._visible) { let mselect = this.marqueeSelect(); if (!e.shiftKey) { SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document); } this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } + this.cleanupInteractions(true); + if (e.altKey) + e.preventDefault(); + } + + @action + onClick = (e: React.MouseEvent): void => { + if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && + Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { + PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress); + // let the DocumentView stopPropagation of this event when it selects this document + } else { // why do we get a click event when the cursor have moved a big distance? + // let's cut it off here so no one else has to deal with it. + e.stopPropagation(); + } } intersectRect(r1: { left: number, top: number, width: number, height: number }, @@ -133,15 +127,17 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @undoBatch @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key === "Backspace" || e.key === "Delete") { + if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") { this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); if (ink && ink !== FieldWaiting) { this.marqueeInkDelete(ink.Data); } - this.cleanupInteractions(); + this.cleanupInteractions(true); + e.stopPropagation(); } - if (e.key === "c") { + if (e.key === "c" || e.key === "r" || e.key === "e") { + e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { this.props.removeDocument(d); @@ -152,22 +148,45 @@ export class MarqueeView extends React.Component<MarqueeViewProps> }); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined; - //setTimeout(() => { + let zoomBasis = this.props.container.props.Document.GetNumber(KeyStore.Scale, 1); let newCollection = Documents.FreeformDocument(selected, { x: bounds.left, y: bounds.top, panx: 0, pany: 0, - width: bounds.width, - height: bounds.height, + borderRounding: e.key === "e" ? -1 : undefined, + backgroundColor: selected.length ? "white" : "", + scale: zoomBasis, + width: bounds.width * zoomBasis, + height: bounds.height * zoomBasis, ink: inkData ? this.marqueeInkSelect(inkData) : undefined, title: "a nested collection" }); - this.props.addDocument(newCollection, false); + this.marqueeInkDelete(inkData); - // }, 100); - this.cleanupInteractions(); SelectionManager.DeselectAll(); + if (e.key === "r") { + let summary = Documents.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + summary.GetPrototype()!.CreateLink(newCollection.GetPrototype()!); + this.props.addLiveTextDocument(summary); + e.preventDefault(); + } + else { + this.props.addDocument(newCollection, false); + } + this.cleanupInteractions(true); + } + if (e.key === "s") { + e.stopPropagation(); + e.preventDefault(); + let bounds = this.Bounds; + let selected = this.marqueeSelect(); + SelectionManager.DeselectAll(); + let summary = Documents.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + this.props.addLiveTextDocument(summary); + selected.map(select => summary.GetPrototype()!.CreateLink(select.GetPrototype()!)); + + this.cleanupInteractions(true); } } @action @@ -208,7 +227,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { - var z = doc.GetNumber(KeyStore.Zoom, 1); + var z = doc.GetNumber(KeyStore.ZoomBasis, 1); var x = doc.GetNumber(KeyStore.X, 0); var y = doc.GetNumber(KeyStore.Y, 0); var w = doc.Width() / z; @@ -230,7 +249,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> } render() { - return <div className="marqueeView" onPointerDown={this.onPointerDown}> + return <div className="marqueeView" style={{ borderRadius: "inherit" }} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this.props.children} {!this._visible ? (null) : this.marqueeDiv} </div>; |
