From 0035bdb42367705293e8d00195075125f196f37f Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Tue, 21 Jan 2020 12:45:31 -0500 Subject: added extra button --- src/server/authentication/models/current_user_utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 5375c8ac8..b383bc8b6 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -115,7 +115,8 @@ export class CurrentUserUtils { { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { width: 300, height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", clipboard: Docs.Create.FreeformDocument([], { width: 300, height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, + { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, + { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ nativeWidth: 10, nativeHeight: 10, width: 10, height: 10, dropAction: data.pointerDown ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick, -- cgit v1.2.3-70-g09d2 From 68d13450bee6e42f2cc60684b4e12beb5c931da9 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Tue, 21 Jan 2020 13:23:20 -0500 Subject: fixed the colorpicker --- src/client/views/GestureOverlay.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 84d089b47..e8d685139 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -24,8 +24,8 @@ import { DocumentContentsView } from "./nodes/DocumentContentsView"; export default class GestureOverlay extends Touchable { static Instance: GestureOverlay; - @observable public Color: string = "rgb(244, 67, 54)"; - @observable public Width: number = 5; + @observable public Color?: string; + @observable public Width?: number; @observable public SavedColor?: string; @observable public SavedWidth?: number; @observable public Tool: ToolglassTools = ToolglassTools.None; @@ -438,7 +438,7 @@ export default class GestureOverlay extends Touchable { return ( - {InteractionUtils.CreatePolyline(this._points, B.left, B.top, this.Color, this.Width)} + {InteractionUtils.CreatePolyline(this._points, B.left, B.top, this.Color ?? InkingControl.Instance.selectedColor, this.Width ?? parseInt(InkingControl.Instance.selectedWidth))} ); } @@ -514,6 +514,7 @@ export default class GestureOverlay extends Touchable { export enum ToolglassTools { InkToText = "inktotext", + IgnoreGesture = "ignoregesture", None = "none", } @@ -531,7 +532,7 @@ Scripting.addGlobal(function setPen(width: any, color: any) { }); Scripting.addGlobal(function resetPen() { runInAction(() => { - GestureOverlay.Instance.Color = GestureOverlay.Instance.SavedColor ?? "rgb(244, 67, 54)"; - GestureOverlay.Instance.Width = GestureOverlay.Instance.SavedWidth ?? 5; + GestureOverlay.Instance.Color = GestureOverlay.Instance.SavedColor ?? undefined; + GestureOverlay.Instance.Width = GestureOverlay.Instance.SavedWidth ?? undefined; }); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 691d5500c0722d0af9ef3b3ab9036042970e75e9 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Tue, 21 Jan 2020 13:35:06 -0500 Subject: cffview nested panning --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 5 +++-- src/client/views/nodes/DocumentView.tsx | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 01b978c81..132bf9c8e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -347,6 +347,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._lastX = pt.pageX; this._lastY = pt.pageY; e.preventDefault(); + e.stopPropagation(); } else { e.preventDefault(); @@ -362,7 +363,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { case GestureUtils.Gestures.Stroke: const points = ge.points; const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); - const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { x: B.x, y: B.y, width: B.width, height: B.height }); + const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { title: "ink stroke", x: B.x, y: B.y, width: B.width, height: B.height }); this.addDocument(inkDoc); e.stopPropagation(); break; @@ -384,7 +385,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } return pass; }); - this.addDocument(Docs.Create.FreeformDocument(sel, { x: bounds.x, y: bounds.y, width: bWidth, height: bHeight, panX: 0, panY: 0 })); + this.addDocument(Docs.Create.FreeformDocument(sel, { title: "nested collection", x: bounds.x, y: bounds.y, width: bWidth, height: bHeight, panX: 0, panY: 0 })); sel.forEach(d => this.props.removeDocument(d)); break; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c35a44860..e0913b154 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -315,10 +315,10 @@ export class DocumentView extends DocComponent(Docu handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent) => { if (this.Document.onPointerDown) return; + const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; + this._downX = touch.clientX; + this._downY = touch.clientY; if (!e.nativeEvent.cancelBubble) { - const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; - this._downX = touch.clientX; - this._downY = touch.clientY; this._hitTemplateDrag = false; for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { -- cgit v1.2.3-70-g09d2 From b04bb12a5942d97eef369936e30b36db62b51f30 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Mon, 27 Jan 2020 19:08:05 -0500 Subject: pen updates --- src/client/util/InteractionUtils.tsx | 5 ++- src/client/views/GestureOverlay.tsx | 52 +++++++++++++++++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 28 ++++++------ src/pen-gestures/ndollar.ts | 7 ++- 5 files changed, 72 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 1fe95474c..ad1d1b5de 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -63,7 +63,7 @@ export namespace InteractionUtils { export function GetMyTargetTouches(mte: InteractionUtils.MultiTouchEvent, prevPoints: Map, ignorePen: boolean): React.Touch[] { const myTouches = new Array(); for (const pt of mte.touches) { - if (!ignorePen || (pt.radiusX > 1 && pt.radiusY > 1)) { + if (!ignorePen || ((pt as any).radiusX > 1 && (pt as any).radiusY > 1)) { for (const tPt of mte.targetTouches) { if (tPt?.screenX === pt?.screenX && tPt?.screenY === pt?.screenY) { if (pt && prevPoints.has(pt.identifier)) { @@ -73,6 +73,9 @@ export namespace InteractionUtils { } } } + if (mte.touches.length !== myTouches.length) { + throw Error("opo") + } return myTouches; } diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index e8d685139..9dd87554f 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -20,6 +20,12 @@ import { DocumentView } from "./nodes/DocumentView"; import { Transform } from "../util/Transform"; import { DocumentContentsView } from "./nodes/DocumentContentsView"; +/** + * This class handles all of the gesture and touch events first. Native touch and pen + * events should be ignored by all classes and handled up here, and this class will interpret + * these events before dispatching our custom Dash gesture and touch events. Classes that want + * to use touch and pen events should handle custom Dash events, as opposed to native events. + */ @observer export default class GestureOverlay extends Touchable { static Instance: GestureOverlay; @@ -54,6 +60,15 @@ export default class GestureOverlay extends Touchable { GestureOverlay.Instance = this; } + /** + * @description + * Given a touch event, returns three arrays that represent the event's targetTouches, + * changedTouches, and touches after filtering out the touch events that are being handled + * as hands. This helps us separate hand events and touch events, as they are different + * events in the mental model that we are pursuing. + * @param e - Touch event to filter + * @returns \{ newTargetTouches, newChangedTouches, newTouches } + */ getNewTouches(e: React.TouchEvent | TouchEvent) { const ntt: (React.Touch | Touch)[] = Array.from(e.targetTouches); const nct: (React.Touch | Touch)[] = Array.from(e.changedTouches); @@ -61,6 +76,7 @@ export default class GestureOverlay extends Touchable { this._hands.forEach((hand) => { for (let i = 0; i < e.targetTouches.length; i++) { const pt = e.targetTouches.item(i); + // if there is a finger in this hand that matches the current point, ignore the current point if (pt && hand.some((finger) => finger.screenX === pt.screenX && finger.screenY === pt.screenY)) { ntt.splice(ntt.indexOf(pt), 1); } @@ -83,7 +99,11 @@ export default class GestureOverlay extends Touchable { return { ntt, nct, nt }; } + /** + * @description Handler for the native React touchStart event. + */ onReactTouchStart = (te: React.TouchEvent) => { + // clean up any ghost points that are remaining but don't actually exist const actualPts: React.Touch[] = []; for (let i = 0; i < te.touches.length; i++) { const pt: any = te.touches.item(i); @@ -91,9 +111,6 @@ export default class GestureOverlay extends Touchable { // pen is also a touch, but with a radius of 0.5 (at least with the surface pens) // and this seems to be the only way of differentiating pen and touch on touch events if (pt.radiusX > 1 && pt.radiusY > 1) { - // if (typeof pt.identifier !== "string") { - // pt.identifier = Utils.GenerateGuid(); - // } this.prevPoints.set(pt.identifier, pt); } } @@ -106,10 +123,11 @@ export default class GestureOverlay extends Touchable { }); ptsToDelete.forEach(pt => this.prevPoints.delete(pt)); - const nts = this.getNewTouches(te); - console.log(nts.nt.length); + // decide whether we should be handling this as a hand event or a touch event + const nts = this.getNewTouches(te); if (nts.nt.length < 5) { + // dispatch a touch event const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY); target?.dispatchEvent( new CustomEvent>("dashOnTouchStart", @@ -131,12 +149,17 @@ export default class GestureOverlay extends Touchable { document.addEventListener("touchend", this.onReactTouchEnd); } else { + // handle this event as a hand event this.handleHandDown(te); document.removeEventListener("touchmove", this.onReactTouchMove); document.removeEventListener("touchend", this.onReactTouchEnd); } } + /** + * @description Handler for the native React touchMove event. Filters and dispatches + * the custom Dash touchMove event. + */ onReactTouchMove = (e: TouchEvent) => { const nts: any = this.getNewTouches(e); document.dispatchEvent( @@ -154,7 +177,11 @@ export default class GestureOverlay extends Touchable { ); } + /** + * @description Handler for the native React touchEnd event. + */ onReactTouchEnd = (e: TouchEvent) => { + // filter and dispatch custom touchEnd event const nts: any = this.getNewTouches(e); document.dispatchEvent( new CustomEvent>("dashOnTouchEnd", @@ -169,6 +196,8 @@ export default class GestureOverlay extends Touchable { } }) ); + + // clean up any points that have ended for (let i = 0; i < e.changedTouches.length; i++) { const pt = e.changedTouches.item(i); if (pt) { @@ -178,6 +207,7 @@ export default class GestureOverlay extends Touchable { } } + // clean up events if (this.prevPoints.size === 0) { document.removeEventListener("touchmove", this.onReactTouchMove); document.removeEventListener("touchend", this.onReactTouchEnd); @@ -185,8 +215,12 @@ export default class GestureOverlay extends Touchable { e.stopPropagation(); } + /** + * @description Handler for "handDown" events + */ handleHandDown = async (e: React.TouchEvent) => { const fingers = new Array(); + // log all the fingers on the hand for (let i = 0; i < e.touches.length; i++) { const pt: any = e.touches.item(i); if (pt.radiusX > 1 && pt.radiusY > 1) { @@ -200,6 +234,8 @@ export default class GestureOverlay extends Touchable { } } } + + // figure out left/right hand and thumb/pointer finger const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]); const rightMost = Math.max(...fingers.map(f => f.clientX)); const leftMost = Math.min(...fingers.map(f => f.clientX)); @@ -229,6 +265,7 @@ export default class GestureOverlay extends Touchable { const minX = Math.min(...others.map(f => f.clientX)); const minY = Math.min(...others.map(f => f.clientY)); + // pull up the palette const thumbDoc = await Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc); if (thumbDoc) { runInAction(() => { @@ -246,6 +283,9 @@ export default class GestureOverlay extends Touchable { document.addEventListener("touchend", this.handleHandUp); } + /** + * @description Handler for "handMove" event + */ @action handleHandMove = (e: TouchEvent) => { const fingers = new Array(); @@ -370,7 +410,7 @@ export default class GestureOverlay extends Touchable { else { const result = GestureUtils.GestureRecognizer.Recognize(new Array(points)); let actionPerformed = false; - if (result && result.Score > 0.7) { + if (result && result.Score > 0.8) { switch (result.Name) { case GestureUtils.Gestures.Box: const target = document.elementFromPoint(this._points[0].X, this._points[0].Y); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 132bf9c8e..a0c75c1b7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -347,7 +347,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._lastX = pt.pageX; this._lastY = pt.pageY; e.preventDefault(); - e.stopPropagation(); + // e.stopPropagation(); } else { e.preventDefault(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e0913b154..82ee1bd63 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -316,21 +316,23 @@ export class DocumentView extends DocComponent(Docu handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent) => { if (this.Document.onPointerDown) return; const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; - this._downX = touch.clientX; - this._downY = touch.clientY; - if (!e.nativeEvent.cancelBubble) { - this._hitTemplateDrag = false; - for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { - if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { - this._hitTemplateDrag = true; + if (touch) { + this._downX = touch.clientX; + this._downY = touch.clientY; + if (!e.nativeEvent.cancelBubble) { + this._hitTemplateDrag = false; + for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { + if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { + this._hitTemplateDrag = true; + } } + if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); + this.removeMoveListeners(); + this.addMoveListeners(); + this.removeEndListeners(); + this.addEndListeners(); + e.stopPropagation(); } - if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); - this.removeMoveListeners(); - this.addMoveListeners(); - this.removeEndListeners(); - this.addEndListeners(); - e.stopPropagation(); } } diff --git a/src/pen-gestures/ndollar.ts b/src/pen-gestures/ndollar.ts index ef5ca38c6..9e15ada2d 100644 --- a/src/pen-gestures/ndollar.ts +++ b/src/pen-gestures/ndollar.ts @@ -168,7 +168,12 @@ export class NDollarRecognizer { // this.Multistrokes = new Array(NumMultistrokes); this.Multistrokes[0] = new Multistroke(GestureUtils.Gestures.Box, useBoundedRotationInvariance, new Array( - new Array(new Point(30, 146), new Point(30, 222), new Point(106, 225), new Point(106, 146), new Point(30, 146)) + new Array( + new Point(30, 146), //new Point(29, 160), new Point(30, 180), new Point(31, 200), + new Point(30, 222), //new Point(50, 219), new Point(70, 225), new Point(90, 230), + new Point(106, 225), //new Point(100, 200), new Point(106, 180), new Point(110, 160), + new Point(106, 146), //new Point(80, 150), new Point(50, 146), + new Point(30, 143)) )); this.Multistrokes[1] = new Multistroke(GestureUtils.Gestures.Line, useBoundedRotationInvariance, new Array( new Array(new Point(12, 347), new Point(119, 347)) -- cgit v1.2.3-70-g09d2 From 4ea58f2d334485edd1c158ed06b27382e5d68a1c Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 30 Jan 2020 11:32:42 -0500 Subject: support for docs as fields using {{}}. and added 't' for making a template. --- src/client/util/RichTextRules.ts | 2 +- src/client/util/RichTextSchema.tsx | 27 ++++++++++++++++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 11 +++++---- 3 files changed, 30 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 00ce3ef73..8411cc6ee 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -101,7 +101,7 @@ export const inpRules = { } }); const node = (state.doc.resolve(start) as any).nodeAfter; - const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid: docId, float: "right", fieldKey: match[2], alias: Utils.GenerateGuid() }); + const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid: docId, float: "right", fieldKey: match[2]?.substring(1), alias: Utils.GenerateGuid() }); const sm = state.storedMarks || undefined; return node ? state.tr.replaceRangeWith(start, end, dashDoc).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; }), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index d1e0f07cb..6821d9858 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -21,6 +21,7 @@ import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { ObjectField } from "../../new_fields/ObjectField"; import { ComputedField } from "../../new_fields/ScriptField"; import { observer } from "mobx-react"; +import { Id } from "../../new_fields/FieldSymbols"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -759,15 +760,33 @@ export class DashDocView { return true; }; const alias = node.attrs.alias; - DocServer.GetRefField(node.attrs.docid + alias).then(async dashDoc => { + + const docid = node.attrs.docid || tbox.props.DataDoc?.[Id] || tbox.dataDoc?.[Id]; + DocServer.GetRefField(docid + alias).then(async dashDoc => { if (!(dashDoc instanceof Doc)) { - alias && DocServer.GetRefField(node.attrs.docid).then(async dashDocBase => { + alias && DocServer.GetRefField(docid).then(async dashDocBase => { if (dashDocBase instanceof Doc) { - self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos); + if (node.attrs.fieldKey) { + const fieldDoc = await self._textBox.dataDoc[node.attrs.fieldKey]; + if (fieldDoc instanceof Doc) { + self.doRender(Doc.MakeAlias(fieldDoc), removeDoc, node, view, getPos); + } else { + this._dashSpan.innerHTML = `field:'${node.attrs.fieldKey}' is not a document`; + } + } else { + self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos); + } } }); } else { - self.doRender(dashDoc, removeDoc, node, view, getPos); + if (node.attrs.fieldKey) { + const fieldDoc = await dashDoc[node.attrs.fieldKey]; + if (fieldDoc instanceof Doc) { + self.doRender(fieldDoc, removeDoc, node, view, getPos); + } + } else { + self.doRender(dashDoc, removeDoc, node, view, getPos); + } } }); const self = this; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6a1590b8e..ef2fc2ad1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -299,7 +299,7 @@ export class MarqueeView extends React.Component { + getCollection = (selected: Doc[], asTemplate: boolean) => { const bounds = this.Bounds; const defaultPalette = ["rgb(114,229,239)", "rgb(255,246,209)", "rgb(255,188,156)", "rgb(247,220,96)", "rgb(122,176,238)", "rgb(209,150,226)", "rgb(127,235,144)", "rgb(252,188,189)", "rgb(247,175,81)",]; @@ -321,7 +321,8 @@ export class MarqueeView extends React.Component usedPaletted.get(a)! < usedPaletted.get(b)! ? -1 : usedPaletted.get(a)! > usedPaletted.get(b)! ? 1 : 0); const chosenColor = (usedPaletted.size === 0) ? "white" : palette.length ? palette[0] : usedSequnce[0]; // const inkData = this.ink ? this.ink.inkData : undefined; - const newCollection = Docs.Create.FreeformDocument(selected, { + const creator = asTemplate ? Docs.Create.StackingDocument : Docs.Create.FreeformDocument; + const newCollection = creator(selected, { x: bounds.left, y: bounds.top, _panX: 0, @@ -353,7 +354,7 @@ export class MarqueeView extends React.Component Date: Thu, 30 Jan 2020 13:40:32 -0500 Subject: fixes to embedded documents --- src/client/util/RichTextSchema.tsx | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 6821d9858..287a1049b 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -766,27 +766,13 @@ export class DashDocView { if (!(dashDoc instanceof Doc)) { alias && DocServer.GetRefField(docid).then(async dashDocBase => { if (dashDocBase instanceof Doc) { - if (node.attrs.fieldKey) { - const fieldDoc = await self._textBox.dataDoc[node.attrs.fieldKey]; - if (fieldDoc instanceof Doc) { - self.doRender(Doc.MakeAlias(fieldDoc), removeDoc, node, view, getPos); - } else { - this._dashSpan.innerHTML = `field:'${node.attrs.fieldKey}' is not a document`; - } - } else { - self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos); - } + const aliasedDoc = Doc.MakeDelegate(dashDocBase, docid + alias); + aliasedDoc.layoutKey = "layout_" + node.attrs.fieldKey; + self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); } else { - if (node.attrs.fieldKey) { - const fieldDoc = await dashDoc[node.attrs.fieldKey]; - if (fieldDoc instanceof Doc) { - self.doRender(fieldDoc, removeDoc, node, view, getPos); - } - } else { - self.doRender(dashDoc, removeDoc, node, view, getPos); - } + self.doRender(dashDoc, removeDoc, node, view, getPos); } }); const self = this; @@ -831,7 +817,7 @@ export class DashDocView { }, { fireImmediately: true }); ReactDOM.render( Date: Thu, 30 Jan 2020 15:48:02 -0500 Subject: small template fixes for text mostly. --- src/client/util/DropConverter.ts | 5 +++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/TemplateMenu.tsx | 12 ++++++------ src/new_fields/Doc.ts | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 669ac5336..d0f1d86cb 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -35,10 +35,11 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { if (!doc.onDragStart && !doc.onClick && !doc.isButtonBar) { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; if (layoutDoc.type === DocumentType.COL || layoutDoc.type === DocumentType.TEXT || layoutDoc.type === DocumentType.IMG) { - layoutDoc.isTemplateDoc = makeTemplate(layoutDoc); + makeTemplate(layoutDoc); } else { - layoutDoc.isTemplateDoc = (layoutDoc.layout instanceof Doc) && !data.userDropAction; + (layoutDoc.layout instanceof Doc) && !data.userDropAction; } + layoutDoc.isTemplateDoc = true; dbox = Docs.Create.FontIconDocument({ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: layoutDoc.isTemplateDoc ? "font" : "bolt" }); dbox.dragFactory = layoutDoc; dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7c4391ec0..c5034b901 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -265,7 +265,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const layoutKey = Cast(dv.props.Document.layoutKey, "string", null); const collapse = layoutKey !== "layout_icon"; if (collapse) { - if (layoutKey) dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", ""); + if (layoutKey && layoutKey !== "layout") dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", ""); dv.setCustomView(collapse, "icon"); } else { const deiconifyLayout = Cast(dv.props.Document.deiconifyLayout, "string", null); diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index d5554fd4f..f61eb9cd0 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -90,22 +90,22 @@ export class TemplateMenu extends React.Component { // todo: add brushes to brushMap to save with a style name onCustomKeypress = (e: React.KeyboardEvent) => { if (e.key === "Enter") { - runInAction(() => TemplateMenu._addedKeys.add(this._customRef.current!.value)); + runInAction(() => this._addedKeys.add(this._customRef.current!.value)); } } componentDidMount() { - !TemplateMenu._addedKeys && (TemplateMenu._addedKeys = new ObservableSet(["narrative"])); + !this._addedKeys && (this._addedKeys = new ObservableSet()); Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))). filter(key => key.startsWith("layout_")). - map(key => runInAction(() => TemplateMenu._addedKeys.add(key.replace("layout_", "")))); + map(key => runInAction(() => this._addedKeys.add(key.replace("layout_", "")))); DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => { if (StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title)) { - runInAction(() => TemplateMenu._addedKeys.add(StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title))); + runInAction(() => this._addedKeys.add(StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title))); } }); } - static _addedKeys = new ObservableSet(["narrative"]); + _addedKeys = new ObservableSet(); _customRef = React.createRef(); render() { const layout = Doc.Layout(this.props.docViews[0].Document); @@ -114,7 +114,7 @@ export class TemplateMenu extends React.Component { templateMenu.push()); templateMenu.push(); templateMenu.push(); - TemplateMenu._addedKeys && Array.from(TemplateMenu._addedKeys).map(layout => + this._addedKeys && Array.from(this._addedKeys).map(layout => templateMenu.push( this.toggleLayout(e, layout)} />) ); return
    diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5f454e930..5f78636a9 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -611,7 +611,7 @@ export namespace Doc { Cast(templateField.data, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateField.data)); } - if (templateField.data instanceof RichTextField && templateField.data.Data) { + if (templateField.data instanceof RichTextField && templateField.data.Text) { templateField._textTemplate = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name }); } -- cgit v1.2.3-70-g09d2 From 17dcf7e4d8c2f038dc3a6168b1ff6b8d3cb15536 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Thu, 30 Jan 2020 18:39:20 -0500 Subject: i think some bugs are fixed --- src/client/util/InteractionUtils.tsx | 6 +++--- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index ad1d1b5de..7194feb2e 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -73,9 +73,9 @@ export namespace InteractionUtils { } } } - if (mte.touches.length !== myTouches.length) { - throw Error("opo") - } + // if (mte.touches.length !== myTouches.length) { + // throw Error("opo") + // } return myTouches; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a0c75c1b7..132bf9c8e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -347,7 +347,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._lastX = pt.pageX; this._lastY = pt.pageY; e.preventDefault(); - // e.stopPropagation(); + e.stopPropagation(); } else { e.preventDefault(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 82ee1bd63..ad28c9b1c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -316,6 +316,7 @@ export class DocumentView extends DocComponent(Docu handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent) => { if (this.Document.onPointerDown) return; const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; + console.log("down"); if (touch) { this._downX = touch.clientX; this._downY = touch.clientY; -- cgit v1.2.3-70-g09d2 From f93abfc577225cc04eb94d67c62eec67d7e22bca Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Jan 2020 22:37:44 -0500 Subject: changed hideSidebar to showSidebar. added contextmenu for choosing pivot field. --- src/client/documents/Documents.ts | 4 +- src/client/util/RichTextSchema.tsx | 1 - src/client/views/ContextMenu.tsx | 4 +- src/client/views/EditableView.tsx | 19 +++++--- .../views/collections/CollectionPivotView.tsx | 51 +++++++++++++++++----- .../CollectionStackingViewFieldColumn.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 1 - src/client/views/nodes/FormattedTextBox.tsx | 6 +-- 8 files changed, 61 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index fa5707288..49c03a96f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -75,7 +75,7 @@ export interface DocumentOptions { _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts _textTemplate?: RichTextField; // template used by a formattedTextBox to create a text box to render _itemIndex?: number; // which item index the carousel viewer is showing - _hideSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts + _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts x?: number; y?: number; z?: number; @@ -340,7 +340,7 @@ export namespace Docs { export namespace Create { const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", - "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_hideSidebar"]; + "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar"]; /** * This function receives the relevant document prototype and uses diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 287a1049b..9e4f06919 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -790,7 +790,6 @@ export class DashDocView { } doRender(dashDoc: Doc, removeDoc: any, node: any, view: any, getPos: any) { this._dashDoc = dashDoc; - dashDoc._hideSidebar = true; if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") { try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc._width + "px", height: dashDoc._height + "px" })); diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index ac803d977..4d04d4e89 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -134,13 +134,13 @@ export class ContextMenu extends React.Component { } @action - displayMenu = (x: number, y: number) => { + displayMenu = (x: number, y: number, initSearch = "") => { //maxX and maxY will change if the UI/font size changes, but will work for any amount //of items added to the menu this._pageX = x; this._pageY = y; - this._searchString = ""; + this._searchString = initSearch; this._shouldDisplay = true; } diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 780c5b2f4..84c6b0dfd 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -46,6 +46,7 @@ export interface EditableProps { onClick?: (e: React.MouseEvent) => boolean; isEditingCallback?: (isEditing: boolean) => void; menuCallback?: (x: number, y: number) => void; + showMenuOnLoad?: boolean; HeadingObject?: SchemaHeaderField | undefined; HeadingsHack?: number; toggle?: () => void; @@ -77,6 +78,8 @@ export class EditableView extends React.Component { } } + _didShow = false; + @action onKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Tab") { @@ -97,16 +100,20 @@ export class EditableView extends React.Component { this._editing = false; this.props.isEditingCallback?.(false); } else if (e.key === ":") { - this.props.menuCallback?.(e.currentTarget.offsetLeft, e.currentTarget.offsetTop); + this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); } } @action onClick = (e: React.MouseEvent) => { e.nativeEvent.stopPropagation(); - if (!this.props.onClick || !this.props.onClick(e)) { - this._editing = true; - this.props.isEditingCallback?.(true); + 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)) { + this._editing = true; + this.props.isEditingCallback?.(true); + } } e.stopPropagation(); } @@ -130,6 +137,7 @@ export class EditableView extends React.Component { return wasFocused !== this._editing; } + _ref = React.createRef(); render() { if (this._editing && this.props.GetValue() !== undefined) { return this.props.autosuggestProps @@ -156,9 +164,10 @@ export class EditableView extends React.Component { style={{ display: this.props.display, fontSize: this.props.fontSize }} />; } else { - if (this.props.autosuggestProps) this.props.autosuggestProps.resetValue(); + this.props.autosuggestProps?.resetValue(); return (this.props.contents instanceof ObjectField ? (null) :
    {this.props.contents} diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index 440b6856b..1a84a34a0 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -16,6 +16,10 @@ import "./CollectionPivotView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionTreeView } from "./CollectionTreeView"; import React = require("react"); +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { RichTextField } from "../../../new_fields/RichTextField"; +import { ImageField } from "../../../new_fields/URLField"; @observer export class CollectionPivotView extends CollectionSubView(doc => doc) { @@ -36,7 +40,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { } } bodyPanelWidth = () => this.props.PanelWidth() - this._facetWidth; - getTransform = () => this.props.ScreenToLocalTransform().translate(-200, 0); + getTransform = () => this.props.ScreenToLocalTransform().translate(-this._facetWidth, 0); @computed get _allFacets() { const facets = new Set(); @@ -98,6 +102,25 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { document.removeEventListener("pointerup", this.onPointerUp); } + menuCallback = (x: number, y: number) => { + ContextMenu.Instance.clearItems(); + const docItems: ContextMenuProps[] = []; + const keySet: Set = new Set(); + + this.childLayoutPairs.map(pair => + Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof (pair.layout[fieldKey]) === "string").map(fieldKey => + keySet.add(fieldKey))); + keySet.toArray().map(fieldKey => + docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" })); + docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" }) + ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" }); + const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); + ContextMenu.Instance.displayMenu(x, y, ":"); + } + + @observable private collapsed: boolean = false; + private toggleVisibility = action(() => this.collapsed = !this.collapsed); + render() { const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null); const flyout = ( @@ -109,20 +132,24 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { )}
    ); + const newEditableViewProps = { + GetValue: () => "", + SetValue: (value: any) => { + if (value?.length) { + this.props.Document.pivotField = value; + return true; + } + return false; + }, + showMenuOnLoad: true, + contents: ":" + StrCast(this.props.Document.pivotField), + toggle: this.toggleVisibility, + color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + }; return !facetCollection ? (null) :
    - StrCast(this.props.Document.pivotField)} - SetValue={value => { - if (value && value.length) { - this.props.Document.pivotField = value; - return true; - } - return false; - }} - /> +
    diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 2a9f903bb..d00ddde6a 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -312,7 +312,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { const funcs: ContextMenuProps[] = []; - funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.toggleSidebar(); }, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar }, icon: "expand-arrows-alt" }); funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ @@ -1101,7 +1101,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
    - {this.props.Document._hideSidebar ? (null) : this.sidebarWidthPercent === "0%" ? + {this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
    this.toggleSidebar()} /> :
    @@ -1118,7 +1118,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} - addDocument={(doc: Doc) => { doc._hideSidebar = true; return this.addDocument(doc); }} + addDocument={(doc: Doc) => { doc._showSidebar = false; return this.addDocument(doc); }} CollectionView={undefined} ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)} renderDepth={this.props.renderDepth + 1} -- cgit v1.2.3-70-g09d2 From 1cb72c720d2e287032bfe586f25ebd941ab3f393 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Jan 2020 23:16:19 -0500 Subject: small fixes to textbox sidebar. requires testing for annotationskey in COllectionSubView's childLayoutPairs --- src/client/views/collections/CollectionSubView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 +++++++------- src/client/views/nodes/FormattedTextBox.tsx | 9 +++++---- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8679c8bd1..9482435a0 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -98,7 +98,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get childLayoutPairs(): { layout: Doc; data: Doc; }[] { const { Document, DataDoc } = this.props; - const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout); + const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout); return validPairs.map(({ data, layout }) => ({ data: data!, layout: layout! })); // this mapping is a bit of a hack to coerce types } get childDocList() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 41ef8c2a6..0022a4dbd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -834,23 +834,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { layoutDocsInGrid = () => { UndoManager.RunInBatch(() => { - const docs = DocListCast(this.Document[this.props.fieldKey]); + const docs = this.childLayoutPairs; const startX = this.Document._panX || 0; let x = startX; let y = this.Document._panY || 0; let i = 0; - const width = Math.max(...docs.map(doc => NumCast(doc._width))); - const height = Math.max(...docs.map(doc => NumCast(doc._height))); - for (const doc of docs) { - doc.x = x; - doc.y = y; + const width = Math.max(...docs.map(doc => NumCast(doc.layout._width))); + const height = Math.max(...docs.map(doc => NumCast(doc.layout._height))); + docs.forEach(pair => { + pair.layout.x = x; + pair.layout.y = y; x += width + 20; if (++i === 6) { i = 0; x = startX; y += height + 20; } - } + }); }, "arrange contents"); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 675f72011..939df2540 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1062,7 +1062,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); } - @computed get sidebarWidth() { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); } + sidebarWidth = () => { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); } + sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0); @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } render() { TraceMobx(); @@ -1107,7 +1108,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}> this.sidebarWidth} + PanelWidth={this.sidebarWidth} annotationsKey={this.annotationKey} isAnnotationOverlay={false} focus={this.props.focus} @@ -1118,9 +1119,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} - addDocument={(doc: Doc) => { doc._showSidebar = false; return this.addDocument(doc); }} + addDocument={this.addDocument} CollectionView={undefined} - ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)} + ScreenToLocalTransform={this.sidebarScreenToLocal} renderDepth={this.props.renderDepth + 1} ContainingCollectionDoc={this.props.ContainingCollectionDoc} chromeCollapsed={true}> -- cgit v1.2.3-70-g09d2 From e2acceaaf0a0235513951dca1c33e63183d61661 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Jan 2020 23:55:58 -0500 Subject: fixed zoomin in presentation mode --- src/client/util/DocumentManager.ts | 2 +- src/client/views/nodes/DocumentView.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index fb4c2155a..f024b9116 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -140,7 +140,7 @@ export class DocumentManager { if (first) annotatedDoc = first.props.Document; } if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? - docView.props.focus(docView.props.Document, false); + docView.props.focus(docView.props.Document, willZoom); highlight(); } else { const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a7413d460..82382c536 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -713,6 +713,7 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" }); subitems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" }); + subitems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); @@ -764,8 +765,6 @@ export class DocumentView extends DocComponent(Docu moreItems.push({ description: "Tag Child Images via Google Photos", event: () => GooglePhotos.Query.TagChildImages(this.props.Document), icon: "caret-square-right" }); moreItems.push({ description: "Write Back Link to Album", event: () => GooglePhotos.Transactions.AddTextEnrichment(this.props.Document), icon: "caret-square-right" }); } - moreItems.push({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin" }); //I think this should work... and it does! A miracle! - moreItems.push({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); moreItems.push({ description: "Download document", icon: "download", event: async () => console.log(JSON.parse(await rp.get(Utils.CorsProxy("http://localhost:8983/solr/dash/select"), { @@ -823,6 +822,7 @@ export class DocumentView extends DocComponent(Docu } }); const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc().LibraryBtn as Doc).sourcePanel as Doc) ? "" : d.title), ""); + cm.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin" }); cm.addItem({ description: `path: ${path}`, event: () => { this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true); -- cgit v1.2.3-70-g09d2 From b74b5888c7c0eee6c0f7a7e8f6d44b9a21b46f0b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 31 Jan 2020 00:09:07 -0500 Subject: from last --- src/client/views/presentationview/PresElementBox.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index 34c170be2..ac78babef 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -43,9 +43,11 @@ } .presElementBox-closeIcon { - float: right; border-radius: 20px; transform:scale(0.7); + position: absolute; + right: 0; + top: 0; } .presElementBox-interaction { -- cgit v1.2.3-70-g09d2 From f4662822d9dd3280e843c3f088aee310352705ae Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 31 Jan 2020 09:03:55 -0500 Subject: streamlined presentationview --- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/nodes/PresBox.scss | 4 +--- src/client/views/nodes/PresBox.tsx | 6 +++--- .../views/presentationview/PresElementBox.scss | 20 +++++++++++++++----- .../authentication/models/current_user_utils.ts | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 82cb3bc88..159a1cded 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -643,7 +643,7 @@ export class DockedFrameRenderer extends React.Component { //add this new doc to props.Document const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; if (curPres) { - const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); + const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5 }); Doc.GetProto(pinDoc).presentationTargetDoc = doc; Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title?.toString()'); const data = Cast(curPres.data, listSpec(Doc)); diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index e5a79ab11..01e7f4834 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -6,7 +6,7 @@ top: 0; bottom: 0; width: 100%; - min-width: 200px; + min-width: 100px; height: 100%; min-height: 50px; letter-spacing: 2px; @@ -16,8 +16,6 @@ .presBox-listCont { position: relative; - padding-left: 10px; - padding-right: 10px; } .presBox-buttons { diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 428e9aa7b..8d53f45a6 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -42,7 +42,7 @@ export class PresBox extends React.Component { if (value) { value.forEach((item, i) => { if (item instanceof Doc && item.type !== DocumentType.PRESELEMENT) { - const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); + const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5 }); Doc.GetProto(pinDoc).presentationTargetDoc = item; Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('this.presentationTargetDoc?.title?.toString()'); value.splice(i, 1, pinDoc); @@ -337,7 +337,7 @@ export class PresBox extends React.Component { @action initializeScaleViews = (docList: Doc[], viewtype: number) => { this.props.Document._chromeStatus = "disabled"; - const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 72; + const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 42; docList.forEach((doc: Doc) => { doc.presBox = this.props.Document; doc.presBoxKey = this.props.fieldKey; @@ -357,7 +357,7 @@ export class PresBox extends React.Component { } getTransform = () => { - return this.props.ScreenToLocalTransform().translate(-10, -50);// listBox padding-left and pres-box-cont minHeight + return this.props.ScreenToLocalTransform().translate(0, -50);// listBox padding-left and pres-box-cont minHeight } render() { this.initializeScaleViews(this.childDocs, NumCast(this.props.Document._viewType)); diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index ac78babef..b74b07224 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -6,14 +6,17 @@ width: 100%; outline-color: maroon; outline-style: dashed; - border-radius: 12px; + border-radius: 6px; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; - transition: all .1s; + transition: all .1s; + padding: 0px; + padding-left: 5px; + padding-bottom: 3px; .documentView-node { position: absolute; @@ -32,13 +35,13 @@ .presElementBox-item:hover { transition: all .1s; background: #AAAAAA; - border-radius: 12px; + border-radius: 6px; } .presElementBox-selected { background: gray; color: black; - border-radius: 12px; + border-radius: 6px; box-shadow: black 2px 2px 5px; } @@ -48,20 +51,27 @@ position: absolute; right: 0; top: 0; + padding: 8px; } .presElementBox-interaction { color: gray; float: left; + padding: 0px; + width: 20px; + height: 20px; } .presElementBox-interaction-selected { color: white; float: left; + padding: 0px; + width: 22px; + height: 22px; } .presElementBox-name { - font-size: 15px; + font-size: 12px; position: absolute; display: inline-block; width: calc(100% - 45px); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index dbde351b3..6bfc729de 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -55,7 +55,7 @@ export class CurrentUserUtils { { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' }, { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "presentation", icon: "tv", ignoreClick: true, drag: `Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { _width: 200, _height: 500, _viewType: ${CollectionViewType.Stacking}, title: "a presentation trail" })` }, + { title: "presentation", icon: "tv", ignoreClick: true, drag: `Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { _width: 200, _height: 500, _xMargin:5, _viewType: ${CollectionViewType.Stacking}, title: "a presentation trail" })` }, { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, -- cgit v1.2.3-70-g09d2 From b0544ea44ef78a93deb9290815f95d6d9308447d Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 31 Jan 2020 10:12:32 -0500 Subject: fixed text labeling in pivot view --- .../CollectionFreeFormLayoutEngines.tsx | 38 +++++++++++++++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 3 +- 3 files changed, 32 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index be1317b25..18ca71c2a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -4,7 +4,7 @@ import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; import { ScriptField } from "../../../../new_fields/ScriptField"; import { OverlayView, OverlayElementOptions } from "../../OverlayView"; -import { emptyFunction } from "../../../../Utils"; +import { emptyFunction, aggregateBounds } from "../../../../Utils"; import React = require("react"); import { ObservableMap, runInAction } from "mobx"; import { Id, ToString } from "../../../../new_fields/FieldSymbols"; @@ -42,7 +42,13 @@ function toLabel(target: FieldResult) { return String(target); } -export function computePivotLayout(poolData: ObservableMap, pivotDoc: Doc, childDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[]) { +export function computePivotLayout( + poolData: ObservableMap, + pivotDoc: Doc, + pwidth: number, pheight: number, + childDocs: Doc[], + childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[] +) { const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 200); const pivotColumnGroups = new Map, Doc[]>(); @@ -99,21 +105,37 @@ export function computePivotLayout(poolData: ObservableMap, pivotDo x += pivotAxisWidth * (numCols * expander + gap); }); + const grpEles = groupNames.map(gn => { return { x: gn.x, y: gn.y, width: gn.width, height: gn.height }; }); + const docEles = childPairs.map(pair => { + const newPos = docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y) }; // new pos is computed pos, or pos written to the document's fields + return { + x: newPos.x, + y: newPos.y, + width: NumCast(pair.layout._width), + height: NumCast(pair.layout._height) + }; + } + ); + const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0); + + const scale = Math.min(pheight / (aggBounds.b - aggBounds.y), pwidth / (aggBounds.r - aggBounds.x)); + childPairs.map(pair => { - const defaultPosition = { + const fallbackPos = { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y), z: NumCast(pair.layout.z), width: NumCast(pair.layout._width), height: NumCast(pair.layout._height) }; - const pos = docMap.get(pair.layout) || defaultPosition; - const data = poolData.get(pair.layout[Id]); - if (!data || pos.x !== data.x || pos.y !== data.y || pos.z !== data.z || pos.width !== data.width || pos.height !== data.height) { - runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...pos })); + const newPosRaw = docMap.get(pair.layout) || fallbackPos; // new pos is computed pos, or pos written to the document's fields + const newPos = { x: newPosRaw.x * scale, y: newPosRaw.y * scale, z: newPosRaw.z, width: newPosRaw.width * scale, height: newPosRaw.height * scale }; + const lastPos = poolData.get(pair.layout[Id]); // last computed pos + if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.width !== lastPos.width || newPos.height !== lastPos.height) { + runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos })); } }); - return { elements: viewDefsToJSX(groupNames) }; + return { elements: viewDefsToJSX(groupNames.map(gname => { return { type: gname.type, text: gname.text, x: gname.x * scale, y: gname.y * scale, width: gname.width * scale, height: gname.height, fontSize: gname.fontSize } })) }; } export function AddCustomFreeFormLayout(doc: Doc, dataKey: string): () => void { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0022a4dbd..90bed2899 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -776,7 +776,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }.bind(this)); doPivotLayout(poolData: ObservableMap) { - return computePivotLayout(poolData, this.props.Document, this.childDocs, + return computePivotLayout(poolData, this.props.Document, this.props.PanelWidth(), this.props.PanelHeight(), this.childDocs, this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)), [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 939df2540..fe9b8e0ff 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1070,8 +1070,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground; if (this.props.isSelected()) { - // TODO: ftong --> update from dash in richtextmenu - RichTextMenu.Instance.updateFromDash(this._editorView!, undefined, this.props); + this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props); } else if (FormattedTextBoxComment.textBox === this) { FormattedTextBoxComment.Hide(); } -- cgit v1.2.3-70-g09d2