From a2eb8ba283ce4a8fb7f423a9198e2a5778eba886 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Mon, 4 May 2020 12:18:11 +0530 Subject: updating from master --- src/client/views/nodes/ContentFittingDocumentView.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 641797cac..814f8fd9c 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -43,6 +43,7 @@ interface ContentFittingDocumentViewProps { pinToPres: (document: Doc) => void; dontRegisterView?: boolean; rootSelected: (outsideReaction?: boolean) => boolean; + Display?: string; } @observer @@ -77,7 +78,8 @@ export class ContentFittingDocumentView extends React.Component 0.001 ? "auto" : this.props.PanelWidth(), - height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight() + height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(), + display: this.props.Display /* just added for grid */ }}> {!this.props.Document || !this.props.PanelWidth ? (null) : (
Date: Sun, 24 May 2020 10:36:31 +0530 Subject: Added chrome to grid view and modified grid mechanism --- src/client/views/collections/CollectionView.tsx | 1 + .../views/collections/CollectionViewChromes.scss | 30 ++- .../views/collections/CollectionViewChromes.tsx | 57 ++++- .../collectionGrid/CollectionGridView.tsx | 248 ++++++++++++--------- .../views/collections/collectionGrid/Grid.tsx | 8 + .../views/nodes/ContentFittingDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 1 + 7 files changed, 225 insertions(+), 122 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5b344813d..311e8d3a1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -227,6 +227,7 @@ export class CollectionView extends Touchable func(CollectionViewType.Carousel), icon: "columns" }); subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); + subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "border-all" }); if (addExtras && this.props.Document._viewType === CollectionViewType.Freeform) { subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); } diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index e4581eb46..9795a3a22 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -3,7 +3,7 @@ .collectionViewChrome-cont { position: absolute; - width:100%; + width: 100%; opacity: 0.9; z-index: 9001; transition: top .5s; @@ -33,7 +33,7 @@ outline-color: black; } - .collectionViewBaseChrome-button{ + .collectionViewBaseChrome-button { font-size: 75%; text-transform: uppercase; letter-spacing: 2px; @@ -44,6 +44,7 @@ padding: 12px 10px 11px 10px; margin-left: 10px; } + .collectionViewBaseChrome-cmdPicker { margin-left: 3px; margin-right: 0px; @@ -51,14 +52,16 @@ border: none; color: grey; } + .commandEntry-outerDiv { pointer-events: all; background-color: gray; display: flex; flex-direction: row; + .commandEntry-drop { - color:white; - width:25px; + color: white; + width: 25px; margin-top: auto; margin-bottom: auto; } @@ -72,15 +75,17 @@ pointer-events: all; // margin-top: 10px; } + .collectionViewBaseChrome-template, .collectionViewBaseChrome-viewModes { display: grid; background: rgb(238, 238, 238); - color:grey; - margin-top:auto; - margin-bottom:auto; + color: grey; + margin-top: auto; + margin-bottom: auto; margin-left: 5px; } + .collectionViewBaseChrome-viewModes { margin-left: 25px; } @@ -88,7 +93,7 @@ .collectionViewBaseChrome-viewSpecs { margin-left: 5px; display: grid; - + .collectionViewBaseChrome-filterIcon { position: relative; display: flex; @@ -202,7 +207,7 @@ .collectionStackingViewChrome-pivotField, .collectionTreeViewChrome-pivotField { color: white; - width:100%; + width: 100%; min-width: 100px; text-align: center; background: rgb(238, 238, 238); @@ -232,6 +237,10 @@ .collectionTreeViewChrome-pivotField:hover { cursor: text; } + + .collectionGridViewChrome-entryBox { + width: 50%; + } } } @@ -292,8 +301,9 @@ flex-direction: column; height: 40px; } + .commandEntry-inputArea { - display:flex; + display: flex; flex-direction: row; width: 150px; margin: auto auto auto auto; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 5dc0b09ac..def20ae9b 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -2,7 +2,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast } from "../../../fields/Doc"; +import { Doc, DocListCast, HeightSym } from "../../../fields/Doc"; import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; @@ -15,6 +15,8 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss"; import { CollectionViewType } from "./CollectionView"; import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; +import { CollectionGridView } from "./collectionGrid/CollectionGridView"; +import HeightLabel from "./collectionMulticolumn/MultirowHeightLabel"; const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { @@ -205,6 +207,7 @@ export class CollectionViewBaseChrome extends React.Component); case CollectionViewType.Tree: return (); case CollectionViewType.Masonry: return (); + case CollectionViewType.Grid: return (); default: return null; } } @@ -504,3 +507,55 @@ export class CollectionTreeViewChrome extends React.Component { + + /** + * Sets the value of `numCols` on the grid's Document to the value entered. + */ + @action + onNumColsEnter = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === "Tab") { + if (this.props.CollectionView.props.Document.numCols as number !== e.currentTarget.valueAsNumber) { + this.props.CollectionView.props.Document.numCols = e.currentTarget.valueAsNumber; + //this.props.CollectionView.forceUpdate(); // to be used if CollectionGridView is not an observer + } + + } + } + + /** + * Sets the value of `rowHeight` on the grid's Document to the value entered. + */ + @action + onRowHeightEnter = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === "Tab") { + if (this.props.CollectionView.props.Document.rowHeight as number !== e.currentTarget.valueAsNumber) { + this.props.CollectionView.props.Document.rowHeight = e.currentTarget.valueAsNumber; + //this.props.CollectionView.forceUpdate(); + } + } + } + + render() { + return ( +
+ + + + + + + + + + + + +
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index cd1e0f7f0..ebb710af6 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -1,39 +1,58 @@ -import { action, computed, observable } from 'mobx'; -import { observer } from 'mobx-react'; +import { computed, observable, action } from 'mobx'; import * as React from "react"; -import { Doc, DataSym, DocListCast } from '../../../../new_fields/Doc'; -import { documentSchema } from '../../../../new_fields/documentSchemas'; -import { makeInterface } from '../../../../new_fields/Schema'; -import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../new_fields/Types'; +import { Doc, DocListCast } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; +import { makeInterface, createSchema } from '../../../../fields/Schema'; +import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../fields/Types'; import { DragManager } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView'; import { CollectionSubView } from '../CollectionSubView'; -import { List } from '../../../../new_fields/List'; +import { SubCollectionViewProps } from '../CollectionSubView'; +import { List } from '../../../../fields/List'; import { returnZero } from '../../../../Utils'; -import Grid from "./Grid"; -import { Layout } from "./Grid"; +import Grid, { Layout } from "./Grid"; +import { Id } from '../../../../fields/FieldSymbols'; +import { observer } from 'mobx-react'; type GridSchema = makeInterface<[typeof documentSchema]>; const GridSchema = makeInterface(documentSchema); +@observer export class CollectionGridView extends CollectionSubView(GridSchema) { - private layouts: Layout[] = []; - private layoutDocs: Doc[] = []; - @observable private numCols: number = 10; - @observable private rowHeight: number = 100; - @observable private isMounted: boolean = false; + constructor(props: Readonly) { + super(props); - componentDidMount() { - this.isMounted = true; + this.props.Document.numCols = this.props.Document.numCols ? this.props.Document.numCols : 10; + this.props.Document.rowHeight = this.props.Document.rowHeight ? this.props.Document.rowHeight : 100; } - componentWillUnmount() { - this.isMounted = false; - console.log("hola"); + componentDidMount() { + if (!(this.props.Document.gridLayouts as List)?.length) { + + console.log("no layouts stored on doc"); + + this.props.Document.gridLayouts = new List(); + + for (let i = 0; i < this.childLayoutPairs.length; i++) { + + const layoutDoc: Doc = new Doc(); + layoutDoc.i = layoutDoc[Id]; + layoutDoc.x = 2 * (i % 5); + layoutDoc.y = 2 * Math.floor(i / 5); + layoutDoc.w = 2; + layoutDoc.h = 2; + + (this.props.Document.gridLayouts as List).push(layoutDoc); + + // use childlayoutpairs length instead + } + + } + } /** @@ -42,18 +61,26 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { * the sum of all the resolved column widths of the * documents before the target. */ - private lookupIndividualTransform = (layout: Layout) => { + private lookupIndividualTransform = (doc: Doc) => { - const yTranslation = this.rowHeight * layout.y;// + 15 * (layout.y - 1); - console.log(yTranslation); - return this.props.ScreenToLocalTransform().translate(-this.props.PanelWidth() / this.numCols * layout.x, -yTranslation); + const yTranslation = (this.props.Document.rowHeight as number) * (doc.y as number) + 10 * (doc.y as number); + return this.props.ScreenToLocalTransform().translate(-this.props.PanelWidth() / (this.props.Document.numCols as number) * (doc.x as number), -yTranslation); } @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } - @observable private width = (layout: Layout) => layout.w * this.props.PanelWidth() / this.numCols; - @observable private height = (layout: Layout) => layout.h * this.rowHeight; + /** + * Sets the width of the decorating box. + * @param Doc doc + */ + @observable private width = (doc: Doc) => doc.w as number * this.props.PanelWidth() / (this.props.Document.numCols as number); + + /** + * Sets the height of the decorating box. + * @param doc `Doc` + */ + @observable private height = (doc: Doc) => doc.h as number * (this.props.Document.rowHeight as number); addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { @@ -81,15 +108,23 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { onClick={this.onChildClickHandler} renderDepth={this.props.renderDepth + 1} parentActive={this.props.active} - //Display={"contents"} + display={"contents"} />; } - //@action + /** + * Saves the layouts received from the Grid to the Document. + * @param layouts `Layout[]` + */ set layout(layouts: Layout[]) { - this.layouts = layouts; - this.props.Document.gridLayouts = new List(); + + console.log("setting layout in CollectionGridView"); + console.log(layouts?.[0].w); + //this.props.Document.gridLayouts = new List(); + + const docList: Doc[] = []; + for (const layout of layouts) { const layoutDoc = new Doc(); layoutDoc.i = layout.i; @@ -98,126 +133,119 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { layoutDoc.w = layout.w; layoutDoc.h = layout.h; - (this.props.Document.gridLayouts as List).push(layoutDoc); - console.log("gazoinks"); - + docList.push(layoutDoc); } - this.forceUpdate(); // better way to do this? + + this.props.Document.gridLayouts = new List(docList); } - get layout() { - //console.log(this.layouts.length === 0); - if (this.layouts.length === 0) { - if (this.props.Document.gridLayouts) { - //console.log(this.props.Document.gridLayouts); - // for (const layout of (this.props.Document.gridLayouts as List)) { - // if (layout instanceof Doc) { - // this.layouts.push( - // { i: layout.i as string, x: layout.x as number, y: layout.y as number, w: layout.w as number, h: layout.h as number } - // ); - // } - // else { - // layout.then((layout: Doc) => { - // this.layouts.push( - // { i: layout.i as string, x: layout.x as number, y: layout.y as number, w: layout.w as number, h: layout.h as number } - // ); - // console.log(layout.i); - // }); - // } - // } - // } - for (const layout of DocListCast(this.props.Document.gridLayouts)) { - this.layouts.push( - { i: layout.i as string, x: layout.x as number, y: layout.y as number, w: layout.w as number, h: layout.h as number } - ); - } - } - else { - for (let i = 0; i < this.childLayoutPairs.length; i++) { - this.layouts.push( - { i: 'wrapper' + i, x: 2 * (i % 5), y: 2 * Math.floor(i / 5), w: 2, h: 2 } - ); - - const layoutDoc: Doc = new Doc(); - layoutDoc.i = "wrapper" + i; - layoutDoc.x = 2 * (i % 5); - layoutDoc.y = 2 * Math.floor(i / 5); - layoutDoc.w = 2; - layoutDoc.h = 2; - - this.layoutDocs.push(layoutDoc); - this.props.Document.highest = i; - } - this.props.Document.gridLayouts = new List(this.layoutDocs); - } - } + // _.reject() on item removal? - return this.layouts; - } + /** + * @returns a list of `ContentFittingDocumentView`s inside wrapper divs. + * The key of the wrapper div must be the same as the `i` value of the corresponding layout. + */ @computed - private get contents(): [JSX.Element[], Layout[]] { + private get contents(): JSX.Element[] { const { childLayoutPairs } = this; const collector: JSX.Element[] = []; - const layoutArray: Layout[] = []; + //const layoutArray: Layout[] = []; + const docList: Doc[] = DocListCast(this.props.Document.gridLayouts); - const previousLength = this.layout.length; - layoutArray.push(...this.layout); + const previousLength = docList.length; + // layoutArray.push(...this.layout); - if (!layoutArray.length) { - return [[], []]; - } - - if (this.childLayoutPairs.length > previousLength) { - layoutArray.push( - { i: 'wrapper' + previousLength, x: 2 * (previousLength % 5), y: 2 * Math.floor(previousLength / 5), w: 2, h: 2 } - // add values to document - ); - // this.layout.push( - // { i: 'wrapper' + previousLength, x: 2 * (previousLength % 5), y: 2 * Math.floor(previousLength / 5), w: 2, h: 2 } - // ); + if (!previousLength) { + // console.log("early return"); + return []; } for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const dxf = () => this.lookupIndividualTransform(layoutArray[i]);//.translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)); - const width = () => this.width(layoutArray[i]); //this.lookupPixels(layout); - const height = () => this.height(layoutArray[i]);//PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); + const dxf = () => this.lookupIndividualTransform(docList?.[i]); + const width = () => this.width(docList?.[i]); + const height = () => this.height(docList?.[i]); collector.push(
{this.getDisplayDoc(layout, dxf, width, height)}
); } - return [collector, layoutArray]; + return collector; + } + + /** + * @returns a list of Layouts from a list of Docs + * @param docLayoutList `Doc[]` + */ + toLayoutList(docLayoutList: Doc[]): Layout[] { + + const layouts: Layout[] = []; + for (const layout of docLayoutList) { + layouts.push( + { i: layout.i as string, x: layout.x as number, y: layout.y as number, w: layout.w as number, h: layout.h as number } + ); + } + return layouts; + } + + /** + * Checks whether a new node has been added to the grid and updates the Document accordingly. + */ + checkUpdate() { + const previousLength = (this.props.Document.gridLayouts as List)?.length; + if (this.childLayoutPairs.length > previousLength) { + console.log("adding doc"); + const layoutDoc: Doc = new Doc(); + layoutDoc.i = layoutDoc[Id]; + layoutDoc.x = 2 * (previousLength % 5); + layoutDoc.y = 2 * Math.floor(previousLength / 5); + layoutDoc.w = 2; + layoutDoc.h = 2; + + (this.props.Document.gridLayouts as List).push(layoutDoc); + } } render(): JSX.Element { - const contents: JSX.Element[] = this.contents?.[0]; - const layout: Layout[] = this.contents?.[1]; - // if (this.isMounted) { + this.checkUpdate(); + + const contents: JSX.Element[] = this.contents; + const layout: Layout[] = this.toLayoutList(DocListCast(this.props.Document.gridLayouts)); + + if (layout.length === 0) { + console.log("layouts not loaded"); + } + else { + console.log("rendering with this"); + console.log(layout[0].w); + } + + return (
- + }} + ref={this.createDashEventsTarget} + onPointerDown={(e: React.PointerEvent) => e.stopPropagation()} + >
); - // } } } diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index ce0173e94..d400f2810 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -20,9 +20,16 @@ interface GridProps { rowHeight: number; } +/** + * Wrapper around the actual GridLayout of `react-grid-layout`. + */ @observer export default class Grid extends React.Component { + /** + * If there has been a change in layout, calls a method in CollectionGridView to set the layouts on the Document. + * @param layout `Layout[]` + */ onLayoutChange(layout: Layout[]) { this.props.gridView.layout = layout; } @@ -36,6 +43,7 @@ export default class Grid extends React.Component this.onLayoutChange(layout)} > {this.props.nodeList} diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 39097865a..77555061f 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -83,7 +83,7 @@ export class ContentFittingDocumentView extends React.Component 0.001 ? "auto" : this.props.PanelWidth(), height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(), - display: this.props.Display /* just added for grid */ + display: this.props.display /* just added for grid */ }}> {!this.props.Document || !this.props.PanelWidth ? (null) : (
Date: Wed, 27 May 2020 13:53:18 -0400 Subject: fixed ineracting with documents selected in GridView --- src/client/views/collections/collectionGrid/CollectionGridView.tsx | 3 ++- src/client/views/collections/collectionGrid/Grid.tsx | 3 +++ src/client/views/nodes/DocumentView.tsx | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index bc554e2c2..a55d5a8ac 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -240,7 +240,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { style={{ marginLeft: NumCast(this.props.Document._xMargin), marginRight: NumCast(this.props.Document._xMargin), marginTop: NumCast(this.props.Document._yMargin), marginBottom: NumCast(this.props.Document._yMargin), - pointerEvents: !this.props.isSelected() && !this.props.ContainingCollectionView?._isChildActive && !SnappingManager.GetIsDragging() ? "none" : undefined + pointerEvents: !this.props.isSelected() && this.props.renderDepth !== 0 && !this.props.ContainingCollectionView?._isChildActive && !SnappingManager.GetIsDragging() ? "none" : undefined }} ref={this.createDashEventsTarget} onPointerDown={e => e.stopPropagation()} @@ -249,6 +249,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { width={this.props.PanelWidth()} nodeList={contents} layout={layout} + transformScale={this.props.ScreenToLocalTransform().Scale} numCols={this.props.Document.numCols as number} rowHeight={this.props.Document.rowHeight as number} setLayout={(layout: Layout[]) => this.setLayout(layout)} diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index a5f5c724a..9c66d1e33 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -18,6 +18,7 @@ interface GridProps { numCols: number; rowHeight: number; setLayout: Function; + transformScale: number; } /** @@ -35,6 +36,7 @@ export default class Grid extends React.Component { this.props.setLayout(layout); } + Scale = 2 render() { console.log("In grid layout prop received value= " + this.props.layout?.[0]?.w); return ( @@ -45,6 +47,7 @@ export default class Grid extends React.Component { width={this.props.width} compactType={null} isDroppable={true} + useCSSTransforms={true} margin={[10, 10]} onLayoutChange={layout => this.onLayoutChange(layout)} > diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b5de0af12..79b560118 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -517,6 +517,7 @@ export class DocumentView extends DocComponent(Docu if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); + e.preventDefault(); // TODO: check here for panning/inking } return; @@ -531,7 +532,7 @@ export class DocumentView extends DocComponent(Docu (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && !this.Document.inOverlay) { e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); - + e.preventDefault(); } document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); -- cgit v1.2.3-70-g09d2 From efaa44cacf9cf8506209c9bf1437e36828132eea Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 27 May 2020 15:17:01 -0400 Subject: fixed layout and interactions of grid view --- .../collectionGrid/CollectionGridView.scss | 13 ++++---- .../collectionGrid/CollectionGridView.tsx | 37 ++++++++++------------ src/client/views/nodes/DocumentView.tsx | 6 ++-- 3 files changed, 26 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.scss b/src/client/views/collections/collectionGrid/CollectionGridView.scss index 8f12c1a24..c0a2cbc22 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.scss +++ b/src/client/views/collections/collectionGrid/CollectionGridView.scss @@ -4,11 +4,10 @@ width: 100%; height: 100%; flex-direction: column; - - .document-wrapper { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - } +} +.collectionGridView_contents .document-wrapper { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; } \ No newline at end of file diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index a55d5a8ac..03ba9d004 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -94,25 +94,22 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { } getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { - return
- -
; + return ; } @@ -243,7 +240,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { pointerEvents: !this.props.isSelected() && this.props.renderDepth !== 0 && !this.props.ContainingCollectionView?._isChildActive && !SnappingManager.GetIsDragging() ? "none" : undefined }} ref={this.createDashEventsTarget} - onPointerDown={e => e.stopPropagation()} + onPointerDown={e => { ((e.target as any)?.className.includes("react-resizable-handle")) && e.stopPropagation(); }} > (Docu if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); - e.preventDefault(); + if (SelectionManager.IsSelected(this, true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it // TODO: check here for panning/inking } return; @@ -531,8 +531,8 @@ export class DocumentView extends DocComponent(Docu !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && !this.Document.inOverlay) { - e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); - e.preventDefault(); + e.stopPropagation(); + if (SelectionManager.IsSelected(this, true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it } document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); -- cgit v1.2.3-70-g09d2 From 34d43b0d7ff1829514566e2b6b8514f6176e7c60 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 9 Jun 2020 11:48:22 -0400 Subject: fixed keyFrame animation positioning issues when adding a doc at t != 0. added isInkMask field and inkStroke menu option to create an ink mask. added cantLeaveCollection flag. --- src/client/views/InkingStroke.tsx | 21 +++++++++++++++------ src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 3 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 17 ++++++++--------- src/fields/documentSchemas.ts | 2 ++ 6 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index b545ede54..7dac2e3b5 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -31,6 +31,14 @@ export class InkingStroke extends ViewBoxBaseComponent { + this.props.Document._backgroundColor = "rgba(0,0,0,0.7)"; + this.props.Document.mixBlendMode = "hard-light"; + this.props.Document.color = "#9b9b9bff"; + this.props.Document.cantLeaveCollection = true; + this.props.Document.isInkMask = true; + } + render() { TraceMobx(); const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; @@ -52,13 +60,14 @@ export class InkingStroke extends ViewBoxBaseComponent { - ContextMenu.Instance.addItem({ - description: "Analyze Stroke", - event: this.analyzeStrokes, - icon: "paint-brush" - }); + ContextMenu.Instance.addItem({ description: "Analyze Stroke", event: this.analyzeStrokes, icon: "paint-brush" }); + ContextMenu.Instance.addItem({ description: "Make Mask", event: this.makeMask, icon: "paint-brush" }); }} > {points} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 167bce131..47d571bcc 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -221,7 +221,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } else { added = this.addDocument(docDragData.droppedDocuments); } - e.stopPropagation(); + added && e.stopPropagation(); return added; } else if (de.complete.annoDragData) { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 3330abbc4..7f2b5ff8e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -163,7 +163,8 @@ export class CollectionView extends Touchable { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 379156179..d512f815c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -202,7 +202,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); - zsorted.forEach((doc, index) => doc.zIndex = index + 1); + zsorted.forEach((doc, index) => doc.zIndex = doc.isInkMask ? 5000 : index + 1); const dropPos = [NumCast(docDragData.droppedDocuments[0].x), NumCast(docDragData.droppedDocuments[0].y)]; for (let i = 0; i < docDragData.droppedDocuments.length; i++) { const d = docDragData.droppedDocuments[i]; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 910aa744d..77a2e04e6 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -36,7 +36,8 @@ export class CollectionFreeFormDocumentView extends DocComponent(numberRange(timecode + 1).map(i => undefined) as any as number[]); const ylist = new List(numberRange(timecode + 1).map(i => undefined) as any as number[]); const olist = new List(numberRange(timecode + 1).map(t => progressivize && t < i ? 0 : 1)); - xlist[Math.max(curTimecode - 1, 0)] = xlist[curTimecode] = NumCast(doc.x); - ylist[Math.max(curTimecode - 1, 0)] = ylist[curTimecode] = NumCast(doc.y); + xlist[curTimecode] = NumCast(doc.x); + ylist[curTimecode] = NumCast(doc.y); doc["x-indexed"] = xlist; doc["y-indexed"] = ylist; doc["opacity-indexed"] = olist; - doc.activeFrame = ComputedField.MakeFunction("self.context ? (self.context.currentFrame||0) : 0"); + doc.activeFrame = ComputedField.MakeFunction("self.context?.currentFrame||0"); doc.x = ComputedField.MakeInterpolated("x", "activeFrame"); doc.y = ComputedField.MakeInterpolated("y", "activeFrame"); doc.opacity = ComputedField.MakeInterpolated("opacity", "activeFrame"); @@ -151,12 +150,12 @@ export class CollectionFreeFormDocumentView extends DocComponent {Doc.UserDoc().renderStyle !== "comic" ? (null) :
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 6474ed148..353333028 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -58,6 +58,7 @@ export const documentSchema = createSchema({ color: "string", // foreground color of document fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view fontSize: "string", + isInkMask: "boolean", // is the document a mask (ie, sits on top of other documents, has an unbounded width/height that is dark, and content uses 'hard-light' mix-blend-mode to let other documents pop through) layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below layoutKey: "string", // holds the field key for the field that actually holds the current lyoat letterSpacing: "string", @@ -83,6 +84,7 @@ export const documentSchema = createSchema({ _lockedTransform: "boolean",// whether a freeformview can pan/zoom // drag drop properties + cantLeaveCollection: "boolean",// whether document can be dropped into a different collection dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move' -- cgit v1.2.3-70-g09d2 From 747581ac65f706710becad034c5f5abff76b8e51 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 9 Jun 2020 17:26:05 -0400 Subject: fixed lots of errors/warnings. added 'a' to be able embed documents on drop. added 'l' toggle to perist lasso/marquee mode. --- src/client/apis/youtube/YoutubeBox.tsx | 3 +- src/client/documents/Documents.ts | 2 +- src/client/util/DragManager.ts | 50 +++++++++++++++------- .../util/Import & Export/DirectoryImportBox.tsx | 4 +- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 1 + src/client/views/InkingStroke.tsx | 4 +- src/client/views/TemplateMenu.tsx | 4 +- src/client/views/animationtimeline/Keyframe.tsx | 8 ++-- src/client/views/animationtimeline/Timeline.tsx | 2 +- .../views/animationtimeline/TimelineOverview.tsx | 4 +- .../views/collections/CollectionPileView.tsx | 7 +-- .../views/collections/CollectionStackingView.tsx | 3 +- .../CollectionStackingViewFieldColumn.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 4 +- .../views/collections/CollectionTimeView.tsx | 3 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/CollectionViewChromes.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +++--- .../collectionFreeForm/MarqueeView.scss | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 9 ++-- src/client/views/nodes/ScreenshotBox.tsx | 3 +- src/client/views/nodes/VideoBox.tsx | 2 +- .../views/nodes/formattedText/DashDocView.tsx | 4 +- .../views/nodes/formattedText/DashFieldView.tsx | 7 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- .../views/nodes/formattedText/RichTextSchema.tsx | 4 +- src/client/views/webcam/DashWebRTCVideo.tsx | 3 +- src/fields/Doc.ts | 4 +- src/fields/RichTextUtils.ts | 6 +-- src/server/ApiManagers/UploadManager.ts | 3 +- 31 files changed, 96 insertions(+), 75 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index 748d571c0..2a1f55710 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -10,6 +10,7 @@ import { FieldView, FieldViewProps } from "../../views/nodes/FieldView"; import "../../views/nodes/WebBox.scss"; import "./YoutubeBox.scss"; import React = require("react"); +import { InkTool } from '../../../fields/InkField'; interface VideoTemplate { thumbnailUrl: string; @@ -349,7 +350,7 @@ export class YoutubeBox extends React.Component { const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - const classname = "webBox-cont" + (this.props.isSelected() && !Doc.GetSelectedTool() && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const classname = "webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( <>
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8d3e5a771..8d867348f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -631,7 +631,7 @@ export namespace Docs { return doc; } - export function InkDocument(color: string, tool: number, strokeWidth: string, strokeBezier: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) { + export function InkDocument(color: string, tool: string, strokeWidth: string, strokeBezier: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) { const I = new Doc(); I.type = DocumentType.INK; I.layout = InkingStroke.LayoutString("data"); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index e7a14f9c5..f1afaf734 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -67,6 +67,7 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; + let dragLabel: HTMLDivElement; export let StartWindowDrag: Opt<((e: any, dragDocs: Doc[]) => void)> = undefined; export function Root() { @@ -97,7 +98,8 @@ export namespace DragManager { readonly shiftKey: boolean, readonly altKey: boolean, readonly metaKey: boolean, - readonly ctrlKey: boolean + readonly ctrlKey: boolean, + readonly embedKey: boolean, ) { } } @@ -309,14 +311,24 @@ export namespace DragManager { }; } export let docsBeingDragged: Doc[] = []; + export let CanEmbed = false; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { eles = eles.filter(e => e); + CanEmbed = false; if (!dragDiv) { dragDiv = document.createElement("div"); dragDiv.className = "dragManager-dragDiv"; dragDiv.style.pointerEvents = "none"; + dragLabel = document.createElement("div") as HTMLDivElement; + dragLabel.className = "dragManager-dragLabel"; + dragLabel.style.zIndex = "100001"; + dragLabel.style.fontSize = "10"; + dragLabel.style.position = "absolute"; + dragLabel.innerText = "press 'a' to embed on drop"; + dragDiv.appendChild(dragLabel); DragManager.Root().appendChild(dragDiv); } + dragLabel.style.display = ""; SnappingManager.SetIsDragging(true); const scaleXs: number[] = []; const scaleYs: number[] = []; @@ -358,6 +370,7 @@ export namespace DragManager { dragElement.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`; dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; + dragLabel.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0) - 20}px)`; if (docsBeingDragged.length) { const pdfBox = dragElement.getElementsByTagName("canvas"); @@ -399,20 +412,21 @@ export namespace DragManager { if (dragData instanceof DocumentDragData) { dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined; } - if (e.shiftKey && dragData.droppedDocuments.length === 1) { - !dragData.dropAction && (dragData.dropAction = alias); - if (dragData.dropAction === "move") { - dragData.removeDocument?.(dragData.draggedDocuments[0]); + if (e) + if (e.shiftKey && dragData.droppedDocuments.length === 1) { + !dragData.dropAction && (dragData.dropAction = alias); + if (dragData.dropAction === "move") { + dragData.removeDocument?.(dragData.draggedDocuments[0]); + } + AbortDrag(); + finishDrag?.(new DragCompleteEvent(true, dragData)); + DragManager.StartWindowDrag?.({ + pageX: e.pageX, + pageY: e.pageY, + preventDefault: emptyFunction, + button: 0 + }, dragData.droppedDocuments); } - AbortDrag(); - finishDrag?.(new DragCompleteEvent(true, dragData)); - DragManager.StartWindowDrag?.({ - pageX: e.pageX, - pageY: e.pageY, - preventDefault: emptyFunction, - button: 0 - }, dragData.droppedDocuments); - } const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); @@ -421,12 +435,14 @@ export namespace DragManager { const moveY = thisY - lastY; lastX = thisX; lastY = thisY; + dragLabel.style.transform = `translate(${xs[0] + moveX + (options?.offsetX || 0)}px, ${ys[0] + moveY + (options?.offsetY || 0) - 20}px)`; dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveX) + (options?.offsetX || 0)}px, ${(ys[i] += moveY) + (options?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) ); }; const hideDragShowOriginalElements = () => { + dragLabel.style.display = "none"; dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false)); }; @@ -481,7 +497,8 @@ export namespace DragManager { shiftKey: e.shiftKey, altKey: e.altKey, metaKey: e.metaKey, - ctrlKey: e.ctrlKey + ctrlKey: e.ctrlKey, + embedKey: CanEmbed } }) ); @@ -496,7 +513,8 @@ export namespace DragManager { shiftKey: e.shiftKey, altKey: e.altKey, metaKey: e.metaKey, - ctrlKey: e.ctrlKey + ctrlKey: e.ctrlKey, + embedKey: CanEmbed } }) ); diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 4e5cde558..25c556697 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -7,7 +7,7 @@ import Measure, { ContentRect } from "react-measure"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTag, faPlus, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons'; -import { Docs, DocumentOptions } from "../../documents/Documents"; +import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; import { observer } from "mobx-react"; import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from "./ImportMetadataEntry"; import { Utils } from "../../../Utils"; @@ -123,7 +123,7 @@ export default class DirectoryImportBox extends React.Component } const { accessPaths, exifData } = result; const path = Utils.prepend(accessPaths.agnostic.client); - const document = await Doc.Get.DocumentFromType(type, path, { _width: 300, title: name }); + const document = await DocUtils.DocumentFromType(type, path, { _width: 300, title: name }); const { data, error } = exifData; if (document) { Doc.GetProto(document).exif = error || Doc.Get.FromJson({ data }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e7a237e62..6ca7331d6 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -403,7 +403,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onPointerUp = (e: PointerEvent): void => { SelectionManager.SelectedDocuments().map(dv => { if (NumCast(dv.layoutDoc._delayAutoHeight) < this._dragHeights.get(dv.layoutDoc)!) { - dv.nativeWidth > 0 && Doc.toggleNativeDimensions(dv.layoutDoc, dv.props.ContentScaling(), dv.panelWidth(), dv.panelHeight()); + dv.nativeWidth > 0 && Doc.toggleNativeDimensions(dv.layoutDoc, dv.props.ContentScaling(), dv.props.PanelWidth(), dv.props.PanelHeight()); dv.layoutDoc._autoHeight = true; } dv.layoutDoc._delayAutoHeight = undefined; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 2d5af5386..772cb07b1 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -72,6 +72,7 @@ export default class KeyManager { private unmodified = action((keyname: string, e: KeyboardEvent) => { switch (keyname) { + case "a": DragManager.CanEmbed = true; case " ": MarqueeView.DragMarquee = !MarqueeView.DragMarquee; break; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 7dac2e3b5..7d73247af 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -92,5 +92,5 @@ Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any) { Scripting.addGlobal(function activateEraser(pen: any) { return Doc.SetSelectedTool(pen ? InkTool.Eraser : InkTool.None); }); Scripting.addGlobal(function activateStamp(pen: any) { return Doc.SetSelectedTool(pen ? InkTool.Stamp : InkTool.None); }); Scripting.addGlobal(function deactivateInk() { return Doc.SetSelectedTool(InkTool.None); }); -Scripting.addGlobal(function setInkWidth(width: any) { return Doc.SetSelectedTool(width); }); -Scripting.addGlobal(function setInkColor(color: any) { return Doc.SetSelectedTool(color); }); \ No newline at end of file +Scripting.addGlobal(function setInkWidth(width: any) { return SetActiveInkWidth(width); }); +Scripting.addGlobal(function setInkColor(color: any) { return SetActiveInkColor(color); }); \ No newline at end of file diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 77e6ebf44..f135823a8 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -7,7 +7,7 @@ import { DocumentView } from "./nodes/DocumentView"; import { Template } from "./Templates"; import React = require("react"); import { Doc, DocListCast } from "../../fields/Doc"; -import { Docs, } from "../documents/Documents"; +import { Docs, DocUtils, } from "../documents/Documents"; import { StrCast, Cast } from "../../fields/Types"; import { CollectionTreeView } from "./collections/CollectionTreeView"; import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero } from "../../Utils"; @@ -176,5 +176,5 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc | undefined) { template = Cast(template.dragFactory, Doc, null); } const templateTitle = StrCast(template?.title); - return templateTitle && Doc.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template); + return templateTitle && DocUtils.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template); }); diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index b562bd957..3a7182a94 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -180,10 +180,10 @@ export class Keyframe extends React.Component { const fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); const fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.end); - (fadeIn as Doc).opacity = 1; - (fadeOut as Doc).opacity = 1; - (start as Doc).opacity = 0.1; - (finish as Doc).opacity = 0.1; + fadeIn.opacity = 1; + fadeOut.opacity = 1; + start.opacity = 0.1; + finish.opacity = 0.1; this.forceUpdate(); //not needed, if setTimeout is gone... }, 1000); } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 43f15a33f..ab984f727 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -445,7 +445,7 @@ export class Timeline extends React.Component { // @computed getCurrentTime = () => { - let current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + const current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); return this.toReadTime(current > this._time ? this._time : current); } diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 31e248823..81a5587e4 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -42,9 +42,9 @@ export class TimelineOverview extends React.Component{ this.setOverviewWidth(); this._authoringReaction = reaction( - () => this.props.parent._isAuthoring, + () => this.props.isAuthoring, () => { - if (!this.props.parent._isAuthoring) { + if (!this.props.isAuthoring) { runInAction(() => { this.setOverviewWidth(); }); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index fc48e0327..22a3877ab 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -12,6 +12,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { UndoManager, undoBatch } from "../../util/UndoManager"; import { SnappingManager } from "../../util/SnappingManager"; import { DragManager } from "../../util/DragManager"; +import { DocUtils } from "../../documents/Documents"; @observer export class CollectionPileView extends CollectionSubView(doc => doc) { @@ -45,12 +46,12 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { if (this.layoutEngine() === 'starburst') { const defaultSize = 110; this.layoutDoc._overflow = undefined; - this.childDocs.forEach(d => Doc.iconify(d)); + this.childDocs.forEach(d => DocUtils.iconify(d)); this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize); - Doc.pileup(this.childDocs); + DocUtils.pileup(this.childDocs); this.layoutDoc._panX = 0; this.layoutDoc._panY = -10; this.props.Document._pileLayoutEngine = 'pass'; @@ -76,7 +77,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { onInternalDrop = (e: Event, de: DragManager.DropEvent) => { if (super.onInternalDrop(e, de)) { if (de.complete.docDragData) { - Doc.pileup(this.childDocs); + DocUtils.pileup(this.childDocs); } } return true; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index bd48d1727..0a1b03522 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -27,6 +27,7 @@ import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; import { SnappingManager } from "../../util/SnappingManager"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; +import { DocUtils } from "../../documents/Documents"; const _global = (window /* browser */ || global /* node */) as any; type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; @@ -412,7 +413,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) if (value && this.sectionHeaders) { const schemaHdrField = new SchemaHeaderField(value); this.sectionHeaders.push(schemaHdrField); - Doc.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: schemaHdrField.color }]); + DocUtils.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: schemaHdrField.color }]); return true; } return false; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index a269b21f5..bcd55f0fe 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -235,7 +235,7 @@ export class CollectionStackingViewFieldColumn extends React.Component dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof (dataDoc[fieldKey]) === "string").map(fieldKey => docItems.push({ description: ":" + fieldKey, event: () => { - const created = Docs.Get.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.parent.props.Document)); + const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.parent.props.Document)); if (created) { if (this.props.parent.Document.isTemplateDoc) { Doc.MakeMetadataFieldTemplate(created, this.props.parent.props.Document); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 47d571bcc..93d20c475 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,7 +10,7 @@ import { WebField } from "../../../fields/URLField"; import { Cast, ScriptCast, NumCast } from "../../../fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; import { Upload } from "../../../server/SharedMediaTypes"; -import { Utils } from "../../../Utils"; +import { Utils, returnFalse } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Networking } from "../../Network"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; @@ -217,7 +217,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); const res = addedDocs.length ? this.addDocument(addedDocs) : true; - added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, this.addDocument) : res; + added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, de.embedKey || !this.props.isAnnotationOverlay ? this.addDocument : returnFalse) : res; } else { added = this.addDocument(docDragData.droppedDocuments); } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 15bc0bfd5..c2d682361 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -19,6 +19,7 @@ const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; import React = require("react"); +import { DocUtils } from "../../documents/Documents"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -28,7 +29,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @observable _childClickedScript: Opt; @observable _viewDefDivClick: Opt; async componentDidMount() { - const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || Doc.findTemplate("detailView", StrCast(this.props.Document.type), ""); + const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.props.Document.type), ""); const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; runInAction(() => { this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c3fc3a40a..7e5f427ba 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -164,7 +164,7 @@ export class CollectionView extends Touchable { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 29a3e559a..3dc740c25 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -93,7 +93,7 @@ export class CollectionViewBaseChrome extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d512f815c..aa4fc48f3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -177,7 +177,7 @@ export class CollectionFreeFormView extends CollectionSubView { SelectionManager.DeselectAll(); @@ -251,11 +251,11 @@ export class CollectionFreeFormView extends CollectionSubView { // if (this.props.Document.isBackground) return false; const [xp, yp] = this.getTransform().transformPoint(de.x, de.y); - if (this.isAnnotationOverlay !== true && de.complete.linkDragData) + if (this.isAnnotationOverlay !== true && de.complete.linkDragData) { return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp); - if (de.complete.annoDragData?.dropDocument && super.onInternalDrop(e, de)) + } else if (de.complete.annoDragData?.dropDocument && super.onInternalDrop(e, de)) { return this.internalPdfAnnoDrop(e, de.complete.annoDragData, xp, yp); - if (de.complete.docDragData?.droppedDocuments.length && this.internalDocDrop(e, de, de.complete.docDragData, xp, yp)) { + } else if (de.complete.docDragData?.droppedDocuments.length && this.internalDocDrop(e, de, de.complete.docDragData, xp, yp)) { return true; } else { UndoManager.Undo(); @@ -530,9 +530,7 @@ export class CollectionFreeFormView extends CollectionSubView { - console.log(results); const wordResults = results.filter((r: any) => r.category === "inkWord"); for (const word of wordResults) { const indices: number[] = word.strokeIds; @@ -617,8 +615,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.removeDocument(d)); - const newCollection = Doc.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2); + const newCollection = DocUtils.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2); this.props.addDocument(newCollection!); this.props.selectDocuments([newCollection!], []); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -527,7 +526,7 @@ export class MarqueeView extends React.Component { - this._freeHand = x; + this._freeHand = !this._freeHand; } // @action // marqueeInkSelect(ink: Map) { @@ -697,7 +696,7 @@ export class MarqueeView extends React.Component - {/* */} +
; } else { diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index d75b864cf..f7dee0896 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -18,6 +18,7 @@ import { ContextMenuProps } from "../ContextMenuItem"; import { ViewBoxBaseComponent } from "../DocComponent"; import { FieldView, FieldViewProps } from './FieldView'; import "./ScreenshotBox.scss"; +import { InkTool } from "../../../fields/InkField"; const path = require('path'); type ScreenshotDocument = makeInterface<[typeof documentSchema]>; @@ -132,7 +133,7 @@ export class ScreenshotBox extends ViewBoxBaseComponentLoading
:
diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index 9192a38d7..529e7762f 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -21,6 +21,7 @@ interface GridProps { childrenDraggable: boolean; preventCollision: boolean; compactType: string; + margin: number; } /** @@ -47,6 +48,7 @@ export default class Grid extends React.Component { preventCollision={this.props.preventCollision} transformScale={1 / this.props.transformScale} // still doesn't work :( style={{ zIndex: 5 }} + margin={[this.props.margin, this.props.margin]} > {this.props.nodeList} diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 77555061f..d9e7d072f 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -73,8 +73,8 @@ export class ContentFittingDocumentView extends React.Component this.props.ScreenToLocalTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling()); - private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; } - private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; } + private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth && this.props.display !== "contents" ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; } + private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 && this.props.display !== "contents" ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; } @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); } -- cgit v1.2.3-70-g09d2 From 1daca67ea2a574b16c02b185d66f5724651ba235 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 10 Jun 2020 15:55:05 -0400 Subject: changed how ink is highlighted when selected. --- src/client/util/InteractionUtils.tsx | 4 ++- src/client/views/GestureOverlay.tsx | 2 ++ src/client/views/InkingStroke.tsx | 35 ++++++++++++++++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 9 +++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 2 +- 6 files changed, 43 insertions(+), 12 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 3948611f0..81f9b9362 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -89,7 +89,7 @@ export namespace InteractionUtils { return myTouches; } - export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: string, bezier: string, scalex: number, scaley: number, shape: string) { + export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: string, bezier: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean) { var pts = ""; if (shape) { //if any of the shape are true @@ -120,7 +120,9 @@ export namespace InteractionUtils { 5 ? strokeColor : "transparent", + (strokeWidth + 15).toString(), + StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false); return ( { ContextMenu.Instance.addItem({ description: "Analyze Stroke", @@ -60,7 +67,25 @@ export class InkingStroke extends ViewBoxBaseComponent + > + + + + + + + + + + + + + {hpoints} {points} ); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 97244ed06..b0461609a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,7 +1,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, Opt } from "../../../../fields/Doc"; -import { InkData, InkField } from "../../../../fields/InkField"; +import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { RichTextField } from "../../../../fields/RichTextField"; import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; @@ -271,10 +271,11 @@ export class MarqueeView extends React.Component { - if ( - Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && + if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - !(e.nativeEvent as any).formattedHandled && this.setPreviewCursor(e.clientX, e.clientY, false); + if (Doc.GetSelectedTool() === InkTool.None) { + !(e.nativeEvent as any).formattedHandled && this.setPreviewCursor(e.clientX, e.clientY, false); + } // 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. diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 910aa744d..509f78021 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -14,6 +14,7 @@ import { List } from "../../../fields/List"; import { numberRange } from "../../../Utils"; import { ComputedField } from "../../../fields/ScriptField"; import { listSpec } from "../../../fields/Schema"; +import { DocumentType } from "../../documents/DocumentTypes"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; @@ -156,7 +157,7 @@ export class CollectionFreeFormDocumentView extends DocComponent {Doc.UserDoc().renderStyle !== "comic" ? (null) :
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 98be1adc0..9f2b0124a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1135,7 +1135,7 @@ export class DocumentView extends DocComponent(Docu ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] : ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"]; const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; - let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; + let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear && this.props.Document.type !== DocumentType.INK; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way return
Date: Sat, 13 Jun 2020 20:53:31 -0400 Subject: fixed text sidebar when text is scaled. started to add multiple links to a text selection --- .../collectionFreeForm/CollectionFreeFormView.tsx | 25 +++++++------ .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../nodes/formattedText/FormattedTextBox.scss | 43 ++++++++++++++++++++++ .../views/nodes/formattedText/FormattedTextBox.tsx | 18 ++++++--- .../formattedText/FormattedTextBoxComment.tsx | 19 +++++----- src/client/views/nodes/formattedText/marks_rts.ts | 11 +++++- 6 files changed, 90 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 678ad2a53..67356bff7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -52,7 +52,6 @@ library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressAr export const panZoomSchema = createSchema({ _panX: "number", _panY: "number", - scale: "number", currentTimecode: "number", displayTimecode: "number", currentFrame: "number", @@ -76,6 +75,7 @@ export type collectionFreeformViewProps = { forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: boolean; + scaleField?: string; }; @observer @@ -108,6 +108,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.Document.panTransformType === "Ease"; private panX = () => this.fitToContent ? (this.contentBounds.x + this.contentBounds.r) / 2 : this.Document._panX || 0; @@ -115,14 +116,14 @@ export class CollectionFreeFormView extends CollectionSubView (this.fitToContentScaling / this.parentScaling) * (this.fitToContent ? Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) : - this.Document.scale || 1) + NumCast(this.Document[this.scaleFieldKey], 1)); @computed get cachedCenteringShiftX(): number { - const scaling = this.fitToContent ? 1 : this.contentScaling; + const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / scaling : 0; // shift so pan position is at center of window for non-overlay collections } @computed get cachedCenteringShiftY(): number { - const scaling = this.fitToContent ? 1 : this.contentScaling; + const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / scaling : 0;// shift so pan position is at center of window for non-overlay collections } @computed get cachedGetLocalTransform(): Transform { @@ -779,7 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView= 0.15 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40); - this.props.Document.scale = Math.abs(safeScale); + this.props.Document[this.scaleFieldKey] = Math.abs(safeScale); this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale); } } @@ -795,7 +796,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this.Document.scale = scale * Math.min(this.props.PanelWidth() / NumCast(doc._width), this.props.PanelHeight() / NumCast(doc._height)); + this.Document[this.scaleFieldKey] = scale * Math.min(this.props.PanelWidth() / NumCast(doc._width), this.props.PanelHeight() / NumCast(doc._height)); } @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; } @@ -1125,7 +1126,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); optionItems.push({ description: "toggle snap line display", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }); optionItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 085625e69..5f09fa0ee 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -122,7 +122,7 @@ export class MarqueeView extends React.Component !child && node.marks.length && (child = node)); + if (child) { + allHrefs.push(...(child.marks.find((m: Mark) => m.type.name === schema.marks.link.name)?.attrs.allHrefs ?? [])); + } + const link = this._editorView.state.schema.marks.link.create({ href: newRef, allHrefs, title, location, linkId: linkDocId, targetId: targetDocId }); + this._editorView.dispatch(this._editorView.state.tr.addMark(this._editorView.state.selection.from, this._editorView.state.selection.to, link)); } } componentDidMount() { @@ -987,7 +994,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp FormattedTextBox._downEvent = false; if (!(e.nativeEvent as any).formattedHandled) { FormattedTextBoxComment.textBox = this; - FormattedTextBoxComment.update(this._editorView!); + FormattedTextBoxComment.update(this._editorView!, undefined, (e.target as any)?.className === "prosemirror-dropdownlink" ? (e.target as any).href : ""); } (e.nativeEvent as any).formattedHandled = true; @@ -1205,7 +1212,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); } sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); - sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0); + sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()) / this.props.ContentScaling(), 0); @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } render() { TraceMobx(); @@ -1273,6 +1280,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp PanelWidth={this.sidebarWidth} NativeHeight={returnZero} NativeWidth={returnZero} + scaleField={this.annotationKey + "-scale"} annotationsKey={this.annotationKey} isAnnotationOverlay={false} focus={this.props.focus} diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 59a6045ab..dde7cc0c1 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -115,7 +115,7 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = ""); } - static update(view: EditorView, lastState?: EditorState) { + static update(view: EditorView, lastState?: EditorState, forceUrl: string = "") { const state = view.state; // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && @@ -160,25 +160,26 @@ export class FormattedTextBoxComment { let child: any = null; state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node)); const mark = child && findLinkMark(child.marks); - if (mark && child && nbef && naft && mark.attrs.showPreview) { - FormattedTextBoxComment.tooltipText.textContent = "external => " + mark.attrs.href; - (FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href; - if (mark.attrs.href.startsWith("https://en.wikipedia.org/wiki/")) { - wiki().page(mark.attrs.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(summary => FormattedTextBoxComment.tooltipText.textContent = summary.substring(0, 500))); + const href = mark?.attrs.href || forceUrl; + if (forceUrl || (href && child && nbef && naft && mark?.attrs.showPreview)) { + FormattedTextBoxComment.tooltipText.textContent = "external => " + href; + (FormattedTextBoxComment.tooltipText as any).href = href; + if (href.startsWith("https://en.wikipedia.org/wiki/")) { + wiki().page(href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(summary => FormattedTextBoxComment.tooltipText.textContent = summary.substring(0, 500))); } else { FormattedTextBoxComment.tooltipText.style.whiteSpace = "pre"; FormattedTextBoxComment.tooltipText.style.overflow = "hidden"; } - if (mark.attrs.href.indexOf(Utils.prepend("/doc/")) === 0) { + if (href.indexOf(Utils.prepend("/doc/")) === 0) { FormattedTextBoxComment.tooltipText.textContent = "target not found..."; (FormattedTextBoxComment.tooltipText as any).href = ""; - const docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0]; + const docTarget = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; try { ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); } catch (e) { } docTarget && DocServer.GetRefField(docTarget).then(async linkDoc => { if (linkDoc instanceof Doc) { - (FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href; + (FormattedTextBoxComment.tooltipText as any).href = href; FormattedTextBoxComment.linkDoc = linkDoc; const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index ebaa23e99..b42fa6755 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -15,6 +15,7 @@ export const marks: { [index: string]: MarkSpec } = { link: { attrs: { href: {}, + allHrefs: { default: [] as { href: string, title: string }[] }, targetId: { default: "" }, linkId: { default: "" }, showPreview: { default: true }, @@ -31,7 +32,15 @@ export const marks: { [index: string]: MarkSpec } = { toDOM(node: any) { return node.attrs.docref && node.attrs.title ? ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, class: "prosemirror-attribution", title: `${node.attrs.title}` }, node.attrs.title], ["br"]] : - ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0]; + node.attrs.allHrefs.length === 1 ? + ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0] : + ["div", { class: "prosemirror-anchor" }, + ["button", { class: "prosemirror-linkBtn" }, + ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0], + ["input", { class: "fa fa-caret-down prosemirror-hrefoptions" }], + ], + ["div", { class: "prosemirror-links" }, ...node.attrs.allHrefs.map((item: { href: string, title: string }) => ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title])] + ] } }, -- cgit v1.2.3-70-g09d2 From c3fcbe3b416b9719d26fb19999f63f17d1d3c6c6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 13 Jun 2020 21:17:01 -0400 Subject: fixed linking to text selection that includes a nested link --- .../views/nodes/formattedText/FormattedTextBox.tsx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index a8f5b7827..95d36c994 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -583,18 +583,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }; } - makeLinkToSelection(linkDocId: string, title: string, location: string, targetDocId: string) { + makeLinkToSelection(linkDocId: string, title: string, location: string, targetId: string) { if (this._editorView) { - const newRef = Utils.prepend("/doc/" + linkDocId); - const allHrefs = [{ href: newRef, title }]; - let child: any = null; + const href = Utils.prepend("/doc/" + linkDocId); const sel = this._editorView.state.selection; - this._editorView.state.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node)); - if (child) { - allHrefs.push(...(child.marks.find((m: Mark) => m.type.name === schema.marks.link.name)?.attrs.allHrefs ?? [])); - } - const link = this._editorView.state.schema.marks.link.create({ href: newRef, allHrefs, title, location, linkId: linkDocId, targetId: targetDocId }); - this._editorView.dispatch(this._editorView.state.tr.addMark(this._editorView.state.selection.from, this._editorView.state.selection.to, link)); + let tr = this._editorView!.state.tr; + sel.from !== sel.to && this._editorView.state.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { + if (node.firstChild === null) { + const allHrefs = [{ href, title }]; + allHrefs.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.link.name)?.attrs.allHrefs ?? [])); + const link = this._editorView!.state.schema.marks.link.create({ href, allHrefs, title, location, linkId: linkDocId, targetId }); + tr = tr.addMark(pos, pos + node.nodeSize, link); + } + }); + this._editorView.dispatch(tr); } } componentDidMount() { -- cgit v1.2.3-70-g09d2 From e2423815ef608f35fdb9c1625d7de0bf5a5fe206 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 13 Jun 2020 23:19:27 -0400 Subject: fixes to make link lines work correctly with text anchors that have more than one link. fixed problem making a text link anchor by adding dummy mark to split the selection first. --- .../CollectionFreeFormLinkView.tsx | 11 ++++++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 24 ++++++++++--------- .../formattedText/FormattedTextBoxComment.tsx | 2 +- .../formattedText/ProsemirrorExampleTransfer.ts | 1 - .../views/nodes/formattedText/RichTextMenu.tsx | 8 +++---- src/client/views/nodes/formattedText/marks_rts.ts | 27 ++++++++++++++-------- src/fields/RichTextUtils.ts | 2 +- 7 files changed, 45 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index f3fc04752..8ab00bb29 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -46,10 +46,15 @@ export class CollectionFreeFormLinkView extends React.Component ele.getAttribute("targetids")?.includes(AanchorId)); + const targetBhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(BanchorId)); if (!targetBhyperlink) { this.props.A.props.Document[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100; this.props.A.props.Document[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 95d36c994..ffab1d1e1 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -583,20 +583,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }; } - makeLinkToSelection(linkDocId: string, title: string, location: string, targetId: string) { - if (this._editorView) { - const href = Utils.prepend("/doc/" + linkDocId); - const sel = this._editorView.state.selection; - let tr = this._editorView!.state.tr; - sel.from !== sel.to && this._editorView.state.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { - if (node.firstChild === null) { - const allHrefs = [{ href, title }]; + makeLinkToSelection(linkId: string, title: string, location: string, targetId: string) { + const state = this._editorView?.state; + if (state) { + const href = Utils.prepend("/doc/" + linkId); + const sel = state.selection; + const splitter = state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); + let tr = state.tr.addMark(sel.from, sel.to, splitter); + sel.from !== sel.to && tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { + if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { + const allHrefs = [{ href, title, targetId, linkId }]; allHrefs.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.link.name)?.attrs.allHrefs ?? [])); - const link = this._editorView!.state.schema.marks.link.create({ href, allHrefs, title, location, linkId: linkDocId, targetId }); + const link = state.schema.marks.link.create({ href, allHrefs, title, location, linkId, targetId }); tr = tr.addMark(pos, pos + node.nodeSize, link); } }); - this._editorView.dispatch(tr); + this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter)); } } componentDidMount() { @@ -704,7 +706,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } const marks = [...node.marks]; const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.link); - return linkIndex !== -1 && scrollToLinkID === marks[linkIndex].attrs.href.replace(/.*\/doc\//, "") ? node : undefined; + return linkIndex !== -1 && marks[linkIndex].attrs.allRefs.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? node : undefined; }; let start = 0; diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index dde7cc0c1..7513c881d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -160,7 +160,7 @@ export class FormattedTextBoxComment { let child: any = null; state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node)); const mark = child && findLinkMark(child.marks); - const href = mark?.attrs.href || forceUrl; + const href = mark?.attrs.allHrefs.find((item: { href: string }) => item.href)?.href || forceUrl; if (forceUrl || (href && child && nbef && naft && mark?.attrs.showPreview)) { FormattedTextBoxComment.tooltipText.textContent = "external => " + href; (FormattedTextBoxComment.tooltipText as any).href = href; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 0e3e7f91e..77b93b9d2 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -6,7 +6,6 @@ import { liftListItem, sinkListItem } from "./prosemirrorPatches.js"; import { splitListItem, wrapInList, } from "prosemirror-schema-list"; import { EditorState, Transaction, TextSelection } from "prosemirror-state"; import { SelectionManager } from "../../../util/SelectionManager"; -import { Docs } from "../../../documents/Documents"; import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types"; import { Doc } from "../../../../fields/Doc"; import { FormattedTextBox } from "./FormattedTextBox"; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index fd1b26208..03d393cde 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -631,7 +631,7 @@ export default class RichTextMenu extends AntimodeMenu { const node = this.view.state.selection.$from.nodeAfter; const link = node && node.marks.find(m => m.type.name === "link"); if (link) { - const href = link.attrs.href; + const href = link.attrs.allHrefs.length > 0 ? link.attrs.allHrefs[0].href : undefined; if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { const linkclicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; @@ -677,7 +677,7 @@ export default class RichTextMenu extends AntimodeMenu { const node = this.view.state.selection.$from.nodeAfter; const link = node && node.marks.find(m => m.type === this.view!.state.schema.marks.link); - const href = link!.attrs.href; + const href = link!.attrs.allHrefs.length > 0 ? link!.attrs.allHrefs[0].href : undefined; if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { const linkclicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; @@ -705,8 +705,8 @@ export default class RichTextMenu extends AntimodeMenu { let startIndex = $start.index(); let endIndex = $start.indexAfter(); - while (startIndex > 0 && $start.parent.child(startIndex - 1).marks.filter(m => m.type === mark && m.attrs.href === href).length) startIndex--; - while (endIndex < $start.parent.childCount && $start.parent.child(endIndex).marks.filter(m => m.type === mark && m.attrs.href === href).length) endIndex++; + while (startIndex > 0 && $start.parent.child(startIndex - 1).marks.filter(m => m.type === mark && m.attrs.allHrefs.find((item: { href: string }) => item.href === href)).length) startIndex--; + while (endIndex < $start.parent.childCount && $start.parent.child(endIndex).marks.filter(m => m.type === mark && m.attrs.allHrefs.find((item: { href: string }) => item.href === href)).length) endIndex++; let startPos = $start.start(); let endPos = startPos; diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index b42fa6755..9c279a88f 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -9,15 +9,20 @@ const codeDOM: DOMOutputSpecArray = ["code", 0]; // :: Object [Specs](#model.MarkSpec) for the marks in the schema. export const marks: { [index: string]: MarkSpec } = { + splitter: { + attrs: { + id: { default: "" } + }, + toDOM(node: any) { + return ["div", { className: "dummy" }, 0]; + } + }, // :: MarkSpec A link. Has `href` and `title` attributes. `title` // defaults to the empty string. Rendered and parsed as an `` // element. link: { attrs: { - href: {}, - allHrefs: { default: [] as { href: string, title: string }[] }, - targetId: { default: "" }, - linkId: { default: "" }, + allHrefs: { default: [] as { href: string, title: string, linkId: string, targetId: string }[] }, showPreview: { default: true }, location: { default: null }, title: { default: null }, @@ -26,20 +31,24 @@ export const marks: { [index: string]: MarkSpec } = { inclusive: false, parseDOM: [{ tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), location: dom.getAttribute("location"), title: dom.getAttribute("title"), targetId: dom.getAttribute("id") }; + return { allHrefs: [{ href: dom.getAttribute("href"), title: dom.getAttribute("title"), linkId: dom.getAttribute("linkids"), targetId: dom.getAttribute("targetids") }], location: dom.getAttribute("location"), }; } }], toDOM(node: any) { + const targetids = node.attrs.allHrefs.reduce((p: string, item: { href: string, title: string, targetId: string, linkId: string }) => p + " " + item.targetId, ""); + const linkids = node.attrs.allHrefs.reduce((p: string, item: { href: string, title: string, targetId: string, linkId: string }) => p + " " + item.linkId, ""); return node.attrs.docref && node.attrs.title ? ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, class: "prosemirror-attribution", title: `${node.attrs.title}` }, node.attrs.title], ["br"]] : node.attrs.allHrefs.length === 1 ? - ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0] : + ["a", { ...node.attrs, class: linkids, targetids, title: `${node.attrs.title}`, href: node.attrs.allHrefs[0].href }, 0] : ["div", { class: "prosemirror-anchor" }, ["button", { class: "prosemirror-linkBtn" }, - ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0], - ["input", { class: "fa fa-caret-down prosemirror-hrefoptions" }], + ["a", { ...node.attrs, class: linkids, targetids, title: `${node.attrs.title}` }, 0], + ["input", { class: "prosemirror-hrefoptions" }], ], - ["div", { class: "prosemirror-links" }, ...node.attrs.allHrefs.map((item: { href: string, title: string }) => ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title])] + ["div", { class: "prosemirror-links" }, ...node.attrs.allHrefs.map((item: { href: string, title: string }) => + ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title] + )] ] } }, diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index f81ec8c6d..66959882d 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -392,7 +392,7 @@ export namespace RichTextUtils { const { attrs } = mark; switch (converted) { case "link": - let url = attrs.href; + let url = attrs.allHrefs.length ? attrs.allHrefs[0].href : ""; const delimiter = "/doc/"; const alreadyShared = "?sharing=true"; if (new RegExp(window.location.origin + delimiter).test(url) && !url.endsWith(alreadyShared)) { -- cgit v1.2.3-70-g09d2 From 9300029e95dcb8406cd05ed57c9d86107df49547 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 14 Jun 2020 01:03:36 -0400 Subject: lint/compile fixes. fixed entering/display of formulas in schema views. --- src/client/util/DragManager.ts | 29 ++++++++------- src/client/views/EditableView.tsx | 23 ++++++------ src/client/views/GestureOverlay.tsx | 4 +-- .../views/collections/CollectionSchemaCells.tsx | 42 ++++++++++++---------- .../CollectionFreeFormLinkView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 2 +- .../views/nodes/ContentFittingDocumentView.tsx | 14 ++++---- src/client/views/nodes/LinkAnchorBox.tsx | 2 +- src/client/views/nodes/formattedText/marks_rts.ts | 2 +- 10 files changed, 64 insertions(+), 58 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f1afaf734..cb899ef92 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -319,7 +319,7 @@ export namespace DragManager { dragDiv = document.createElement("div"); dragDiv.className = "dragManager-dragDiv"; dragDiv.style.pointerEvents = "none"; - dragLabel = document.createElement("div") as HTMLDivElement; + dragLabel = document.createElement("div"); dragLabel.className = "dragManager-dragLabel"; dragLabel.style.zIndex = "100001"; dragLabel.style.fontSize = "10"; @@ -412,21 +412,20 @@ export namespace DragManager { if (dragData instanceof DocumentDragData) { dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined; } - if (e) - if (e.shiftKey && dragData.droppedDocuments.length === 1) { - !dragData.dropAction && (dragData.dropAction = alias); - if (dragData.dropAction === "move") { - dragData.removeDocument?.(dragData.draggedDocuments[0]); - } - AbortDrag(); - finishDrag?.(new DragCompleteEvent(true, dragData)); - DragManager.StartWindowDrag?.({ - pageX: e.pageX, - pageY: e.pageY, - preventDefault: emptyFunction, - button: 0 - }, dragData.droppedDocuments); + if (e?.shiftKey && dragData.droppedDocuments.length === 1) { + !dragData.dropAction && (dragData.dropAction = alias); + if (dragData.dropAction === "move") { + dragData.removeDocument?.(dragData.draggedDocuments[0]); } + AbortDrag(); + finishDrag?.(new DragCompleteEvent(true, dragData)); + DragManager.StartWindowDrag?.({ + pageX: e.pageX, + pageY: e.pageY, + preventDefault: emptyFunction, + button: 0 + }, dragData.droppedDocuments); + } const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index e0e205df9..e21d431b1 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -66,16 +66,17 @@ export class EditableView extends React.Component { EditableView.loadId = ""; } - @action - componentDidUpdate(nextProps: EditableProps) { - // this is done because when autosuggest is turned on, the suggestions are passed in as a prop, - // so when the suggestions are passed in, and no editing prop is passed in, it used to set it - // to false. this will no longer do so -syip - if (nextProps.editing && nextProps.editing !== this._editing) { - this._editing = nextProps.editing; - EditableView.loadId = ""; - } - } + // @action + // componentDidUpdate(nextProps: EditableProps) { + // // this is done because when autosuggest is turned on, the suggestions are passed in as a prop, + // // so when the suggestions are passed in, and no editing prop is passed in, it used to set it + // // to false. this will no longer do so -syip + // console.log("props editing = " + nextProps.editing); + // if (nextProps.editing && nextProps.editing !== this._editing) { + // this._editing = nextProps.editing; + // EditableView.loadId = ""; + // } + // } _didShow = false; @@ -109,7 +110,7 @@ export class EditableView extends React.Component { if (this._ref.current && this.props.showMenuOnLoad) { this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y); } else { - if (!this.props.onClick || !this.props.onClick(e)) { + if (!this.props.onClick?.(e)) { this._editing = true; this.props.isEditingCallback?.(true); } diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index d239a1d6f..f00fd7cb4 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -809,11 +809,11 @@ export default class GestureOverlay extends Touchable { [this._strokes.map(l => { const b = this.getBounds(l); return - {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape)} + {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape, "none", false)} ; }), this._points.length <= 1 ? (null) : - {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape)} + {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape, "none", false)} ] ]; } diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 62aed67ed..baf9d4156 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -1,5 +1,5 @@ import React = require("react"); -import { action, observable } from "mobx"; +import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { CellInfo } from "react-table"; import "react-table/react-table.css"; @@ -23,6 +23,7 @@ import { faExpand } from '@fortawesome/free-solid-svg-icons'; import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; import { SnappingManager } from "../../util/SnappingManager"; +import { ComputedField } from "../../../fields/ScriptField"; library.add(faExpand); @@ -57,7 +58,6 @@ export class CollectionSchemaCell extends React.Component { componentDidMount() { document.addEventListener("keydown", this.onKeyDown); - } componentWillUnmount() { @@ -70,7 +70,6 @@ export class CollectionSchemaCell extends React.Component { document.removeEventListener("keydown", this.onKeyDown); this._isEditing = true; this.props.setIsEditing(true); - } } @@ -217,7 +216,8 @@ export class CollectionSchemaCell extends React.Component { //
// //
- // ); + // ); + trace(); return (
@@ -231,23 +231,29 @@ export class CollectionSchemaCell extends React.Component { height={"auto"} maxHeight={Number(MAX_ROW_HEIGHT)} GetValue={() => { - const field = props.Document[props.fieldKey]; - if (Field.IsField(field)) { - return Field.toScriptString(field); - } - return ""; - } - } - SetValue={(value: string) => { + const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); + const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined; + const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1]; + const val = cscript !== undefined ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : + Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; + return val; + }} + SetValue={action((value: string) => { + let retVal = false; if (value.startsWith(":=")) { - return this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col); + retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col); + } else { + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + if (script.compiled) { + retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); + } } - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - if (!script.compiled) { - return false; + if (retVal) { + this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing' + this.props.setIsEditing(false); } - return this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); - }} + return retVal; + })} OnFillDown={async (value: string) => { const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); if (script.compiled) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 8ab00bb29..6cac39f77 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -52,7 +52,7 @@ export class CollectionFreeFormLinkView extends React.Component ele.getAttribute("targetids")?.includes(AanchorId)); const targetBhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(BanchorId)); if (!targetBhyperlink) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 67356bff7..11a14a862 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -116,7 +116,7 @@ export class CollectionFreeFormView extends CollectionSubView (this.fitToContentScaling / this.parentScaling) * (this.fitToContent ? Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) : - NumCast(this.Document[this.scaleFieldKey], 1)); + NumCast(this.Document[this.scaleFieldKey], 1)) @computed get cachedCenteringShiftX(): number { const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index fe89b63ee..a5d355abc 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -162,7 +162,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { if (this.flexGrid) { const savedLayouts = this.savedLayoutList; this.childLayoutPairs.forEach(({ layout: doc }) => { - let gridLayout = savedLayouts.find(gridLayout => gridLayout.i === doc[Id]); + const gridLayout = savedLayouts.find(gridLayout => gridLayout.i === doc[Id]); gridLayout && Object.assign(gridLayout, layoutArray.find(layout => layout.i === doc[Id]) || gridLayout); }); diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index d9e7d072f..ba075886b 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -1,18 +1,18 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; +import { Transform } from "nodemailer/lib/xoauth2"; import "react-table/react-table.css"; -import { Doc, Opt, WidthSym, HeightSym } from "../../../fields/Doc"; -import { NumCast, StrCast, Cast } from "../../../fields/Types"; +import { Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { ScriptField } from "../../../fields/ScriptField"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnOne } from "../../../Utils"; +import { emptyFunction } from "../../../Utils"; +import { dropActionType } from "../../util/DragManager"; +import { CollectionView } from "../collections/CollectionView"; import '../DocumentDecorations.scss'; import { DocumentView, DocumentViewProps } from "../nodes/DocumentView"; import "./ContentFittingDocumentView.scss"; -import { dropActionType } from "../../util/DragManager"; -import { CollectionView } from "../collections/CollectionView"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { Transform } from "nodemailer/lib/xoauth2"; interface ContentFittingDocumentViewProps { Document: Doc; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 83245a89c..3c232eff8 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -117,7 +117,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent 1 ? NumCast(this.layoutDoc[this.fieldKey + "_y"], 100) : 0; const c = StrCast(this.layoutDoc.backgroundColor, "lightblue"); const anchor = this.fieldKey === "anchor1" ? "anchor2" : "anchor1"; - const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .15; + const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .25; const timecode = this.dataDoc[anchor + "_timecode"]; const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title) + (timecode !== undefined ? ":" + timecode : ""); diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index 9c279a88f..c735155d8 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -49,7 +49,7 @@ export const marks: { [index: string]: MarkSpec } = { ["div", { class: "prosemirror-links" }, ...node.attrs.allHrefs.map((item: { href: string, title: string }) => ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title] )] - ] + ]; } }, -- cgit v1.2.3-70-g09d2 From 5b9d33920858a42319e84eab2c515919feba45ac Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 14 Jun 2020 14:47:57 -0400 Subject: fixed dragging in tree views for Catalog to "copy" documents within the sidebar instead of aliasing them. --- src/client/util/DragManager.ts | 33 +++++++++-------- .../CollectionSchemaMovableTableHOC.tsx | 8 +++-- .../views/collections/CollectionSchemaView.tsx | 4 ++- .../views/collections/CollectionTreeView.tsx | 41 +++++++++++++--------- .../views/collections/CollectionViewChromes.tsx | 5 +-- src/client/views/nodes/DocHolderBox.tsx | 9 +++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 9 ++--- src/mobile/MobileInkOverlay.tsx | 3 +- 8 files changed, 65 insertions(+), 47 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index cb899ef92..06907d25d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -13,7 +13,7 @@ import * as globalCssVariables from "../views/globalCssVariables.scss"; import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; -export type dropActionType = "alias" | "copy" | "move" | undefined; // undefined = move +export type dropActionType = "alias" | "copy" | "move" | "same" | undefined; // undefined = move export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, @@ -122,7 +122,7 @@ export namespace DragManager { export class DocumentDragData { constructor(dragDoc: Doc[]) { this.draggedDocuments = dragDoc; - this.droppedDocuments = dragDoc; + this.droppedDocuments = []; this.offset = [0, 0]; } draggedDocuments: Doc[]; @@ -209,15 +209,19 @@ export namespace DragManager { }; const batch = UndoManager.StartBatch("dragging"); const finishDrag = (e: DragCompleteEvent) => { - e.docDragData && (e.docDragData.droppedDocuments = - dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : - dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? Doc.MakeAlias(d) : - dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeDelegate(d) : d) - ); - e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) => - (dragData?.removeDropProperties || []).concat(Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), [])).map(prop => drop[prop] = undefined) - ); - batch.end(); + const docDragData = e.docDragData; + if (docDragData && !docDragData.droppedDocuments.length) { + docDragData.dropAction = dragData.userDropAction || dragData.dropAction; + docDragData.droppedDocuments = + dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : + docDragData.dropAction === "alias" ? Doc.MakeAlias(d) : + docDragData.dropAction === "copy" ? Doc.MakeDelegate(d) : d); + docDragData.dropAction !== "same" && docDragData.droppedDocuments.forEach((drop: Doc, i: number) => + (dragData?.removeDropProperties || []).concat(Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), [])).map(prop => drop[prop] = undefined) + ); + batch.end(); + } + return e; }; dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded StartDrag(eles, dragData, downX, downY, options, finishDrag); @@ -231,6 +235,7 @@ export namespace DragManager { initialize?.(bd); Doc.GetProto(bd)["onClick-paramFieldKeys"] = new List(params); e.docDragData && (e.docDragData.droppedDocuments = [bd]); + return e; }; StartDrag(eles, new DragManager.DocumentDragData([]), downX, downY, options, finishDrag); } @@ -406,14 +411,13 @@ export namespace DragManager { const yFromTop = downY - elesCont.top; const xFromRight = elesCont.right - downX; const yFromBottom = elesCont.bottom - downY; - let alias = "alias"; const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined; } - if (e?.shiftKey && dragData.droppedDocuments.length === 1) { - !dragData.dropAction && (dragData.dropAction = alias); + if (e?.shiftKey && dragData.draggedDocuments.length === 1) { + dragData.dropAction = dragData.userDropAction || "same"; if (dragData.dropAction === "move") { dragData.removeDocument?.(dragData.draggedDocuments[0]); } @@ -429,7 +433,6 @@ export namespace DragManager { const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); - alias = "move"; const moveX = thisX - lastX; const moveY = thisY - lastY; lastX = thisX; diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index 6f1e8ac1f..6588825ba 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -66,8 +66,9 @@ export class MovableColumn extends React.Component { const rect = this._header!.current!.getBoundingClientRect(); const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top); const before = x[0] < bounds[0]; - if (de.complete.columnDragData) { - this.props.reorderColumns(de.complete.columnDragData.colKey, this.props.columnValue, before, this.props.allColumns); + const colDragData = de.complete.columnDragData; + if (colDragData) { + this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns); return true; } return false; @@ -164,13 +165,14 @@ export class MovableRow extends React.Component { } createRowDropTarget = (ele: HTMLDivElement) => { - this._rowDropDisposer && this._rowDropDisposer(); + this._rowDropDisposer?.(); if (ele) { this._rowDropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this)); } } rowDrop = (e: Event, de: DragManager.DropEvent) => { + this.onPointerLeave(e as any); const rowDoc = FieldValue(Cast(this.props.rowInfo.original, Doc)); if (!rowDoc) return false; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 89fc6a406..252fa547e 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -29,6 +29,7 @@ import { CollectionView } from "./CollectionView"; import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; import { setupMoveUpEvents, emptyFunction, returnZero, returnOne, returnFalse } from "../../../Utils"; import { DocumentView } from "../nodes/DocumentView"; +import { SnappingManager } from "../../util/SnappingManager"; library.add(faCog, faPlus, faSortUp, faSortDown); library.add(faTable); @@ -186,7 +187,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } render() { - return
+ return
this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}> {this.schemaTable}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e891c4274..8f30e71b6 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -123,7 +123,7 @@ class TreeView extends React.Component { protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer?.(); - ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)), this.props.document); + ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this)), this.props.document); } onPointerEnter = (e: React.PointerEvent): void => { @@ -187,33 +187,36 @@ class TreeView extends React.Component { })} />) + preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { + const dragData = de.complete.docDragData; + dragData && (dragData.dropAction = this.props.treeViewId[Id] === dragData.treeViewId ? "same" : dragData.dropAction); + } + @undoBatch treeDrop = (e: Event, de: DragManager.DropEvent) => { const pt = [de.x, de.y]; const rect = this._header!.current!.getBoundingClientRect(); const before = pt[1] < rect.top + rect.height / 2; const inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && DocListCast(this.dataDoc[this.fieldKey]).length); - if (de.complete.linkDragData) { - const sourceDoc = de.complete.linkDragData.linkSourceDocument; + const complete = de.complete; + if (complete.linkDragData) { + const sourceDoc = complete.linkDragData.linkSourceDocument; const destDoc = this.props.document; DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree link"); e.stopPropagation(); } - if (de.complete.docDragData) { + const docDragData = complete.docDragData; + if (docDragData) { e.stopPropagation(); - if (de.complete.docDragData.draggedDocuments[0] === this.props.document) return true; - let addDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before); + if (docDragData.draggedDocuments[0] === this.props.document) return true; + const parentAddDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before); + let addDoc = parentAddDoc; if (inside) { addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce( - ((flg: boolean, doc) => flg && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc)), true) || addDoc(doc); + (flg: boolean, doc) => flg && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc), true) || parentAddDoc(doc); } - const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments); - const move = de.complete.docDragData.dropAction === "move" || de.complete.docDragData.dropAction; - return ((!move && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ? - de.complete.docDragData.droppedDocuments.reduce((added, d) => addDoc(d) || added, false) - : de.complete.docDragData.moveDocument ? - movedDocs.reduce((added, d) => de.complete.docDragData?.moveDocument?.(d, undefined, addDoc) || added, false) - : de.complete.docDragData.droppedDocuments.reduce((added, d) => addDoc(d), false); + const move = (!docDragData.dropAction || docDragData.dropAction === "move" || docDragData.dropAction === "same") && docDragData.moveDocument; + return docDragData.droppedDocuments.reduce((added, d) => (move ? docDragData.moveDocument?.(d, undefined, addDoc) : addDoc(d)) || added, false); } return false; } @@ -662,10 +665,15 @@ export class CollectionTreeView extends CollectionSubView { this.treedropDisposer?.(); if (this._mainEle = ele) { - this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.props.Document); + this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.props.Document, this.onInternalPreDrop.bind(this)); } } + protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { + const dragData = de.complete.docDragData; + dragData && (dragData.dropAction = this.props.Document[Id] === dragData?.treeViewId ? "same" : dragData.dropAction); + } + componentWillUnmount() { super.componentWillUnmount(); this.treedropDisposer?.(); @@ -788,7 +796,8 @@ export class CollectionTreeView extends CollectionSubView c.title === this._currentKey).map(c => c.immediate(de.complete.docDragData?.draggedDocuments || [])); + const docDragData = de.complete.docDragData; + if (docDragData?.draggedDocuments.length) { + this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || [])); e.stopPropagation(); } return true; diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx index 0c5239d66..a4c4663dd 100644 --- a/src/client/views/nodes/DocHolderBox.tsx +++ b/src/client/views/nodes/DocHolderBox.tsx @@ -198,11 +198,10 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { - if (de.complete.docDragData) { - if (de.complete.docDragData.draggedDocuments[0].type === DocumentType.FONTICON) { - const doc = Cast(de.complete.docDragData.draggedDocuments[0].dragFactory, Doc, null); - this.layoutDoc.childLayoutTemplate = doc; - } + const docDragData = de.complete.docDragData; + if (docDragData?.draggedDocuments[0].type === DocumentType.FONTICON) { + const doc = Cast(docDragData.draggedDocuments[0].dragFactory, Doc, null); + this.layoutDoc.childLayoutTemplate = doc; } } protected createDropTarget = (ele: HTMLDivElement) => { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ffab1d1e1..fc5ab50d9 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -283,8 +283,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { - if (de.complete.docDragData) { - const draggedDoc = de.complete.docDragData.draggedDocuments.length && de.complete.docDragData.draggedDocuments[0]; + const dragData = de.complete.docDragData; + if (dragData) { + const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0]; // replace text contents whend dragging with Alt if (draggedDoc && draggedDoc.type === DocumentType.RTF && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) { if (draggedDoc.data instanceof RichTextField) { @@ -292,8 +293,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp e.stopPropagation(); } // embed document when dragging with a userDropAction or an embedDoc flag set - } else if (de.complete.docDragData.userDropAction || de.complete.docDragData.embedDoc) { - const target = de.complete.docDragData.droppedDocuments[0]; + } else if (dragData.userDropAction || dragData.embedDoc) { + const target = dragData.droppedDocuments[0]; // const link = DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "Embedded Doc:" + target.title); // if (link) { target._fitToBox = true; diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 973931615..59c73ed27 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -114,7 +114,8 @@ export default class MobileInkOverlay extends React.Component { altKey: false, metaKey: false, ctrlKey: false, - shiftKey: false + shiftKey: false, + embedKey: false } } ) -- cgit v1.2.3-70-g09d2 From 279e71d098053dc2ca5b69e6e502a95dab230daa Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 15 Jun 2020 11:58:04 -0400 Subject: added a linkView and changed display of docFieldView to inline to allow text wrapping on the same line as the fieldLabel --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 58 ++++++++++++++++++++-- src/client/views/nodes/ComparisonBox.tsx | 6 +-- src/client/views/nodes/DocumentView.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.scss | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 19 ++++--- 6 files changed, 72 insertions(+), 19 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2ecc8c8b7..002bfe6a2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -606,7 +606,6 @@ export namespace Docs { selection: { type: "text", anchor: 1, head: 1 }, storedMarks: [] }; - const field = text ? new RichTextField(JSON.stringify(rtf), text) : undefined; return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey); } @@ -823,7 +822,8 @@ export namespace DocUtils { if (sv && sv.props.ContainingCollectionDoc === target.doc) return; if (target.doc === Doc.UserDoc()) return undefined; - const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship }, id); + const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView" }, id); + linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null); Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2.title'); Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)"); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 0acfb72c6..47672f7c9 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -86,6 +86,52 @@ export class CurrentUserUtils { }); } + if (doc["template-button-link"] === undefined) { + const linkTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created + Doc.GetProto(linkTemplate).layout = + "
" + + " " + + " " + + "
"; + linkTemplate.isTemplateDoc = makeTemplate(linkTemplate, true, "linkView"); + + const rtf2 = { + doc: { + type: "doc", content: [ + { + type: "paragraph", + content: [{ + type: "dashField", + attrs: { + fieldKey: "src", + hideKey: false + } + }] + }, + { type: "paragraph" }, + { + type: "paragraph", + content: [{ + type: "dashField", + attrs: { + fieldKey: "dst", + hideKey: false + } + }] + }] + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + linkTemplate.header = new RichTextField(JSON.stringify(rtf2), ""); + + doc["template-button-link"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory)'), + dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "link view", icon: "window-maximize" + }); + } + if (doc["template-button-switch"] === undefined) { const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create; @@ -168,17 +214,21 @@ export class CurrentUserUtils { }); } + const requiredTypes = [ + doc["template-button-slides"] as Doc, + doc["template-button-description"] as Doc, + doc["template-button-query"] as Doc, + doc["template-button-detail"] as Doc, + doc["template-button-link"] as Doc, + doc["template-button-switch"] as Doc]; if (doc["template-buttons"] === undefined) { - doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, - doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc], { + doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), })); } else { const curButnTypes = Cast(doc["template-buttons"], Doc, null); - const requiredTypes = [doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, - doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc]; DocListCastAsync(curButnTypes.data).then(async curBtns => { await Promise.all(curBtns!); requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype)); diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index cce60628d..14a2c25bf 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -76,12 +76,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { return
e.stopPropagation()} // prevent triggering slider movement in registerSliding - onClick={e => this.clearDoc(e, `${which}Doc`)}> + onClick={e => this.clearDoc(e, `compareBox-${which}`)}>
; }; const displayDoc = (which: string) => { - const whichDoc = Cast(this.dataDoc[`${which}Doc`], Doc, null); + const whichDoc = Cast(this.dataDoc[`compareBox-${which}`], Doc, null); return whichDoc ? <> {clearButton(which)} @@ -93,7 +93,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { return
this.registerSliding(e, cover)} - ref={ele => this.createDropTarget(ele, `${which}Doc`, index)} > + ref={ele => this.createDropTarget(ele, `compareBox-${which}`, index)} > {displayDoc(which)}
; }; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e4e4dfdd6..35bf5344e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -335,7 +335,7 @@ export class DocumentView extends DocComponent(Docu this.props.addDocTab(alias, "onRight"); // UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"); //ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click"); - } else if (this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { + } else if (this.props.Document.links && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); } else { if ((this.props.Document.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part diff --git a/src/client/views/nodes/formattedText/DashFieldView.scss b/src/client/views/nodes/formattedText/DashFieldView.scss index 35ff9c1e6..23cf1e79b 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.scss +++ b/src/client/views/nodes/formattedText/DashFieldView.scss @@ -25,7 +25,7 @@ margin-left: 2px; margin-right: 5px; position: relative; - display: inline-block; + display: inline; background-color: rgba(155, 155, 155, 0.24); span { min-width: 100%; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 9a1b909c1..60a9c2a27 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -103,11 +103,14 @@ export class DashFieldViewInternal extends React.Component { - r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r)); - r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false)); - r?.addEventListener("pointerdown", action((e) => this._showEnumerables = true)); - }} > + return { + r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r)); + r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false)); + r?.addEventListener("pointerdown", action((e) => this._showEnumerables = true)); + }} > {strVal} ; } @@ -205,9 +208,9 @@ export class DashFieldViewInternal extends React.Component} -
- {this.fieldValueContent} -
+ {/*
*/} + {this.fieldValueContent} + {/*
*/} {!this._showEnumerables ? (null) :
} -- cgit v1.2.3-70-g09d2 From 182aef3ef47a3005e1b8a60bad8195769ce07733 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 15 Jun 2020 18:00:25 -0400 Subject: fixed acls for text hyperlinks (mostly) by not allowing links to be traversed --- src/client/DocServer.ts | 7 +++- src/client/views/nodes/DocumentView.tsx | 14 ++++++- .../formattedText/FormattedTextBoxComment.tsx | 46 +++++++++++++--------- src/fields/Doc.ts | 20 ++-------- 4 files changed, 49 insertions(+), 38 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index c6b3fa61f..c7dfb0b23 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,6 +1,6 @@ import * as io from 'socket.io-client'; import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message"; -import { Opt, Doc } from '../fields/Doc'; +import { Opt, Doc, fetchProto } from '../fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; import { RefField } from '../fields/RefField'; @@ -244,7 +244,10 @@ export namespace DocServer { return cached; } else { // CACHED => great, let's just return the cached field we have - return Promise.resolve(cached); + return Promise.resolve(cached).then(field => { + (field instanceof Doc) && fetchProto(field); + return field; + }); } }; const _GetCachedRefFieldImpl = (id: string): Opt => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 35bf5344e..8a067b806 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -687,7 +687,18 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action setAcl = (acl: "readOnly" | "addOnly" | "ownerOnly") => { - this.layoutDoc.ACL = this.dataDoc.ACL = acl; + this.dataDoc.ACL = this.props.Document.ACL = acl; + DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => { + if (d.author === Doc.CurrentUserEmail) d.ACL = acl; + const data = d[DataSym]; + if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl; + }); + } + @undoBatch + @action + testAcl = (acl: "readOnly" | "addOnly" | "ownerOnly") => { + this.dataDoc.author = this.props.Document.author = "ADMIN"; + this.dataDoc.ACL = this.props.Document.ACL = acl; DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => { if (d.author === Doc.CurrentUserEmail) d.ACL = acl; const data = d[DataSym]; @@ -758,6 +769,7 @@ export class DocumentView extends DocComponent(Docu moreItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" }); + moreItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 7513c881d..5ac173602 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -84,11 +84,13 @@ export class FormattedTextBoxComment { const keep = e.target && (e.target as any).type === "checkbox" ? true : false; const textBox = FormattedTextBoxComment.textBox; if (FormattedTextBoxComment.linkDoc && !keep && textBox) { - if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); - } else { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, - (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + if (FormattedTextBoxComment.linkDoc.author) { + if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { + textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); + } else { + DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, + (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } } } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "onRight"); @@ -115,6 +117,23 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = ""); } + static showCommentbox(set: string, view: EditorView, nbef: number) { + const state = view.state; + if (set !== "none") { + // These are in screen coordinates + // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to); + const start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef); + // The box in which the tooltip is positioned, to use as base + const box = (document.getElementsByClassName("mainView-container") as any)[0].getBoundingClientRect(); + // Find a center-ish x position from the selection endpoints (when + // crossing lines, end may be more to the left) + const left = Math.max((start.left + end.left) / 2, start.left + 3); + FormattedTextBoxComment.tooltip.style.left = (left - box.left) + "px"; + FormattedTextBoxComment.tooltip.style.bottom = (box.bottom - start.top) + "px"; + } + FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = set); + } + static update(view: EditorView, lastState?: EditorState, forceUrl: string = "") { const state = view.state; // Don't do anything if the document/selection didn't change @@ -186,7 +205,8 @@ export class FormattedTextBoxComment { if (anchor !== target && anchor && target) { target._scrollY = NumCast(anchor?.y); } - if (target) { + if (target?.author) { + FormattedTextBoxComment.showCommentbox("", view, nbef); ReactDOM.render( { - if (proto.author !== Doc.CurrentUserEmail) { - if (proto.ACL === "ownerOnly") { - proto[AclSym] = doc[AclSym] = AclPrivate; - return undefined; - } else if (proto.ACL === "readOnly") { - proto[AclSym] = doc[AclSym] = AclReadonly; - } else if (proto.ACL === "addOnly") { - proto[AclSym] = doc[AclSym] = AclAddonly; - } - } - }); - return proto; + if (doc.proto instanceof Promise) { + doc.proto.then(proto => fetchProto(proto)); + return doc.proto; } } -- cgit v1.2.3-70-g09d2 From 163e1f579d5a6b111645953b12e665839694585c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 15 Jun 2020 18:22:14 -0400 Subject: fixed testAcl. added testReadonly --- src/client/views/nodes/DocumentView.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8a067b806..d1877c3a0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -700,9 +700,15 @@ export class DocumentView extends DocComponent(Docu this.dataDoc.author = this.props.Document.author = "ADMIN"; this.dataDoc.ACL = this.props.Document.ACL = acl; DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => { - if (d.author === Doc.CurrentUserEmail) d.ACL = acl; + if (d.author === Doc.CurrentUserEmail) { + d.author = "ADMIN"; + d.ACL = acl; + } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl; + if (data && data.author === Doc.CurrentUserEmail) { + data.author = "ADMIN"; + data.ACL = acl; + } }); } @@ -770,6 +776,7 @@ export class DocumentView extends DocComponent(Docu moreItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" }); + moreItems.push({ description: "Test Readonly", event: () => this.testAcl("readOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); -- cgit v1.2.3-70-g09d2 From aee958a85c61927970e55ede004c91a0251a9405 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 15 Jun 2020 23:53:10 -0400 Subject: fixed warnings. fixed linking in textboxes, particularly with :: syntax --- src/client/documents/Documents.ts | 7 +++++-- src/client/views/GestureOverlay.tsx | 8 ++++---- .../collectionFreeForm/InkOptionsMenu.tsx | 22 ++++++++++------------ src/client/views/nodes/ColorBox.tsx | 4 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 15 +++++++-------- src/client/views/nodes/formattedText/marks_rts.ts | 2 +- src/fields/Doc.ts | 2 +- 7 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 002bfe6a2..d1f6c9cea 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -611,7 +611,10 @@ export namespace Docs { } export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) { - const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, { isLinkButton: true, treeViewHideTitle: true, treeViewOpen: false, removeDropProperties: new List(["isBackground", "isLinkButton"]), ...options }); + const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, { + isLinkButton: true, treeViewHideTitle: true, treeViewOpen: false, + removeDropProperties: new List(["isBackground", "isLinkButton"]), ...options + }, id); const linkDocProto = Doc.GetProto(doc); linkDocProto.anchor1 = source.doc; linkDocProto.anchor2 = target.doc; @@ -824,7 +827,7 @@ export namespace DocUtils { const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView" }, id); linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null); - Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2.title'); + Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title'); Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)"); Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)"); diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index f00fd7cb4..e8ed40b38 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -323,7 +323,7 @@ export default class GestureOverlay extends Touchable { this._thumbY = thumb.clientY; this._menuX = thumb.clientX + 50; this._menuY = thumb.clientY; - this._palette = ; + this._palette = ; }); } @@ -806,13 +806,13 @@ export default class GestureOverlay extends Touchable { return [ this.props.children, this._palette, - [this._strokes.map(l => { + [this._strokes.map((l, i) => { const b = this.getBounds(l); - return + return {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape, "none", false)} ; }), - this._points.length <= 1 ? (null) : + this._points.length <= 1 ? (null) : {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape, "none", false)} ] ]; diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx index 5a27f74e5..ae82c6a65 100644 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx @@ -95,16 +95,14 @@ export default class InkOptionsMenu extends AntimodeMenu { } @computed get shapeButtons() { - return <> - {this._buttons.map((btn, i) => )}, - ; + return this._buttons.map((btn, i) => ); } @computed get bezierButton() { @@ -113,7 +111,7 @@ export default class InkOptionsMenu extends AntimodeMenu { title="Bezier changer" key="bezier" onPointerDown={e => this.changeBezier(e)} - style={ { backgroundColor:ActiveInkBezierApprox() ? "121212":"" } }> + style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}> B ; } @@ -121,7 +119,7 @@ export default class InkOptionsMenu extends AntimodeMenu { render() { const buttons = [ , - this.shapeButtons, + ...this.shapeButtons, this.bezierButton, this.widthPicker, this.colorPicker, diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 0d6258cf3..d04da8f5b 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -60,9 +60,9 @@ export class ColorBox extends ViewBoxBaseComponent
{ActiveInkWidth() ?? 2}
- ) => SetActiveInkWidth(e.target.value)} /> + ) => SetActiveInkWidth(e.target.value)} />
{ActiveInkBezierApprox() ?? 2}
- ) => SetActiveBezierApprox(e.target.value)} /> + ) => SetActiveBezierApprox(e.target.value)} />

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index fc5ab50d9..600671179 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -180,7 +180,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.linkOnDeselect.set(key, value); const id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key); - const link = this._editorView.state.schema.marks.link.create({ href: Utils.prepend("/doc/" + id), location: "onRight", title: value }); + const allHrefs = [{ href: Utils.prepend("/doc/" + id), title: value, targetId: id }]; + const link = this._editorView.state.schema.marks.link.create({ allHrefs, location: "onRight", title: value }); const mval = this._editorView.state.schema.marks.metadataVal.create(); const offset = (tx.selection.to === range!.end - 1 ? -1 : 0); tx = tx.addMark(textEndSelection - value.length + offset, textEndSelection, link).addMark(textEndSelection - value.length + offset, textEndSelection, mval); @@ -239,10 +240,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const lastSel = Math.min(flattened.length - 1, this._searchIndex); this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex; const alink = DocUtils.MakeLink({ doc: this.rootDoc }, { doc: target }, "automatic")!; - const link = this._editorView.state.schema.marks.link.create({ - href: Utils.prepend("/doc/" + alink[Id]), - title: "a link", location: location, linkId: alink[Id], targetId: target[Id] - }); + const allHrefs = [{ href: Utils.prepend("/doc/" + alink[Id]), title: "a link", targetId: target[Id], linkId: alink[Id] }]; + const link = this._editorView.state.schema.marks.link.create({ allHrefs, title: "a link", location }); this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link)); } } @@ -1176,7 +1175,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } const mark = e.key !== " " && this._lastTimedMark ? this._lastTimedMark : schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }); this._lastTimedMark = mark; - this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark)); + // this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark)); if (!this._undoTyping) { this._undoTyping = UndoManager.StartBatch("undoTyping"); @@ -1225,9 +1224,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground; if (this.props.isSelected()) { - this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props); + setTimeout(() => this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props), 0); } else if (FormattedTextBoxComment.textBox === this) { - FormattedTextBoxComment.Hide(); + setTimeout(() => FormattedTextBoxComment.Hide(), 0); } return (
fetchProto(proto)); + doc.proto.then(fetchProto); return doc.proto; } } -- cgit v1.2.3-70-g09d2