From a8664face6f19cd2373bd928c2a2b3043bb6278d Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 2 Jul 2019 19:02:51 -0400 Subject: Added arrange script to freeform views --- .../collectionFreeForm/CollectionFreeFormView.tsx | 41 +++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 169dbe540..23c0fdd0d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -27,6 +27,10 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); +import { ScriptField } from "../../../../new_fields/ScriptField"; +import { OverlayView } from "../../OverlayView"; +import { ScriptBox } from "../../ScriptBox"; +import { CompileScript } from "../../../util/Scripting"; export const panZoomSchema = createSchema({ @@ -388,6 +392,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } + getCalculatedPositions(doc: Doc, index: number, collection: Doc): { x?: number, y?: number, width?: number, height?: number } | undefined { + const script = Cast(this.props.Document.arrangeScript, ScriptField); + if (!script) { + return undefined; + } + const result = script.script.run({ doc, index, collection }); + if (!result.success) { + return undefined; + } + return result.result; + } + @computed.struct get views() { let curPage = FieldValue(this.Document.curPage, -1); @@ -397,7 +413,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (Math.round(page) === Math.round(curPage) || page === -1) { let minim = BoolCast(doc.isMinimized, false); if (minim === undefined || !minim) { - prev.push(); + const pos = this.getCalculatedPositions(doc, prev.length, this.Document) || {}; + prev.push(); } } return prev; @@ -438,6 +455,28 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } } }); + ContextMenu.Instance.addItem({ + description: "Add freeform arrangement", + event: () => { + let overlayDisposer: () => void; + let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + const script = CompileScript(text, { + params: { + doc: "Doc", index: "number", collection: "Doc" + }, + requiredType: "{x: number, y: number, width?: number, height?: number}", + typecheck: false + }); + if (!script.compiled) { + onError(script.errors.map(error => error.messageText).join("\n")); + return; + } + this.props.Document.arrangeScript = new ScriptField(script); + overlayDisposer(); + }} />; + overlayDisposer = OverlayView.Instance.addElement(scriptingBox, { x: 100, y: 100, width: 200, height: 200 }); + } + }); } private childViews = () => [ -- cgit v1.2.3-70-g09d2 From c619bad0281ea6f248c48b8d418f324f67f530dd Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 3 Jul 2019 12:00:59 -0400 Subject: added to fitToBox to treeviews. fixed some fitToBox issues. moved notifications button to library tree view. --- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- .../dash-nodes/HistogramBoxPrimitives.tsx | 2 - src/client/views/Main.scss | 4 +- src/client/views/MainView.tsx | 84 ++++++++-------------- .../views/collections/CollectionSchemaView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 38 +++++++++- .../views/collections/CollectionVideoView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 5 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/LinkEditor.tsx | 1 - src/client/views/search/SearchItem.tsx | 26 +++---- src/new_fields/Doc.ts | 12 ++++ 13 files changed, 98 insertions(+), 89 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a60eaea85..b81eafbee 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -36,7 +36,7 @@ export class HistogramBox extends React.Component { @computed public get HistogramResult(): HistogramResult { return this.HistoOp.Result as HistogramResult; } @observable public SizeConverter: SizeConverter = new SizeConverter(); - @computed get createOperationParamsCache() { trace(); return this.HistoOp.CreateOperationParameters(); } + @computed get createOperationParamsCache() { return this.HistoOp.CreateOperationParameters(); } @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; } @computed get ChartType() { return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ? diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index 350987695..5a16b3782 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -62,7 +62,6 @@ export class HistogramBoxPrimitives extends React.Component); } render() { - trace(); return
{this.xaxislines} {this.yaxislines} diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 08f5cb8a5..44c1cb9fc 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -111,8 +111,8 @@ button:hover { //toolbar stuff #toolbar { position: absolute; - bottom: 62px; - left: 24px; + right: 8px; + top: 5px; .toolbar-button { display: block; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 19a04595a..1542fedef 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,44 +1,43 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faArrowDown, faArrowUp, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut, faExclamation } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faArrowUp, faBell, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, configure, observable, runInAction, trace } from 'mobx'; +import { action, computed, configure, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { CirclePicker, SliderPicker, BlockPicker, TwitterPicker, SketchPicker } from 'react-color'; import "normalize.css"; import * as React from 'react'; +import { SketchPicker } from 'react-color'; import Measure from 'react-measure'; import * as request from 'request'; +import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; +import { Id } from '../../new_fields/FieldSymbols'; +import { InkTool } from '../../new_fields/InkField'; +import { List } from '../../new_fields/List'; +import { listSpec } from '../../new_fields/Schema'; +import { Cast, FieldValue } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; -import { Docs, DocTypes } from '../documents/Documents'; -import { SetupDrag, DragManager } from '../util/DragManager'; +import { emptyFunction, returnOne, returnTrue } from '../../Utils'; +import { DocServer } from '../DocServer'; +import { Docs } from '../documents/Documents'; +import { SetupDrag } from '../util/DragManager'; +import { HistoryUtil } from '../util/History'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; -import { PresentationView } from './presentationview/PresentationView'; +import { CollectionBaseView } from './collections/CollectionBaseView'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { ContextMenu } from './ContextMenu'; import { DocumentDecorations } from './DocumentDecorations'; +import KeyManager from './GlobalKeyHandler'; import { InkingControl } from './InkingControl'; import "./Main.scss"; import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; +import { OverlayView } from './OverlayView'; +import PDFMenu from './pdf/PDFMenu'; +import { PresentationView } from './presentationview/PresentationView'; import { PreviewCursor } from './PreviewCursor'; import { FilterBox } from './search/FilterBox'; -import { SelectionManager } from '../util/SelectionManager'; -import { FieldResult, Field, Doc, Opt, DocListCast } from '../../new_fields/Doc'; -import { Cast, FieldValue, StrCast, PromiseValue } from '../../new_fields/Types'; -import { DocServer } from '../DocServer'; -import { listSpec } from '../../new_fields/Schema'; -import { Id } from '../../new_fields/FieldSymbols'; -import { HistoryUtil } from '../util/History'; -import { CollectionBaseView } from './collections/CollectionBaseView'; -import { List } from '../../new_fields/List'; -import PDFMenu from './pdf/PDFMenu'; -import { InkTool } from '../../new_fields/InkField'; -import _ from "lodash"; -import KeyManager from './GlobalKeyHandler'; -import { OverlayView } from './OverlayView'; +import { CollectionTreeView } from './collections/CollectionTreeView'; @observer export class MainView extends React.Component { @@ -184,8 +183,6 @@ export class MainView extends React.Component { } } - @observable _notifsCol: Opt; - @action openWorkspace = async (doc: Doc, fromHistory = false) => { CurrentUserUtils.MainDocId = doc[Id]; @@ -197,18 +194,12 @@ export class MainView extends React.Component { if (col) { const l = Cast(col.data, listSpec(Doc)); if (l) { - runInAction(() => this._notifsCol = col); + runInAction(() => CollectionTreeView.NotifsCol = col); } } }, 100); } - openNotifsCol = () => { - if (this._notifsCol && CollectionDockingView.Instance) { - CollectionDockingView.Instance.AddRightSplit(this._notifsCol, undefined); - } - } - onDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -284,24 +275,25 @@ export class MainView extends React.Component { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); } + flyoutWidthFunc = () => this.flyoutWidth; + addDocTabFunc = (doc: Doc) => { + if (doc.dockingConfig) { + this.openWorkspace(doc); + } else { + CollectionDockingView.Instance.AddRightSplit(doc, undefined); + } + }; @computed get flyout() { - let addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => { - if (doc.dockingConfig) { - this.openWorkspace(doc); - } else { - CollectionDockingView.Instance.AddRightSplit(doc, dataDoc); - } - }; return addDocTab(doc, undefined, "onRight")} + addDocTab={this.addDocTabFunc} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} - PanelWidth={this.getPWidth} + PanelWidth={this.flyoutWidthFunc} PanelHeight={this.getPHeight} renderDepth={0} selectOnLoad={false} @@ -403,23 +395,9 @@ export class MainView extends React.Component { /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ @computed get miscButtons() { - const length = this._notifsCol ? DocListCast(this._notifsCol.data).length : 0; - const notifsRef = React.createRef(); - const dragNotifs = action(() => this._notifsCol!); let logoutRef = React.createRef(); return [ -
-
- -
0 ? { "display": "initial" } : { "display": "none" }}> - {length} -
-
-
, this.isSearchVisible ?
: null,
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b0d46953c..d06d1dab6 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -334,7 +334,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @computed get reactTable() { - trace(); let previewWidth = this.previewWidth() + 2 * this.borderWidth + this.DIVIDER_WIDTH + 1; return doc) { } render() { - trace(); return (
this.onDrop(e, {})} onContextMenu={this.onContextMenu} ref={this.createTarget}> @@ -404,6 +402,7 @@ interface CollectionSchemaPreviewProps { Document?: Doc; DataDocument?: Doc; childDocs?: Doc[]; + fitToBox?: () => number[]; renderDepth: number; width: () => number; height: () => number; @@ -472,6 +471,7 @@ export class CollectionSchemaPreview extends React.Component { } ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15); e.stopPropagation(); + e.preventDefault(); } } @@ -312,6 +314,11 @@ class TreeView extends React.Component { return ele; } + fitToBox = () => { + let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc); + let bounds = Doc.ComputeContentBounds(layoutDoc); + return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Math.min(this.props.panelHeight() / (bounds.b - bounds.y), this.props.panelWidth() / (bounds.r - bounds.x))]; + } render() { let contentElement: (JSX.Element | null) = null; let docList = Cast(this.resolvedDataDoc[this._chosenKey], listSpec(Doc)); @@ -333,6 +340,7 @@ class TreeView extends React.Component { Document={layoutDoc} DataDocument={this.resolvedDataDoc} renderDepth={this.props.renderDepth} + fitToBox={this.fitToBox} width={docWidth} height={layoutDoc[HeightSym]} getTransform={this.docTransform} @@ -456,6 +464,31 @@ export class CollectionTreeView extends CollectionSubView(Document) { outerXf = () => Utils.GetScreenTransform(this._mainEle!); onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {}); + + @observable static NotifsCol: Opt; + + openNotifsCol = () => { + if (CollectionTreeView.NotifsCol && CollectionDockingView.Instance) { + CollectionDockingView.Instance.AddRightSplit(CollectionTreeView.NotifsCol, undefined); + } + } + @computed get notifsButton() { + const length = CollectionTreeView.NotifsCol ? DocListCast(CollectionTreeView.NotifsCol.data).length : 0; + const notifsRef = React.createRef(); + const dragNotifs = action(() => CollectionTreeView.NotifsCol!); + return
+
+ +
0 ? { "display": "initial" } : { "display": "none" }}> + {length} +
+
+
; + } + render() { let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before); @@ -480,6 +513,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true); }} /> + {this.props.Document.excludeFromLibrary ? this.notifsButton : (null)}
    { TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove, diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index c1a6ca44e..1984965ba 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -122,7 +122,6 @@ export class CollectionVideoView extends React.Component { } render() { - trace(); return ( {this.subView} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 23c0fdd0d..cb7be3f28 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -54,9 +54,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed get nativeHeight() { return this.Document.nativeHeight || 0; } public get isAnnotationOverlay() { return this.props.fieldKey === "annotations" || this.props.fieldExt === "annotations"; } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } - private panX = () => this.props.fitToBox ? this.props.fitToBox[0] : this.Document.panX || 0; - private panY = () => this.props.fitToBox ? this.props.fitToBox[1] : this.Document.panY || 0; - private zoomScaling = () => this.props.fitToBox ? this.props.fitToBox[2] : this.Document.scale || 1; + private panX = () => this.props.fitToBox ? this.props.fitToBox()[0] : this.Document.panX || 0; + private panY = () => this.props.fitToBox ? this.props.fitToBox()[1] : this.Document.panY || 0; + private zoomScaling = () => this.props.fitToBox ? this.props.fitToBox()[2] : this.Document.scale || 1; private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0; // shift so pan position is at center of window for non-overlay collections private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform()); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3673cb0e2..8b75d0d25 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -71,7 +71,7 @@ export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Doc; DataDoc?: Doc; - fitToBox?: number[]; + fitToBox?: () => number[]; addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean; removeDocument?: (doc: Doc) => boolean; moveDocument?: (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; @@ -573,8 +573,7 @@ export class DocumentView extends DocComponent(Docu @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } @computed get contents() { - return ( - ); + return (); } render() { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 3f5a2e744..c5fc6c65a 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -31,7 +31,7 @@ export interface FieldViewProps { fieldKey: string; fieldExt: string; leaveNativeSize?: boolean; - fitToBox?: number[]; + fitToBox?: () => number[]; ContainingCollectionView: Opt; Document: Doc; DataDoc?: Doc; diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index 22da732cf..e6cc50620 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -271,7 +271,6 @@ export class LinkGroupEditor extends React.Component { ); } - trace(); return (
    diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 5a7bdd24d..129d71b3b 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -101,34 +101,23 @@ export class SearchItem extends React.Component { @observable _useIcons = true; @observable _displayDim = 50; + fitToBox = () => { + let bounds = Doc.ComputeContentBounds(this.props.doc); + return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / Math.max((bounds.b - bounds.y), (bounds.r - bounds.x)), this._displayDim]; + } @computed public get DocumentIcon() { - let layoutresult = StrCast(this.props.doc.type); if (!this._useIcons) { - let renderDoc = this.props.doc; - let box: number[] = []; - if (layoutresult.indexOf(DocTypes.COL) !== -1) { - renderDoc = Doc.MakeDelegate(renderDoc); - let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => { - var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]; - let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()]; - return { - x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), - r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) - }; - }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); - box = [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / (bounds.r - bounds.x), this._displayDim]; - } let returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); let returnYDimension = () => this._displayDim; - let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension()); + let scale = () => returnXDimension() / NumCast(this.props.doc.nativeWidth, returnXDimension()); return
    { this._useIcons = !this._useIcons; this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); })} onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))} onPointerLeave={action(() => this._displayDim = 50)} > {
    ; } + let layoutresult = StrCast(this.props.doc.type); let button = layoutresult.indexOf(DocTypes.PDF) !== -1 ? faFilePdf : layoutresult.indexOf(DocTypes.IMG) !== -1 ? faImage : layoutresult.indexOf(DocTypes.TEXT) !== -1 ? faStickyNote : diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 734a90731..29d35e19f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -249,6 +249,18 @@ export namespace Doc { return true; } + export function ComputeContentBounds(doc: Doc) { + let bounds = DocListCast(doc.data).reduce((bounds, doc) => { + var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]; + let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()]; + return { + x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), + r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) + }; + }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); + return bounds; + } + // // Resolves a reference to a field by returning 'doc' if o field extension is specified, // otherwise, it returns the extension document stored in doc._ext. -- cgit v1.2.3-70-g09d2 From 3cdc6f11e262e289b6070d6fa75a59fff7e59b1e Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 3 Jul 2019 13:42:20 -0400 Subject: Added state to layout scripts --- src/client/views/OverlayView.tsx | 9 +-- src/client/views/ScriptBox.scss | 17 ++++++ src/client/views/ScriptBox.tsx | 10 +++- .../collectionFreeForm/CollectionFreeFormView.tsx | 69 +++++++++++++--------- 4 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 src/client/views/ScriptBox.scss (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 72f1068ce..f8fc94274 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import { observer } from "mobx-react"; import { observable, action } from "mobx"; +import { Utils } from "../../Utils"; export type OverlayDisposer = () => void; @@ -15,7 +16,7 @@ export type OverlayElementOptions = { export class OverlayView extends React.Component { public static Instance: OverlayView; @observable.shallow - private _elements: { ele: JSX.Element, options: OverlayElementOptions }[] = []; + private _elements: { ele: JSX.Element, id: string, options: OverlayElementOptions }[] = []; constructor(props: any) { super(props); @@ -26,7 +27,7 @@ export class OverlayView extends React.Component { @action addElement(ele: JSX.Element, options: OverlayElementOptions): OverlayDisposer { - const eleWithPosition = { ele, options }; + const eleWithPosition = { ele, options, id: Utils.GenerateGuid() }; this._elements.push(eleWithPosition); return action(() => { const index = this._elements.indexOf(eleWithPosition); @@ -37,8 +38,8 @@ export class OverlayView extends React.Component { render() { return (
    - {this._elements.map(({ ele, options: { x, y, width, height } }) => ( -
    {ele}
    + {this._elements.map(({ ele, options: { x, y, width, height }, id }) => ( +
    {ele}
    ))}
    ); diff --git a/src/client/views/ScriptBox.scss b/src/client/views/ScriptBox.scss new file mode 100644 index 000000000..28326624a --- /dev/null +++ b/src/client/views/ScriptBox.scss @@ -0,0 +1,17 @@ +.scriptBox-outerDiv { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; +} + +.scriptBox-toolbar { + width: 100%; +} + +.scriptBox-textArea { + width: 100%; + height: 100%; + box-sizing: border-box; + resize: none; +} \ No newline at end of file diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index aea9d52a4..fa236c2da 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -2,15 +2,23 @@ import * as React from "react"; import { observer } from "mobx-react"; import { observable, action } from "mobx"; +import "./ScriptBox.scss"; + export interface ScriptBoxProps { onSave: (text: string, onError: (error: string) => void) => void; onCancel?: () => void; + initialText?: string; } @observer export class ScriptBox extends React.Component { @observable - private _scriptText: string = ""; + private _scriptText: string; + + constructor(props: ScriptBoxProps) { + super(props); + this._scriptText = props.initialText || ""; + } @action onChange = (e: React.ChangeEvent) => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 23c0fdd0d..edd2fb1b0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -28,7 +28,7 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { ScriptField } from "../../../../new_fields/ScriptField"; -import { OverlayView } from "../../OverlayView"; +import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; @@ -36,7 +36,9 @@ import { CompileScript } from "../../../util/Scripting"; export const panZoomSchema = createSchema({ panX: "number", panY: "number", - scale: "number" + scale: "number", + arrangeScript: ScriptField, + arrangeInit: ScriptField, }); type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema, typeof pageSchema]>; @@ -392,28 +394,34 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - getCalculatedPositions(doc: Doc, index: number, collection: Doc): { x?: number, y?: number, width?: number, height?: number } | undefined { - const script = Cast(this.props.Document.arrangeScript, ScriptField); - if (!script) { - return undefined; - } - const result = script.script.run({ doc, index, collection }); + getCalculatedPositions(doc: Doc, index: number, collection: Doc, script: ScriptField, state: any): { x?: number, y?: number, width?: number, height?: number, state?: any } { + const result = script.script.run({ doc, index, collection, state }); if (!result.success) { - return undefined; + return {}; } - return result.result; + return result.result === undefined ? {} : result.result; } @computed.struct get views() { let curPage = FieldValue(this.Document.curPage, -1); + const initScript = this.Document.arrangeInit; + const script = this.Document.arrangeScript; + let state: any = undefined; + if (initScript) { + const initResult = initScript.script.run(); + if (initResult.success) { + state = initResult.result; + } + } let docviews = this.childDocs.reduce((prev, doc) => { if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); if (Math.round(page) === Math.round(curPage) || page === -1) { let minim = BoolCast(doc.isMinimized, false); if (minim === undefined || !minim) { - const pos = this.getCalculatedPositions(doc, prev.length, this.Document) || {}; + const pos = script ? this.getCalculatedPositions(doc, prev.length, this.Document, script, state) : {}; + state = pos.state === undefined ? state : pos.state; prev.push(); } } @@ -458,23 +466,28 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContextMenu.Instance.addItem({ description: "Add freeform arrangement", event: () => { - let overlayDisposer: () => void; - let scriptingBox = overlayDisposer()} onSave={(text, onError) => { - const script = CompileScript(text, { - params: { - doc: "Doc", index: "number", collection: "Doc" - }, - requiredType: "{x: number, y: number, width?: number, height?: number}", - typecheck: false - }); - if (!script.compiled) { - onError(script.errors.map(error => error.messageText).join("\n")); - return; - } - this.props.Document.arrangeScript = new ScriptField(script); - overlayDisposer(); - }} />; - overlayDisposer = OverlayView.Instance.addElement(scriptingBox, { x: 100, y: 100, width: 200, height: 200 }); + let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record, requiredType?: string) => { + let overlayDisposer: () => void; + const script = this.Document[key]; + let originalText: string | undefined = undefined; + if (script) originalText = script.script.originalScript; + let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + const script = CompileScript(text, { + params, + requiredType, + typecheck: false + }); + if (!script.compiled) { + onError(script.errors.map(error => error.messageText).join("\n")); + return; + } + this.Document[key] = new ScriptField(script); + overlayDisposer(); + }} />; + overlayDisposer = OverlayView.Instance.addElement(scriptingBox, options); + }; + addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300 }, undefined, undefined); + addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300 }, { doc: "Doc", index: "number", collection: "Doc", state:"any" }, "{x: number, y: number, width?: number, height?: number}"); } }); } -- cgit v1.2.3-70-g09d2 From c77dfd3fcb2df644fcf2c177db7e6e376ca4c3a9 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 3 Jul 2019 14:29:53 -0400 Subject: quick and dirty arrange transition animations --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 5 ++++- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index cb7be3f28..6b0cb5728 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, DocListCastAsync, HeightSym, WidthSym } from "../../../../new_fields/Doc"; +import { Doc, DocListCastAsync, HeightSym, WidthSym, DocListCast } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { createSchema, makeInterface } from "../../../../new_fields/Schema"; @@ -458,6 +458,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContextMenu.Instance.addItem({ description: "Add freeform arrangement", event: () => { + const docs = DocListCast(this.Document[this.props.fieldKey]); + docs.map(d => d.transition = "transform 1s"); let overlayDisposer: () => void; let scriptingBox = overlayDisposer()} onSave={(text, onError) => { const script = CompileScript(text, { @@ -473,6 +475,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } this.props.Document.arrangeScript = new ScriptField(script); overlayDisposer(); + setTimeout(() => docs.map(d => d.transition = undefined), 1200); }} />; overlayDisposer = OverlayView.Instance.addElement(scriptingBox, { x: 100, y: 100, width: 200, height: 200 }); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3f9270597..30cf74f3e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,7 +1,7 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { BoolCast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { BoolCast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView"; @@ -86,6 +86,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Wed, 3 Jul 2019 19:22:16 -0400 Subject: Added params to init script and added docs param to layout script --- .../collectionFreeForm/CollectionFreeFormView.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ba41b5afe..4b7d462e5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -394,8 +394,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - getCalculatedPositions(doc: Doc, index: number, collection: Doc, script: ScriptField, state: any): { x?: number, y?: number, width?: number, height?: number, state?: any } { - const result = script.script.run({ doc, index, collection, state }); + getCalculatedPositions(script: ScriptField, params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, width?: number, height?: number, state?: any } { + const result = script.script.run(params); if (!result.success) { return {}; } @@ -408,19 +408,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const initScript = this.Document.arrangeInit; const script = this.Document.arrangeScript; let state: any = undefined; + const docs = this.childDocs; if (initScript) { - const initResult = initScript.script.run(); + const initResult = initScript.script.run({ docs, collection: this.Document }); if (initResult.success) { state = initResult.result; } } - let docviews = this.childDocs.reduce((prev, doc) => { + let docviews = docs.reduce((prev, doc) => { if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); if (Math.round(page) === Math.round(curPage) || page === -1) { let minim = BoolCast(doc.isMinimized, false); if (minim === undefined || !minim) { - const pos = script ? this.getCalculatedPositions(doc, prev.length, this.Document, script, state) : {}; + const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) : {}; state = pos.state === undefined ? state : pos.state; prev.push(); } @@ -489,8 +490,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }} />; overlayDisposer = OverlayView.Instance.addElement(scriptingBox, options); }; - addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300 }, undefined, undefined); - addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300 }, { doc: "Doc", index: "number", collection: "Doc", state: "any" }, "{x: number, y: number, width?: number, height?: number}"); + addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300 }, { collection: "Doc", docs: "Doc[]" }, undefined); + addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300 }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); } }); } -- cgit v1.2.3-70-g09d2 From 336266551d363df8c4958d485170846b478f1787 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 5 Jul 2019 11:54:39 -0400 Subject: fixed templates (old style) a bit. --- deploy/assets/downarrow.png | Bin 0 -> 3363 bytes src/client/views/Templates.tsx | 3 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- src/client/views/nodes/DocumentContentsView.tsx | 5 ++++- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 deploy/assets/downarrow.png (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/deploy/assets/downarrow.png b/deploy/assets/downarrow.png new file mode 100644 index 000000000..3c59ff5b1 Binary files /dev/null and b/deploy/assets/downarrow.png differ diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 4843a70a6..236704fa2 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -69,8 +69,7 @@ export namespace Templates { `< div >
    {layout}
    - +
    ` ); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4b7d462e5..7c0591600 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -468,8 +468,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { description: "Add freeform arrangement", event: () => { let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record, requiredType?: string) => { - const docs = DocListCast(this.Document[this.props.fieldKey]); - docs.map(d => d.transition = "transform 1s"); let overlayDisposer: () => void; const script = this.Document[key]; let originalText: string | undefined = undefined; @@ -484,6 +482,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onError(script.errors.map(error => error.messageText).join("\n")); return; } + const docs = DocListCast(this.Document[this.props.fieldKey]); + docs.map(d => d.transition = "transform 1s"); this.Document[key] = new ScriptField(script); overlayDisposer(); setTimeout(() => docs.map(d => d.transition = undefined), 1200); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 0da4888a1..51d0c83cd 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -24,6 +24,7 @@ import { Without, OmitKeys } from "../../../Utils"; import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc } from "../../../new_fields/Doc"; +import { CollectionViewType } from "../collections/CollectionBaseView"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without; @@ -82,7 +83,8 @@ export class DocumentContentsView extends React.Component { let self = this; // this scales constants in the markup by the scaling applied to the document, but caps the constants to be smaller @@ -103,6 +105,7 @@ export class DocumentContentsView extends React.Component 7) return (null); if (!this.layout && (this.props.layoutKey !== "overlayLayout" || !this.templates.length)) return (null); return Date: Mon, 8 Jul 2019 10:54:53 -0400 Subject: fixed annotation dragging on PDFs. fixed panning after zooming on images. --- src/client/util/DragManager.ts | 1 + src/client/views/collections/CollectionSubView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 12 ++++-------- src/client/views/pdf/PDFMenu.tsx | 19 +++++++------------ src/client/views/pdf/Page.tsx | 4 ++-- 5 files changed, 15 insertions(+), 22 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index ce1f9d890..a269d7eba 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -321,6 +321,7 @@ export namespace DragManager { dragElement.style.top = "0"; dragElement.style.bottom = ""; dragElement.style.left = "0"; + dragElement.style.transition = "none"; dragElement.style.color = "black"; dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 79c23d71a..5287d3c13 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -102,6 +102,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { return added; } else if (de.data instanceof DragManager.AnnotationDragData) { + e.stopPropagation(); return this.props.addDocument(de.data.dropDocument); } return false; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7c0591600..7a22b7ec3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -249,16 +249,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { 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)); - // this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; - // this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; - this.props.Document.panX = panX; + this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; + this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; + // this.props.Document.panX = panX; + // this.props.Document.panY = panY; if (this.props.Document.scrollY) { this.props.Document.scrollY = panY; - this.props.Document.panY = panY; - } - else { - - this.props.Document.panY = panY; } } diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index f93b2e59f..d6970e7f4 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -3,11 +3,8 @@ import "./PDFMenu.scss"; import { observable, action, runInAction } from "mobx"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { emptyFunction, returnZero, returnTrue, returnFalse } from "../../../Utils"; +import { emptyFunction, returnFalse } from "../../../Utils"; import { Doc } from "../../../new_fields/Doc"; -import { DragManager } from "../../util/DragManager"; -import { DocUtils } from "../../documents/Documents"; -import { PresentationView } from "../presentationview/PresentationView"; @observer export default class PDFMenu extends React.Component { @@ -20,7 +17,7 @@ export default class PDFMenu extends React.Component { @observable private _transitionDelay: string = ""; - StartDrag: (e: PointerEvent) => void = emptyFunction; + StartDrag: (e: PointerEvent, ele: HTMLDivElement) => void = emptyFunction; Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; Delete: () => void = emptyFunction; Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; @@ -35,9 +32,10 @@ export default class PDFMenu extends React.Component { private _offsetY: number = 0; private _offsetX: number = 0; - private _mainCont: React.RefObject; + private _mainCont: React.RefObject = React.createRef(); + private _commentCont: React.RefObject = React.createRef(); + private _snippetButton: React.RefObject = React.createRef(); private _dragging: boolean = false; - private _snippetButton: React.RefObject; @observable private _keyValue: string = ""; @observable private _valueValue: string = ""; @observable private _added: boolean = false; @@ -46,9 +44,6 @@ export default class PDFMenu extends React.Component { super(props); PDFMenu.Instance = this; - - this._mainCont = React.createRef(); - this._snippetButton = React.createRef(); } pointerDown = (e: React.PointerEvent) => { @@ -69,7 +64,7 @@ export default class PDFMenu extends React.Component { return; } - this.StartDrag(e); + this.StartDrag(e, this._commentCont.current!); this._dragging = true; } @@ -246,7 +241,7 @@ export default class PDFMenu extends React.Component { style={this.Highlighting ? { backgroundColor: "#121212" } : {}}> , - , + , this.Status === "snippet" ? : undefined,