From 173863d85ee590c276bf22b1cfe91e0d00986720 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 6 Sep 2019 13:45:04 -0400 Subject: added named target docs from rich text. --- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 27eafd769..5015ee39a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -93,9 +93,8 @@ export class MarqueeView extends React.Component } }); } else if (!e.ctrlKey) { - let newBox = Docs.Create.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); - newBox.proto!.autoHeight = true; - this.props.addLiveTextDocument(newBox); + this.props.addLiveTextDocument( + Docs.Create.TextDocument({ width: 200, height: 100, x: x, y: y, autoHeight: true, title: "-typed text-" })); } e.stopPropagation(); } -- cgit v1.2.3-70-g09d2 From 2d21fff15510d6eeb8975cc2459f69ca28d86d1d Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 9 Sep 2019 17:26:27 -0400 Subject: added stand-in spatial parser. --- src/client/util/TooltipTextMenu.tsx | 11 +++++++++++ src/client/views/DocumentDecorations.tsx | 6 ++++++ src/client/views/InkingControl.tsx | 7 ++++++- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +++++++++++++ .../views/collections/collectionFreeForm/MarqueeView.tsx | 1 + src/client/views/nodes/FormattedTextBox.tsx | 10 ++++++++++ 6 files changed, 47 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 020c51c36..c376b6f86 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -18,6 +18,7 @@ import { DragManager } from "./DragManager"; import { LinkManager } from "./LinkManager"; import { schema } from "./RichTextSchema"; import "./TooltipTextMenu.scss"; +import { Cast, NumCast } from '../../new_fields/Types'; const { toggleMark, setBlockType } = require("prosemirror-commands"); const { openPrompt, TextField } = require("./ProsemirrorCopy/prompt.js"); @@ -495,10 +496,20 @@ export class TooltipTextMenu { if (markType.name[0] === 'p') { let size = this.fontSizeToNum.get(markType); if (size) { this.updateFontSizeDropdown(String(size) + " pt"); } + let ruleProvider = Cast(this.editorProps.Document.ruleProvider, Doc) as Doc; + let heading = NumCast(this.editorProps.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleSize_" + heading] = size; + } } else { let fontName = this.fontStylesToName.get(markType); if (fontName) { this.updateFontStyleDropdown(fontName); } + let ruleProvider = Cast(this.editorProps.Document.ruleProvider, Doc) as Doc; + let heading = NumCast(this.editorProps.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleFont_" + heading] = fontName; + } } //actually apply font return toggleMark(markType)(view.state, view.dispatch, view); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 700a4b49d..7cdb16f52 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -428,6 +428,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1])); SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). map(d => d.borderRounding = `${Math.min(100, dist)}%`); + SelectionManager.SelectedDocuments().map(dv => { + let cv = dv.props.ContainingCollectionView; + let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); + let heading = NumCast(dv.props.Document.heading); + cv && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleRounding_" + heading] = StrCast(dv.props.Document.borderRounding)); + }) e.stopPropagation(); e.preventDefault(); } diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 3f40642b5..eb6312e78 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -9,7 +9,7 @@ import { SelectionManager } from "../util/SelectionManager"; import { InkTool } from "../../new_fields/InkField"; import { Doc } from "../../new_fields/Doc"; import { undoBatch, UndoManager } from "../util/UndoManager"; -import { StrCast } from "../../new_fields/Types"; +import { StrCast, NumCast, Cast } from "../../new_fields/Types"; import { FormattedTextBox } from "./nodes/FormattedTextBox"; import { MainOverlayTextBox } from "./MainOverlayTextBox"; @@ -50,6 +50,11 @@ export class InkingControl extends React.Component { let targetDoc = view.props.Document.layout instanceof Doc ? view.props.Document.layout : view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); let oldColor = StrCast(targetDoc.backgroundColor); targetDoc.backgroundColor = this._selectedColor; + if (view.props.Document.heading) { + let cv = view.props.ContainingCollectionView; + let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); + cv && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = this._selectedColor); + } return { target: targetDoc, previous: oldColor diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2ec2b0671..f7c1bedbb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -256,6 +256,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); private addLiveTextBox = (newBox: Doc) => { FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed + newBox.heading = 1; + for (let i = 0; i < this.childDocs.length; i++) { + if (this.childDocs[i].heading == 1) { + newBox.heading = 2; + } + } + let ruleProvider = Cast(this.props.Document.ruleProvider, Doc); + if (!(ruleProvider instanceof Doc)) ruleProvider = this.props.Document; + let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); + let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]); + round && (newBox.borderRounding = round); + col && (newBox.backgroundColor = col); + newBox.ruleProvider = ruleProvider; this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 5015ee39a..100e6d817 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -329,6 +329,7 @@ export class MarqueeView extends React.Component this.props.addLiveTextDocument(summary); } else { + newCollection.ruleProvider = this.props.container.props.Document; this.props.addDocument(newCollection, false); this.props.selectDocuments([newCollection]); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ae1393fc4..93c97fa23 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -665,6 +665,16 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe else if (this.props.isOverlay) this._editorView!.focus(); // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet. this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: timenow() })]; + let heading = this.props.Document.heading; + if (heading) { + let ruleProvider = Cast(this.props.Document.ruleProvider, Doc); + if (ruleProvider instanceof Doc) { + let font = StrCast(ruleProvider["ruleFont_" + heading]); + let size = NumCast(ruleProvider["ruleSize_" + heading]); + size && (this._editorView!.state.storedMarks = [...this._editorView!.state.storedMarks, schema.marks.pFontSize.create({ fontSize: size })]); + font && (this._editorView!.state.storedMarks = [...this._editorView!.state.storedMarks, font === "Arial" ? schema.marks.arial.create() : schema.marks.comicSans.create()]); + } + } } componentWillUnmount() { -- cgit v1.2.3-70-g09d2 From 5ea7e3318620865146318e0f3826b6f13aec0675 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 10 Sep 2019 13:38:16 -0400 Subject: added more support for creating stylized layouts --- src/Utils.ts | 92 ++++++++++++++++++++++ src/client/util/ProsemirrorExampleTransfer.ts | 5 -- src/client/util/RichTextRules.ts | 40 ++++++++++ src/client/util/RichTextSchema.tsx | 19 +++++ src/client/views/ContextMenu.tsx | 1 + src/client/views/DocumentDecorations.tsx | 5 ++ src/client/views/InkingControl.tsx | 32 +++++++- .../collectionFreeForm/CollectionFreeFormView.tsx | 27 ++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 26 +++++- src/client/views/nodes/FormattedTextBox.tsx | 48 ++++++++--- .../authentication/models/current_user_utils.ts | 20 ++--- 11 files changed, 270 insertions(+), 45 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index f805ae872..3921a49c3 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -53,6 +53,98 @@ export class Utils { document.body.removeChild(textArea); } + public static fromRGBAstr(rgba: string) { + let rm = rgba.match(/rgb[a]?\(([0-9]+)/); + let r = rm ? Number(rm[1]) : 0; + let gm = rgba.match(/rgb[a]?\([0-9]+,([0-9]+)/); + let g = gm ? Number(gm[1]) : 0; + let bm = rgba.match(/rgb[a]?\([0-9]+,[0-9]+,([0-9]+)/); + let b = bm ? Number(bm[1]) : 0; + let am = rgba.match(/rgba?\([0-9]+,[0-9]+,[0-9]+,([0-9]+)/); + let a = am ? Number(am[1]) : 0; + return { r: r, g: g, b: b, a: a }; + } + public static toRGBAstr(col: { r: number, g: number, b: number, a?: number }) { + return "rgba(" + col.r + "," + col.g + "," + col.b + (col.a !== undefined ? "," + col.a : "") + ")"; + } + + public static HSLtoRGB(h: number, s: number, l: number) { + // Must be fractions of 1 + // s /= 100; + // l /= 100; + + let c = (1 - Math.abs(2 * l - 1)) * s, + x = c * (1 - Math.abs((h / 60) % 2 - 1)), + m = l - c / 2, + r = 0, + g = 0, + b = 0; + if (0 <= h && h < 60) { + r = c; g = x; b = 0; + } else if (60 <= h && h < 120) { + r = x; g = c; b = 0; + } else if (120 <= h && h < 180) { + r = 0; g = c; b = x; + } else if (180 <= h && h < 240) { + r = 0; g = x; b = c; + } else if (240 <= h && h < 300) { + r = x; g = 0; b = c; + } else if (300 <= h && h < 360) { + r = c; g = 0; b = x; + } + r = Math.round((r + m) * 255); + g = Math.round((g + m) * 255); + b = Math.round((b + m) * 255); + return { r: r, g: g, b: b }; + } + + public static RGBToHSL(r: number, g: number, b: number) { + // Make r, g, and b fractions of 1 + r /= 255; + g /= 255; + b /= 255; + + // Find greatest and smallest channel values + let cmin = Math.min(r, g, b), + cmax = Math.max(r, g, b), + delta = cmax - cmin, + h = 0, + s = 0, + l = 0; + // Calculate hue + + // No difference + if (delta == 0) + h = 0; + // Red is max + else if (cmax == r) + h = ((g - b) / delta) % 6; + // Green is max + else if (cmax == g) + h = (b - r) / delta + 2; + // Blue is max + else + h = (r - g) / delta + 4; + + h = Math.round(h * 60); + + // Make negative hues positive behind 360° + if (h < 0) + h += 360; // Calculate lightness + + l = (cmax + cmin) / 2; + + // Calculate saturation + s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + + // Multiply l and s by 100 + // s = +(s * 100).toFixed(1); + // l = +(l * 100).toFixed(1); + + return { h: h, s: s, l: l }; + } + + public static GetClipboardText(): string { var textArea = document.createElement("textarea"); document.body.appendChild(textArea); diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index bac0177ad..1d2d33800 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -14,7 +14,6 @@ export type KeyMap = { [key: string]: any }; export default function buildKeymap>(schema: S, mapKeys?: KeyMap): KeyMap { let keys: { [key: string]: any } = {}, type; - keys["ACTIVE"] = false; function bind(key: string, cmd: any) { if (mapKeys) { let mapped = mapKeys[key]; @@ -148,10 +147,6 @@ export default function buildKeymap>(schema: S, mapKeys?: return tx; } bind("Enter", (state: EditorState, dispatch: (tx: Transaction) => void) => { - if (!keys["ACTIVE"]) {// hack to ignore an initial carriage return when creating a textbox from the action menu - dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from - 1, state.selection.from)).deleteSelection()); - return true; - } var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); if (!splitListItem(schema.nodes.list_item)(state, (tx3: Transaction) => dispatch(tx3))) { if (!splitBlockKeepMarks(state, (tx3: Transaction) => { diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 5d1131410..00e671db9 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -2,6 +2,9 @@ import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from import { schema } from "./RichTextSchema"; import { wrappingInputRule } from "./prosemirrorPatches"; import { NodeSelection } from "prosemirror-state"; +import { NumCast, Cast } from "../../new_fields/Types"; +import { Doc } from "../../new_fields/Doc"; +import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; export const inpRules = { rules: [ @@ -57,6 +60,12 @@ export const inpRules = { new InputRule( new RegExp(/^#([0-9]+)\s$/), (state, match, start, end) => { + let size = Number(match[1]); + let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleSize_" + heading] = size; + } return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: Number(match[1]) })) }), new InputRule( @@ -64,9 +73,40 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; + let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleAlign_" + heading] = "center"; + } return node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "center" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; }), + new InputRule( + new RegExp(/^\[\[\s$/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleAlign_" + heading] = "left"; + } + return node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "left" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + }), + new InputRule( + new RegExp(/^\]\]\s$/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleAlign_" + heading] = "right"; + } + return node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "right" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + }), new InputRule( new RegExp(/\^f\s$/), (state, match, start, end) => { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 3def4a579..f027a4bf7 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -12,6 +12,7 @@ import { DocServer } from "../DocServer"; import { Cast, NumCast } from "../../new_fields/Types"; import { DocumentManager } from "./DocumentManager"; import ParagraphNodeSpec from "./ParagraphNodeSpec"; +import { times } from "async"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -422,6 +423,24 @@ export const marks: { [index: string]: MarkSpec } = { toDOM() { return codeDOM; } }, + // pFontFamily: { + // attrs: { + // style: { default: 'font-family: "Times New Roman", Times, serif;' }, + // }, + // parseDOM: [{ + // tag: "span", getAttrs(dom: any) { + // if (getComputedStyle(dom).font === "Times New Roman") return { style: `font-family: "Times New Roman", Times, serif;` }; + // if (getComputedStyle(dom).font === "Arial, Helvetica") return { style: `font-family: Arial, Helvetica, sans-serif;` }; + // if (getComputedStyle(dom).font === "Georgia") return { style: `font-family: Georgia, serif;` }; + // if (getComputedStyle(dom).font === "Comic Sans") return { style: `font-family: "Comic Sans MS", cursive, sans-serif;` }; + // if (getComputedStyle(dom).font === "Tahoma, Geneva") return { style: `font-family: Tahoma, Geneva, sans-serif;` }; + // } + // }], + // toDOM: (node: any) => ['span', { + // style: node.attrs.style + // }] + // }, + /* FONTS */ timesNewRoman: { diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 890bfdfb7..68b97f2b6 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -250,6 +250,7 @@ export class ContextMenu extends React.Component { const item = this.flatItems[this.selectedIndex]; item && item.event(); this.closeMenu(); + e.preventDefault(); } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7cdb16f52..94aab8b2f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -621,6 +621,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> doc.y = (doc.y || 0) + dY * (actualdH - height); let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... let fixedAspect = e.ctrlKey || (!BoolCast(doc.ignoreAspect) && nwidth && nheight); + if (fixedAspect && e.ctrlKey && BoolCast(doc.ignoreAspect)) { + doc.ignoreAspect = false; + proto.nativeWidth = nwidth = doc.width || 0; + proto.nativeHeight = nheight = doc.height || 0; + } if (fixedAspect && (!nwidth || !nheight)) { proto.nativeWidth = nwidth = doc.width || 0; proto.nativeHeight = nheight = doc.height || 0; diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index eb6312e78..519792308 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -10,8 +10,10 @@ import { InkTool } from "../../new_fields/InkField"; import { Doc } from "../../new_fields/Doc"; import { undoBatch, UndoManager } from "../util/UndoManager"; import { StrCast, NumCast, Cast } from "../../new_fields/Types"; -import { FormattedTextBox } from "./nodes/FormattedTextBox"; import { MainOverlayTextBox } from "./MainOverlayTextBox"; +import { listSpec } from "../../new_fields/Schema"; +import { List } from "../../new_fields/List"; +import { Utils } from "../../Utils"; library.add(faPen, faHighlighter, faEraser, faBan); @@ -49,11 +51,34 @@ export class InkingControl extends React.Component { let oldColors = selected.map(view => { let targetDoc = view.props.Document.layout instanceof Doc ? view.props.Document.layout : view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); let oldColor = StrCast(targetDoc.backgroundColor); - targetDoc.backgroundColor = this._selectedColor; + if (view.props.ContainingCollectionView && view.props.ContainingCollectionView.props.Document.colorPalette) { + let cp = Cast(view.props.ContainingCollectionView.props.Document.colorPalette, listSpec("string")) as string[]; + let closest = 0; + let dist = 10000000; + let ccol = Utils.fromRGBAstr(StrCast(targetDoc.backgroundColor)); + for (let i = 0; i < cp.length; i++) { + let cpcol = Utils.fromRGBAstr(cp[i]); + let d = Math.sqrt((ccol.r - cpcol.r) * (ccol.r - cpcol.r) + (ccol.b - cpcol.b) * (ccol.b - cpcol.b) + (ccol.g - cpcol.g) * (ccol.g - cpcol.g)); + if (d < dist) { + dist = d; + closest = i; + } + } + cp[closest] = "rgb(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + ")"; + view.props.ContainingCollectionView.props.Document.colorPalette = new List(cp); + targetDoc.backgroundColor = cp[closest]; + } else + targetDoc.backgroundColor = this._selectedColor; if (view.props.Document.heading) { let cv = view.props.ContainingCollectionView; let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); - cv && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = this._selectedColor); + let parback = cv && StrCast(cv.props.Document.backgroundColor); + cv && parback && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); + // if (parback && cv && parback.indexOf("rgb") !== -1) { + // let parcol = Utils.fromRGBAstr(parback); + // let hsl = Utils.RGBToHSL(parcol.r, parcol.g, parcol.b); + // cv && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = color.hsl.s - hsl.s); + // } } return { target: targetDoc, @@ -67,7 +92,6 @@ export class InkingControl extends React.Component { }); } }); - @action switchWidth = (width: string): void => { this._selectedWidth = width; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f7c1bedbb..c9b2c30b1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -8,7 +8,7 @@ import { Id } from "../../../../new_fields/FieldSymbols"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { createSchema, makeInterface } from "../../../../new_fields/Schema"; import { ScriptField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; +import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../../new_fields/Types"; import { emptyFunction, returnEmptyString, returnOne, Utils } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { Docs } from "../../../documents/Documents"; @@ -262,14 +262,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { newBox.heading = 2; } } - let ruleProvider = Cast(this.props.Document.ruleProvider, Doc); - if (!(ruleProvider instanceof Doc)) ruleProvider = this.props.Document; - let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); - let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]); - round && (newBox.borderRounding = round); - col && (newBox.backgroundColor = col); - newBox.ruleProvider = ruleProvider; - this.addDocument(newBox, false); + PromiseValue(Cast(this.props.Document.ruleProvider, Doc)).then(ruleProvider => { + if (!ruleProvider) ruleProvider = this.props.Document; + // saturation shift + // let col = NumCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); + // let back = Utils.fromRGBAstr(StrCast(this.props.Document.backgroundColor)); + // let hsl = Utils.RGBToHSL(back.r, back.g, back.b); + // let newcol = { h: hsl.h, s: hsl.s + col, l: hsl.l }; + // col && (Doc.GetProto(newBox).backgroundColor = Utils.toRGBAstr(Utils.HSLtoRGB(newcol.h, newcol.s, newcol.l))); + // OR transparency set + let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); + col && (Doc.GetProto(newBox).backgroundColor = col); + + let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]); + round && (newBox.borderRounding = round); + newBox.ruleProvider = ruleProvider; + this.addDocument(newBox, false); + }); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { this.props.addDocument(newBox, false); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 100e6d817..56d8127e2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,11 +1,11 @@ import * as htmlToImage from "html-to-image"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, FieldResult } from "../../../../new_fields/Doc"; +import { Doc, FieldResult, DocListCast } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; -import { Cast, NumCast } from "../../../../new_fields/Types"; +import { Cast, NumCast, StrCast } from "../../../../new_fields/Types"; import { Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; @@ -20,6 +20,8 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); import { SchemaHeaderField, RandomPastel } from "../../../../new_fields/SchemaHeaderField"; +import { string } from "prop-types"; +import { listSpec } from "../../../../new_fields/Schema"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -272,14 +274,30 @@ export class MarqueeView extends React.Component return d; }); } + let 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)",]; + let colorPalette = Cast(this.props.container.props.Document.colorPalette, listSpec("string")); + if (!colorPalette) this.props.container.props.Document.colorPalette = new List(defaultPalette); + let palette = Array.from(Cast(this.props.container.props.Document.colorPalette, listSpec("string")) as string[]); + let usedPaletted = new Map(); + [...this.props.activeDocuments(), this.props.container.props.Document].map(child => { + let bg = StrCast(child.backgroundColor); + if (palette.indexOf(bg) !== -1) { + palette.splice(palette.indexOf(bg), 1); + if (usedPaletted.get(bg)) usedPaletted.set(bg, usedPaletted.get(bg)! + 1); + else usedPaletted.set(bg, 1); + } + }); + let usedSequnce = Array.from(usedPaletted.keys()).sort((a, b) => usedPaletted.get(a)! < usedPaletted.get(b)! ? -1 : usedPaletted.get(a)! > usedPaletted.get(b)! ? 1 : 0); + let chosenColor = usedPaletted.get("white") || usedPaletted.get("rgb(255,255,255)") && usedPaletted.size === 1 ? "white" : palette.length ? palette[0] : usedSequnce[0]; let inkData = this.ink ? this.ink.inkData : undefined; let newCollection = Docs.Create.FreeformDocument(selected, { x: bounds.left, y: bounds.top, panX: 0, panY: 0, - backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", - defaultBackgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", + backgroundColor: this.props.container.isAnnotationOverlay ? undefined : chosenColor, + defaultBackgroundColor: this.props.container.isAnnotationOverlay ? undefined : chosenColor, width: bounds.width, height: bounds.height, title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection", diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 6a6000dc5..0ea36cdc2 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -13,7 +13,7 @@ import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc"; import { Copy, Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField"; -import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types"; +import { BoolCast, Cast, NumCast, StrCast, DateCast, PromiseValue } from "../../../new_fields/Types"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { Utils, numberRange, timenow } from '../../../Utils'; import { DocServer } from "../../DocServer"; @@ -39,6 +39,7 @@ import { ReplaceStep } from 'prosemirror-transform'; import { DocumentType } from '../../documents/DocumentTypes'; import { formattedTextBoxCommentPlugin, FormattedTextBoxComment } from './FormattedTextBoxComment'; import { inputRules } from 'prosemirror-inputrules'; +import { select } from 'async'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -203,8 +204,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe FormattedTextBox._toolTipTextMenu.mark_key_pressed(tx.storedMarks); } - this._keymap["ACTIVE"] = true; // hack to ignore an initial carriage return when creating a textbox from the action menu - this._applyingChange = true; this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n")); this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now()))); @@ -353,7 +352,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe _keymap: any = undefined; @computed get config() { this._keymap = buildKeymap(schema); - this._keymap["ACTIVE"] = this.extensionDoc.text; // hack to ignore an initial carriage return only when creating a textbox from the action menu return { schema, plugins: this.props.isOverlay ? [ @@ -659,7 +657,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - if (this.props.Document[Id] === FormattedTextBox.SelectOnLoad) { + let selectOnLoad = this.props.Document[Id] === FormattedTextBox.SelectOnLoad; + if (selectOnLoad) { FormattedTextBox.SelectOnLoad = ""; this.props.select(false); } @@ -667,15 +666,38 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet. this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: timenow() })]; let heading = this.props.Document.heading; - if (heading) { - let ruleProvider = Cast(this.props.Document.ruleProvider, Doc); - if (ruleProvider instanceof Doc) { - let font = StrCast(ruleProvider["ruleFont_" + heading]); - let size = NumCast(ruleProvider["ruleSize_" + heading]); - size && (this._editorView!.state.storedMarks = [...this._editorView!.state.storedMarks, schema.marks.pFontSize.create({ fontSize: size })]); - font && (this._editorView!.state.storedMarks = [...this._editorView!.state.storedMarks, font === "Arial" ? schema.marks.arial.create() : schema.marks.comicSans.create()]); - } + if (heading && selectOnLoad) { + PromiseValue(Cast(this.props.Document.ruleProvider, Doc)).then(ruleProvider => { + if (ruleProvider) { + let align = StrCast(ruleProvider["ruleAlign_" + heading]); + let font = StrCast(ruleProvider["ruleFont_" + heading]); + let size = NumCast(ruleProvider["ruleSize_" + heading]); + if (align) { + let tr = this._editorView!.state.tr; + tr = tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(2))). + replaceSelectionWith(this._editorView!.state.schema.nodes.paragraph.create({ align: align }), true). + setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(0))); + this._editorView!.dispatch(tr); + } + let sm = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: timenow() })]; + size && (sm = [...sm, schema.marks.pFontSize.create({ fontSize: size })]); + font && (sm = [...sm, this.getFont(font)]); + this._editorView!.dispatch(this._editorView!.state.tr.setStoredMarks(sm)); + } + }); + } + } + getFont(font: string) { + switch (font) { + case "Arial": return schema.marks.arial.create(); + case "Times New Roman": return schema.marks.timesNewRoman.create(); + case "Georgia": return schema.marks.georgia.create(); + case "Comic Sans MS": return schema.marks.comicSans.create(); + case "Tahoma": return schema.marks.tahoma.create(); + case "Impact": return schema.marks.impact.create(); + case "ACrimson Textrial": return schema.marks.crimson.create(); } + return schema.marks.arial.create(); } componentWillUnmount() { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 9866e22eb..9d35d36d3 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -115,17 +115,17 @@ export class CurrentUserUtils { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); - try { - const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" }); - NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json()); - await Gateway.Instance.ClearCatalog(); - const extraSchemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []); - let extras = await Promise.all(extraSchemas.map(sc => Gateway.Instance.GetSchema("", sc))); - let catprom = CurrentUserUtils.SetNorthstarCatalog(await Gateway.Instance.GetCatalog(), extras); - // if (catprom) await Promise.all(catprom); - } catch (e) { + // try { + // const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" }); + // NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json()); + // await Gateway.Instance.ClearCatalog(); + // const extraSchemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []); + // let extras = await Promise.all(extraSchemas.map(sc => Gateway.Instance.GetSchema("", sc))); + // let catprom = CurrentUserUtils.SetNorthstarCatalog(await Gateway.Instance.GetCatalog(), extras); + // // if (catprom) await Promise.all(catprom); + // } catch (e) { - } + // } } /* Northstar catalog ... really just for testing so this should eventually go away */ -- cgit v1.2.3-70-g09d2 From a709e21384cef80a85eac9220739c854a96d5313 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 10 Sep 2019 20:15:40 -0400 Subject: fixed several search issues with text boxes and highlighting. --- .../collections/collectionFreeForm/MarqueeView.tsx | 5 +- src/client/views/nodes/DocumentView.tsx | 16 ++++--- src/client/views/search/SearchBox.tsx | 6 +-- src/client/views/search/SearchItem.tsx | 56 ++-------------------- src/server/Search.ts | 3 ++ src/server/index.ts | 3 ++ 6 files changed, 27 insertions(+), 62 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 56d8127e2..0c4860be1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -288,8 +288,11 @@ export class MarqueeView extends React.Component else usedPaletted.set(bg, 1); } }); + usedPaletted.delete("#f1efeb"); + usedPaletted.delete("white"); + usedPaletted.delete("rgba(255,255,255,1)"); let usedSequnce = Array.from(usedPaletted.keys()).sort((a, b) => usedPaletted.get(a)! < usedPaletted.get(b)! ? -1 : usedPaletted.get(a)! > usedPaletted.get(b)! ? 1 : 0); - let chosenColor = usedPaletted.get("white") || usedPaletted.get("rgb(255,255,255)") && usedPaletted.size === 1 ? "white" : palette.length ? palette[0] : usedSequnce[0]; + let chosenColor = (usedPaletted.size === 0) ? "white" : palette.length ? palette[0] : usedSequnce[0]; let inkData = this.ink ? this.ink.inkData : undefined; let newCollection = Docs.Create.FreeformDocument(selected, { x: bounds.left, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 633455f63..1e755f121 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -644,12 +644,16 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); cm.addItem({ description: "Move To Overlay", icon: "laptop-code", event: () => ((o: Doc) => o && Doc.AddDocToList(o, "data", this.props.Document))(Cast(CurrentUserUtils.UserDocument.overlays, Doc) as Doc) }); cm.addItem({ - description: "Download document", icon: "download", event: () => { - const a = document.createElement("a"); - const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); - a.href = url; - a.download = `DocExport-${this.props.Document[Id]}.zip`; - a.click(); + description: "Download document", icon: "download", event: async () => { + let y = JSON.parse(await rp.get(Utils.CorsProxy("http://localhost:8983/solr/dash/select"), { + qs: { q: 'world', fq: 'NOT baseProto_b:true AND NOT deleted:true', start: '0', rows: '100', hl: true, 'hl.fl': '*' } + })); + console.log(y); + // const a = document.createElement("a"); + // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); + // a.href = url; + // a.download = `DocExport-${this.props.Document[Id]}.zip`; + // a.click(); } }); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 2ad69daca..2e29838e6 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -141,7 +141,7 @@ export class SearchBox extends React.Component { private get filterQuery() { const types = FilterBox.Instance.filterTypes; const includeDeleted = FilterBox.Instance.getDataStatus(); - return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); + return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted_b:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); } @@ -304,14 +304,14 @@ export class SearchBox extends React.Component { this.getResults(this._searchString); if (i < this._results.length) result = this._results[i]; if (result) { - this._visibleElements[i] = ; + this._visibleElements[i] = ; this._isSearch[i] = "search"; } } else { result = this._results[i]; if (result) { - this._visibleElements[i] = ; + this._visibleElements[i] = ; this._isSearch[i] = "search"; } } diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 386b5fe74..0b722c086 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -28,7 +28,7 @@ import "./SelectorContextMenu.scss"; export interface SearchItemProps { doc: Doc; - query?: string; + query: string; highlighting: string[]; } @@ -128,68 +128,26 @@ export class LinkContextMenu extends React.Component { export class SearchItem extends React.Component { @observable _selected: boolean = false; - private _previewDoc?: Doc; onClick = () => { // I dont think this is the best functionality because clicking the name of the collection does that. Change it back if you'd like DocumentManager.Instance.jumpToDocument(this.props.doc, false); - if (this.props.doc.data instanceof RichTextField) { - this.highlightTextBox(this.props.doc); - } - // CollectionDockingView.Instance.AddRightSplit(this.props.doc, undefined); } @observable _useIcons = true; @observable _displayDim = 50; - highlightTextBox = (doc: Doc) => { - if (this.props.query) { - const fieldkey = 'search_string'; - if (Object.keys(doc).indexOf(fieldkey) === -1) { - doc.search_string = this.props.query; - } - else { - doc.search_string = undefined; - } - - } - } - - fitToBox = () => { - let bounds = Doc.ComputeContentBounds([this.props.doc]); - return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / Math.max((bounds.b - bounds.y), (bounds.r - bounds.x)), this._displayDim]; - } - componentWillUnmount() { - if (this._previewDoc) { - DocServer.DeleteDocument(this._previewDoc[Id]); - } + this.props.doc.search_string = undefined; } - //@computed @action public DocumentIcon() { let layoutresult = StrCast(this.props.doc.type); if (!this._useIcons) { - let renderDoc = this.props.doc; - //let box: number[] = []; - if (layoutresult.indexOf(DocumentType.COL) !== -1) { - renderDoc = Doc.MakeDelegate(renderDoc); - let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => { - var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]; - let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()]; - return { - x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), - r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) - }; - }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); - let box = () => [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / (bounds.r - bounds.x), this._displayDim]; - } let returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); let returnYDimension = () => this._displayDim; - let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension()); - let newRenderDoc = Doc.MakeDelegate(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt - this._previewDoc = newRenderDoc; + let scale = () => returnXDimension() / NumCast(this.props.doc.nativeWidth, returnXDimension()); const docview =
{ this._useIcons = !this._useIcons; @@ -219,15 +177,9 @@ export class SearchItem extends React.Component { ContentScaling={scale} />
; - const data = renderDoc.data; - if (data instanceof ObjectField) newRenderDoc.data = ObjectField.MakeCopy(data); - newRenderDoc.preview = true; - newRenderDoc.search_string = this.props.query; + this.props.doc.search_string = this.props.query; return docview; } - if (this._previewDoc) { - DocServer.DeleteDocument(this._previewDoc[Id]); - } let button = layoutresult.indexOf(DocumentType.PDF) !== -1 ? faFilePdf : layoutresult.indexOf(DocumentType.IMG) !== -1 ? faImage : layoutresult.indexOf(DocumentType.TEXT) !== -1 ? faStickyNote : diff --git a/src/server/Search.ts b/src/server/Search.ts index 723dc101b..4a408405a 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -32,10 +32,13 @@ export class Search { public async search(query: any) { try { + console.log("SEARCH " + query + " " + (this.url + "dash/select") + " " + query.q); + console.log(query); const searchResults = JSON.parse(await rp.get(this.url + "dash/select", { qs: query })); const { docs, numFound } = searchResults.response; + console.log("RESULTS " + numFound); const ids = docs.map((field: any) => field.id); return { ids, numFound, highlighting: searchResults.highlighting }; } catch { diff --git a/src/server/index.ts b/src/server/index.ts index 50ce2b14e..149bacf0f 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -198,12 +198,15 @@ const solrURL = "http://localhost:8983/solr/#/dash"; app.get("/search", async (req, res) => { const solrQuery: any = {}; + console.log("GOT SEARCH"); ["q", "fq", "start", "rows", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]); if (solrQuery.q === undefined) { res.send([]); return; } + console.log("CALLING SEARCH") let results = await Search.Instance.search(solrQuery); + console.log("RETURNING SEARCH") res.send(results); }); -- cgit v1.2.3-70-g09d2 From 68e554cafb6107bfde9526773b3e0e667d582c88 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 11 Sep 2019 17:24:48 -0400 Subject: added default note type collection --- src/client/documents/Documents.ts | 1 + src/client/views/Main.tsx | 1 - src/client/views/PreviewCursor.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 +++++++++------- .../views/collections/collectionFreeForm/MarqueeView.tsx | 6 ++++++ src/client/views/nodes/FormattedTextBox.tsx | 3 ++- src/server/authentication/models/current_user_utils.ts | 12 +++++++++++- 7 files changed, 30 insertions(+), 11 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ae65fde1e..602a7f9ad 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -66,6 +66,7 @@ export interface DocumentOptions { page?: number; scale?: number; layout?: string; + isTemplate?: boolean; templates?: List; viewType?: number; backgroundColor?: string; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 0e687737d..11ec6f0c9 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -37,7 +37,6 @@ let swapDocs = async () => { (await Cast(CurrentUserUtils.UserDocument.workspaces, Doc))!.chromeStatus = "disabled"; (await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc))!.chromeStatus = "disabled"; (await Cast(CurrentUserUtils.UserDocument.sidebar, Doc))!.chromeStatus = "disabled"; - CurrentUserUtils.UserDocument.chromeStatus = "disabled"; await swapDocs(); document.getElementById('root')!.addEventListener('wheel', event => { if (event.ctrlKey) { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 45a8556bf..1aed51e64 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -102,7 +102,7 @@ export class PreviewCursor extends React.Component<{}> { (e.keyCode < 112 || e.keyCode > 123) && // F1 thru F12 keys !e.key.startsWith("Arrow") && !e.defaultPrevented) { - if (!e.ctrlKey && !e.metaKey) {// /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) { + if ((!e.ctrlKey || (e.keyCode >= 48 && e.keyCode <= 57)) && !e.metaKey) {// /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) { PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e); PreviewCursor.Visible = false; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 21f119d57..2591bdd8d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -39,6 +39,7 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { DocServer } from "../../../DocServer"; import { FormattedTextBox } from "../../nodes/FormattedTextBox"; +import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard); @@ -272,7 +273,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // col && (Doc.GetProto(newBox).backgroundColor = Utils.toRGBAstr(Utils.HSLtoRGB(newcol.h, newcol.s, newcol.l))); // OR transparency set let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); - col && (Doc.GetProto(newBox).backgroundColor = col); + (newBox.backgroundColor === newBox.defaultBackgroundColor) && col && (Doc.GetProto(newBox).backgroundColor = col); let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]); round && (Doc.GetProto(newBox).borderRounding = round); @@ -945,17 +946,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); let noteItems: ContextMenuProps[] = []; - noteItems.push({ description: "1: Note", event: () => this.createText("Note", "yellow"), icon: "eye" }); - noteItems.push({ description: "2: Idea", event: () => this.createText("Idea", "pink"), icon: "eye" }); - noteItems.push({ description: "3: Topic", event: () => this.createText("Topic", "lightBlue"), icon: "eye" }); - noteItems.push({ description: "4: Person", event: () => this.createText("Person", "lightGreen"), icon: "eye" }); + let notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data); + notes.map((node, i) => noteItems.push({ description: (i + 1) + ": " + StrCast(node.title), event: () => this.createText(i), icon: "eye" })); layoutItems.push({ description: "Add Note ...", subitems: noteItems, icon: "eye" }) ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" }); } - createText = (noteStyle: string, color: string) => { + createText = (noteStyle: number) => { let pt = this.getTransform().transformPoint(ContextMenu.Instance.pageX, ContextMenu.Instance.pageY); - this.addLiveTextBox(Docs.Create.TextDocument({ title: noteStyle, x: pt[0], y: pt[1], autoHeight: true, backgroundColor: color })) + let notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data); + let text = Docs.Create.TextDocument({ width: 200, height: 100, x: pt[0], y: pt[1], autoHeight: true, title: StrCast(notes[noteStyle % notes.length].title) }); + text.layout = notes[noteStyle % notes.length]; + this.addLiveTextBox(text); } private childViews = () => [ diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0c4860be1..fe48a3485 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -22,6 +22,7 @@ import React = require("react"); import { SchemaHeaderField, RandomPastel } from "../../../../new_fields/SchemaHeaderField"; import { string } from "prop-types"; import { listSpec } from "../../../../new_fields/Schema"; +import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -97,6 +98,11 @@ export class MarqueeView extends React.Component } else if (!e.ctrlKey) { this.props.addLiveTextDocument( Docs.Create.TextDocument({ width: 200, height: 100, x: x, y: y, autoHeight: true, title: "-typed text-" })); + } else if (e.keyCode > 48 && e.keyCode <= 57) { + let notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data); + let text = Docs.Create.TextDocument({ width: 200, height: 100, x: x, y: y, autoHeight: true, title: "-typed text-" }); + text.layout = notes[(e.keyCode - 49) % notes.length]; + this.props.addLiveTextDocument(text); } e.stopPropagation(); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0ea36cdc2..194026a08 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -289,7 +289,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } else if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) !== "") { - this.props.Document.layout = draggedDoc; + if (this.props.DataDoc) this.props.DataDoc.layout = draggedDoc; + else this.props.Document.layout = draggedDoc; draggedDoc.isTemplate = true; e.stopPropagation(); } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 9d35d36d3..af5774ebe 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -7,7 +7,7 @@ import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/nort import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; import { CollectionViewType } from "../../../client/views/collections/CollectionBaseView"; import { CollectionView } from "../../../client/views/collections/CollectionView"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, StrCast, PromiseValue } from "../../../new_fields/Types"; @@ -50,6 +50,16 @@ export class CurrentUserUtils { doc.workspaces = workspaces; } PromiseValue(Cast(doc.workspaces, Doc)).then(workspaces => workspaces && (workspaces.preventTreeViewOpen = true)); + if (doc.noteTypes === undefined) { + let notes = [Docs.Create.TextDocument({ title: "Note", backgroundColor: "yellow", isTemplate: true }), + Docs.Create.TextDocument({ title: "Idea", backgroundColor: "pink", isTemplate: true }), + Docs.Create.TextDocument({ title: "Topic", backgroundColor: "lightBlue", isTemplate: true }), + Docs.Create.TextDocument({ title: "Person", backgroundColor: "lightGreen", isTemplate: true })]; + const noteTypes = Docs.Create.TreeDocument(notes, { title: "Note Types", height: 75 }); + noteTypes.excludeFromLibrary = true; + doc.noteTypes = noteTypes; + } + PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(vals => DocListCast(vals))); if (doc.recentlyClosed === undefined) { const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 }); recentlyClosed.excludeFromLibrary = true; -- cgit v1.2.3-70-g09d2 From 47ca25c49d7d9f1fee22b256f86e296dac42b47b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 12 Sep 2019 21:42:07 -0400 Subject: cleaned up rulerProvider a bit and added menu item to turn it on. --- src/client/views/DocumentDecorations.tsx | 13 +++++---- src/client/views/InkingControl.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 +++++++--------------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +++ src/client/views/nodes/DocumentView.tsx | 12 ++++++--- src/client/views/nodes/FormattedTextBox.tsx | 4 +-- 7 files changed, 31 insertions(+), 36 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6451fdf5e..4ab2ade8e 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -424,23 +424,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointermove", this.onRadiusMove); document.addEventListener("pointerup", this.onRadiusUp); } - if (!this._isMoving) { - SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). - map(d => d.borderRounding = "0%"); - } } onRadiusMove = (e: PointerEvent): void => { this._isMoving = true; let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1])); - SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). - map(d => d.borderRounding = `${Math.min(100, dist)}%`); + dist = dist < 3 ? 0 : dist; + let usingRule = false; SelectionManager.SelectedDocuments().map(dv => { let cv = dv.props.ContainingCollectionView; let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); let heading = NumCast(dv.props.Document.heading); - cv && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleRounding_" + heading] = StrCast(dv.props.Document.borderRounding)); + ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`); + usingRule = usingRule || (ruleProvider && heading ? true : false); }) + !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). + map(d => d.borderRounding = `${Math.min(100, dist)}%`); e.stopPropagation(); e.preventDefault(); } diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index aa573f16b..867735c0b 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -73,7 +73,7 @@ export class InkingControl extends React.Component { let cv = view.props.ContainingCollectionView; let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); let parback = cv && StrCast(cv.props.Document.backgroundColor); - cv && parback && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); + cv && parback && (Doc.GetProto(ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); // if (parback && cv && parback.indexOf("rgb") !== -1) { // let parcol = Utils.fromRGBAstr(parback); // let hsl = Utils.RGBToHSL(parcol.r, parcol.g, parcol.b); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 24f2a60a9..9a8ae3535 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -262,27 +262,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (heading === 0) { let sorted = this.childDocs.filter(d => d.type === DocumentType.TEXT && d.data_ext instanceof Doc && d.data_ext.lastModified).sort((a, b) => DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date > DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? 1 : DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date < DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? -1 : 0); - heading = NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); + heading = !sorted.length ? 1 : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); } newBox.heading = heading; - PromiseValue(Cast(this.props.Document.ruleProvider, Doc)).then(ruleProvider => { - if (!ruleProvider) ruleProvider = this.props.Document; - // saturation shift - // let col = NumCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); - // let back = Utils.fromRGBAstr(StrCast(this.props.Document.backgroundColor)); - // let hsl = Utils.RGBToHSL(back.r, back.g, back.b); - // let newcol = { h: hsl.h, s: hsl.s + col, l: hsl.l }; - // col && (Doc.GetProto(newBox).backgroundColor = Utils.toRGBAstr(Utils.HSLtoRGB(newcol.h, newcol.s, newcol.l))); - // OR transparency set - let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); - (newBox.backgroundColor === newBox.defaultBackgroundColor) && col && (Doc.GetProto(newBox).backgroundColor = col); - - let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]); - round && (Doc.GetProto(newBox).borderRounding = round); - newBox.ruleProvider = ruleProvider; - this.addDocument(newBox, false); - }); + if (Cast(this.props.Document.ruleProvider, Doc) as Doc) { + newBox.ruleProvider = Doc.GetProto(Cast(this.props.Document.ruleProvider, Doc) as Doc); + } + this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { this.props.addDocument(newBox, false); @@ -898,7 +885,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onContextMenu = (e: React.MouseEvent) => { let layoutItems: ContextMenuProps[] = []; - if (this.childDocs.some(d => d.isTemplate)) { + if (this.childDocs.some(d => BoolCast(d.isTemplate))) { layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" }); } layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); @@ -913,9 +900,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, icon: !this.props.Document.useClusters ? "braille" : "braille" }); - this.props.Document.useClusters && layoutItems.push({ - description: `${this.props.Document.clusterOverridesDefaultBackground ? "Use Default Backgrounds" : "Clusters Override Defaults"}`, - event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground, + layoutItems.push({ + description: `${this.props.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, + event: () => this.props.Document.isRuleProvider = !this.props.Document.isRuleProvider, icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard" }); layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index fe48a3485..4308497a1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -356,7 +356,7 @@ export class MarqueeView extends React.Component this.props.addLiveTextDocument(summary); } else { - newCollection.ruleProvider = this.props.container.props.Document; + newCollection.ruleProvider = this.props.container.props.Document.isRuleProvider ? this.props.container.props.Document : this.props.container.props.Document.ruleProvider; this.props.addDocument(newCollection, false); this.props.selectDocuments([newCollection]); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 07dd1cae7..082e5c5e3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -74,7 +74,10 @@ export class CollectionFreeFormDocumentView extends DocComponent { + let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; let br = StrCast(this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout.borderRounding : this.props.Document.borderRounding); + br = !br && ruleRounding ? ruleRounding : br; if (br.endsWith("%")) { let percent = Number(br.substr(0, br.length - 1)) / 100; let nativeDim = Math.min(NumCast(this.layoutDoc.nativeWidth), NumCast(this.layoutDoc.nativeHeight)); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3f0b62511..7b9ed12a7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -793,9 +793,15 @@ export class DocumentView extends DocComponent(Docu render() { - let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ? + let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleColor = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(this.props.Document.heading)]) : undefined; + let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; + let colorSet = this.layoutDoc.backgroundColor !== this.layoutDoc.defaultBackgroundColor; + let clusterCol = this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground; + + let backgroundColor = this.layoutDoc.isBackground || (clusterCol && !colorSet) ? this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : - StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); + ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; @@ -811,7 +817,7 @@ export class DocumentView extends DocComponent(Docu } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith(" diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 444b91b28..658e2a04d 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -284,8 +284,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe e.stopPropagation(); } else if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; - if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) !== "") { - this.props.Document.layout = draggedDoc; + if (draggedDoc && draggedDoc.type === DocumentType.TEXT) { + this.props.Document.layout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc; draggedDoc.isTemplate = true; e.stopPropagation(); } -- cgit v1.2.3-70-g09d2 From 233893698083cbcfcf39ddad8b57049aeb1ba842 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 13 Sep 2019 14:18:55 -0400 Subject: refactored how ruleProvider's work. overloaded custom template for creating metadata fields --- src/client/util/RichTextRules.ts | 8 +++---- src/client/util/TooltipTextMenu.tsx | 4 ++-- src/client/views/DocumentDecorations.tsx | 11 ++------- src/client/views/InkingControl.tsx | 5 ++-- src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/MainView.tsx | 2 ++ src/client/views/TemplateMenu.tsx | 16 ++++++------- .../views/collections/CollectionDockingView.tsx | 1 + .../views/collections/CollectionSchemaView.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 27 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 -- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 13 +++++++---- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/FormattedTextBox.tsx | 2 +- .../views/presentationview/PresentationElement.tsx | 1 + src/client/views/search/SearchItem.tsx | 1 + src/new_fields/Doc.ts | 2 +- 19 files changed, 51 insertions(+), 51 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index c0c62463a..c727eec73 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -61,7 +61,7 @@ export const inpRules = { new RegExp(/^#([0-9]+)\s$/), (state, match, start, end) => { let size = Number(match[1]); - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { (Cast(FormattedTextBox.InputBoxOverlay!.props.Document, Doc) as Doc).heading = Number(match[1]); @@ -74,7 +74,7 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleAlign_" + heading] = "center"; @@ -88,7 +88,7 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleAlign_" + heading] = "left"; @@ -100,7 +100,7 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleAlign_" + heading] = "right"; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index c376b6f86..84d045e6f 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -496,7 +496,7 @@ export class TooltipTextMenu { if (markType.name[0] === 'p') { let size = this.fontSizeToNum.get(markType); if (size) { this.updateFontSizeDropdown(String(size) + " pt"); } - let ruleProvider = Cast(this.editorProps.Document.ruleProvider, Doc) as Doc; + let ruleProvider = this.editorProps.ruleProvider; let heading = NumCast(this.editorProps.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleSize_" + heading] = size; @@ -505,7 +505,7 @@ export class TooltipTextMenu { else { let fontName = this.fontStylesToName.get(markType); if (fontName) { this.updateFontStyleDropdown(fontName); } - let ruleProvider = Cast(this.editorProps.Document.ruleProvider, Doc) as Doc; + let ruleProvider = this.editorProps.ruleProvider; let heading = NumCast(this.editorProps.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleFont_" + heading] = fontName; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6d63e8f73..ebdf2a749 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -365,14 +365,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { let docViews = SelectionManager.ViewsSortedVertically(); let topDocView = docViews[0]; - let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); - if (ind !== -1) { - topDocView.templates.splice(ind, 1); - topDocView.props.Document.subBulletDocs = undefined; - } else { - topDocView.addTemplate(Templates.Bullet); - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); - } + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } } this._removeIcon = false; @@ -439,7 +432,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let usingRule = false; SelectionManager.SelectedDocuments().map(dv => { let cv = dv.props.ContainingCollectionView; - let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); + let ruleProvider = cv && cv.props.ruleProvider; let heading = NumCast(dv.props.Document.heading); ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`); usingRule = usingRule || (ruleProvider && heading ? true : false); diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 867735c0b..86d0fc0be 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -71,9 +71,8 @@ export class InkingControl extends React.Component { targetDoc.backgroundColor = this._selectedColor; if (view.props.Document.heading) { let cv = view.props.ContainingCollectionView; - let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); - let parback = cv && StrCast(cv.props.Document.backgroundColor); - cv && parback && (Doc.GetProto(ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); + let ruleProvider = cv && (Cast(cv.props.ruleProvider, Doc) as Doc); + cv && (Doc.GetProto(ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); // if (parback && cv && parback.indexOf("rgb") !== -1) { // let parcol = Utils.fromRGBAstr(parback); // let hsl = Utils.RGBToHSL(parcol.r, parcol.g, parcol.b); diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index c3a2cb214..71fb2707d 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -72,7 +72,6 @@ export class MainOverlayTextBox extends React.Component if (this._textTargetDiv) { this._textTargetDiv.style.color = this._textColor; } - this._textAutoHeight = autoHeight; this.TextFieldKey = textFieldKey!; let txf = tx ? tx : () => Transform.Identity(); this._textXf = txf; @@ -143,6 +142,7 @@ export class MainOverlayTextBox extends React.Component Document={FormattedTextBox.InputBoxOverlay.props.Document} DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc} onClick={undefined} + ruleProvider={this._textBox ? this._textBox.props.ruleProvider : undefined} ChromeHeight={this.ChromeHeight} isSelected={returnTrue} select={emptyFunction} renderDepth={0} ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b64986084..2cec1c052 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -322,6 +322,7 @@ export class MainView extends React.Component { addDocTab={emptyFunction} pinToPres={emptyFunction} onClick={undefined} + ruleProvider={undefined} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} @@ -385,6 +386,7 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} removeDocument={undefined} + ruleProvider={undefined} onClick={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 0ef1a137d..060191e29 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -51,16 +51,16 @@ export class TemplateMenu extends React.Component { @observable private _hidden: boolean = true; dragRef = React.createRef(); - constructor(props: TemplateMenuProps) { - super(props); - } - toggleCustom = (e: React.MouseEvent): void => { this.props.docs.map(dv => { - if (dv.Document.type !== DocumentType.COL && dv.Document.type !== DocumentType.TEMPLATE) { - dv.makeCustomViewClicked(); - } else if (dv.Document.nativeLayout) { - dv.makeNativeViewClicked(); + if (dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.DataDoc) { + Doc.MakeMetadataFieldTemplate(dv.props.Document, dv.props.ContainingCollectionView.props.DataDoc) + } else { + if (dv.Document.type !== DocumentType.COL && dv.Document.type !== DocumentType.TEMPLATE) { + dv.makeCustomViewClicked(); + } else if (dv.Document.nativeLayout) { + dv.makeNativeViewClicked(); + } } }); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index fb8b0c41b..166fa0811 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -631,6 +631,7 @@ export class DockedFrameRenderer extends React.Component { bringToFront={emptyFunction} addDocument={undefined} removeDocument={undefined} + ruleProvider={undefined} ContentScaling={this.contentScaling} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9d83aa6c1..dca1d7c1d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -995,6 +995,7 @@ export class CollectionSchemaPreview extends React.Component(schemaCtor: (doc: Doc) => T) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9a8ae3535..4a3e5039a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -257,18 +257,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); private addLiveTextBox = (newBox: Doc) => { FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed - let heading = this.childDocs.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); - heading = heading === 0 || this.childDocs.length === 0 ? 1 : heading === 1 ? 2 : 0; + let maxHeading = this.childDocs.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); + let heading = maxHeading === 0 || this.childDocs.length === 0 ? 1 : maxHeading === 1 ? 2 : 0; if (heading === 0) { let sorted = this.childDocs.filter(d => d.type === DocumentType.TEXT && d.data_ext instanceof Doc && d.data_ext.lastModified).sort((a, b) => DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date > DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? 1 : DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date < DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? -1 : 0); - heading = !sorted.length ? 1 : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); - } - newBox.heading = heading; - - if (Cast(this.props.Document.ruleProvider, Doc) as Doc) { - newBox.ruleProvider = Doc.GetProto(Cast(this.props.Document.ruleProvider, Doc) as Doc); + heading = !sorted.length ? Math.max(1, maxHeading) : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); } + !this.props.Document.isRuleProvider && (newBox.heading = heading); this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { @@ -698,6 +694,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, + ruleProvider: this.props.Document.isRuleProvider && childLayout.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider, onClick: this.props.onClick, ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform, renderDepth: this.props.renderDepth + 1, @@ -723,6 +720,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, + ruleProvider: this.props.ruleProvider, onClick: this.props.onClick, ScreenToLocalTransform: this.getTransform, renderDepth: this.props.renderDepth, @@ -817,6 +815,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (pair.layout && !(pair.data instanceof Promise)) { prev.push({ ele: , @@ -873,6 +872,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, "arrange contents"); } + autoFormat = () => { + this.props.Document.isRuleProvider = !this.props.Document.isRuleProvider; + this.childDocs.map(child => child.heading = undefined); + } + analyzeStrokes = async () => { let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); if (!data) { @@ -900,11 +904,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, icon: !this.props.Document.useClusters ? "braille" : "braille" }); - layoutItems.push({ - description: `${this.props.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, - event: () => this.props.Document.isRuleProvider = !this.props.Document.isRuleProvider, - icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard" - }); + layoutItems.push({ description: `${this.props.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, event: this.autoFormat, icon: !this.props.Document.isRuleProvider ? "chalkboard" : "chalkboard" }); layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" }); layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); @@ -1034,7 +1034,6 @@ class CollectionFreeFormOverlayView extends React.Component boolean }> { @computed get backgroundView() { - let props = this.props; return (); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 4308497a1..e46e8cb88 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -329,7 +329,6 @@ export class MarqueeView extends React.Component selected = [newCollection]; newCollection.x = bounds.left + bounds.width; summary.proto!.subBulletDocs = new List(selected); - summary.templates = new List([Templates.Bullet.Layout]); let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); container.viewType = CollectionViewType.Stacking; container.autoHeight = true; @@ -356,7 +355,6 @@ export class MarqueeView extends React.Component this.props.addLiveTextDocument(summary); } else { - newCollection.ruleProvider = this.props.container.props.Document.isRuleProvider ? this.props.container.props.Document : this.props.container.props.Document.ruleProvider; this.props.addDocument(newCollection, false); this.props.selectDocuments([newCollection]); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 082e5c5e3..4872a7aa1 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -74,7 +74,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { - let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleProvider = this.props.ruleProvider; let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; let br = StrCast(this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout.borderRounding : this.props.Document.borderRounding); br = !br && ruleRounding ? ruleRounding : br; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0816cb813..cc04c5a9f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import * as fa from '@fortawesome/free-solid-svg-icons'; -import { action, computed, IReactionDisposer, reaction, runInAction, trace, observable } from "mobx"; +import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; import { Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; @@ -9,12 +9,13 @@ import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema"; import { ScriptField } from '../../../new_fields/ScriptField'; -import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../new_fields/Types"; +import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { RouteStore } from '../../../server/RouteStore'; import { emptyFunction, returnTrue, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from "../../documents/Documents"; +import { DocumentType } from '../../documents/DocumentTypes'; import { ClientUtils } from '../../util/ClientUtils'; import { DictationManager } from '../../util/DictationManager'; import { DocumentManager } from "../../util/DocumentManager"; @@ -35,12 +36,10 @@ import { MainView } from '../MainView'; import { OverlayView } from '../OverlayView'; import { ScriptBox } from '../ScriptBox'; import { ScriptingRepl } from '../ScriptingRepl'; -import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import { FormattedTextBox } from './FormattedTextBox'; import React = require("react"); -import { DocumentType } from '../../documents/DocumentTypes'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -89,6 +88,7 @@ export interface DocumentViewProps { renderDepth: number; showOverlays?: (doc: Doc) => { title?: string, caption?: string }; ContentScaling: () => number; + ruleProvider: Doc | undefined; PanelWidth: () => number; PanelHeight: () => number; focus: (doc: Doc, willZoom: boolean, scale?: number) => void; @@ -470,6 +470,9 @@ export class DocumentView extends DocComponent(Docu this.props.Document.type === DocumentType.VID ? Docs.Create.VideoDocument("http://www.cs.brown.edu", options) : Docs.Create.ImageDocument("http://www.cs.brown.edu", options); + fieldTemplate.backgroundColor = StrCast(this.props.Document.backgroundColor); + fieldTemplate.heading = 1; + let docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: StrCast(this.Document.title) + "layout", width: NumCast(this.props.Document.width) + 20, height: Math.max(100, NumCast(this.props.Document.height) + 45) }); let proto = Doc.GetProto(docTemplate); Doc.MakeMetadataFieldTemplate(fieldTemplate, proto); @@ -800,7 +803,7 @@ export class DocumentView extends DocComponent(Docu render() { - let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleProvider = this.props.ruleProvider; let ruleColor = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(this.props.Document.heading)]) : undefined; let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; let colorSet = this.layoutDoc.backgroundColor !== this.layoutDoc.defaultBackgroundColor; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index d9774303b..943d181d6 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -30,6 +30,7 @@ export interface FieldViewProps { leaveNativeSize?: boolean; fitToBox?: boolean; ContainingCollectionView: Opt; + ruleProvider: Doc | undefined; Document: Doc; DataDoc?: Doc; onClick?: ScriptField; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d39291743..a0dc054cf 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -458,7 +458,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._rulesReactionDisposer = reaction(() => { - let ruleProvider = Cast(this.props.Document.ruleProvider, Doc); + let ruleProvider = this.props.ruleProvider; let heading = NumCast(this.props.Document.heading); if (ruleProvider instanceof Doc) { return { diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 80aa25f48..7be44faf6 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -351,6 +351,7 @@ export default class PresentationElement extends React.Component { Document={this.props.doc} addDocument={returnFalse} removeDocument={returnFalse} + ruleProvider={undefined} ScreenToLocalTransform={Transform.Identity} addDocTab={returnFalse} pinToPres={returnFalse} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 1a3d689bb..5b22a62a1 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -560,7 +560,7 @@ export namespace Doc { export function MakeMetadataFieldTemplate(fieldTemplate: Doc, templateDataDoc: Doc) { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) - let metadataFieldName = StrCast(fieldTemplate.title); + let metadataFieldName = StrCast(fieldTemplate.title).replace(/^-/, ""); let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); let fieldLayoutDoc = fieldTemplate; if (fieldTemplate.layout instanceof Doc) { -- cgit v1.2.3-70-g09d2 From dd7679295b84ceba49b8d581bb64f97cc1a86fbb Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 13 Sep 2019 17:30:02 -0400 Subject: more rule provider fixes --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/InkingControl.tsx | 8 +++++++- src/client/views/collections/CollectionSchemaCells.tsx | 1 + src/client/views/collections/CollectionSchemaView.tsx | 5 ++++- src/client/views/collections/CollectionStackingView.tsx | 1 + src/client/views/collections/CollectionTreeView.tsx | 3 +++ src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 ++ src/client/views/nodes/KeyValuePair.tsx | 1 + 10 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ebdf2a749..ac103b2ea 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -848,7 +848,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let templates: Map = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => { let checked = false; - SelectionManager.SelectedDocuments().map(doc => checked = checked || (doc.props.Document["show" + template.Name] !== undefined)); + SelectionManager.SelectedDocuments().map(doc => checked = checked || (doc.layoutDoc["show" + template.Name] !== undefined)); templates.set(template, checked); }); diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 86d0fc0be..94cc1f06c 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -51,7 +51,13 @@ export class InkingControl extends React.Component { let oldColors = selected.map(view => { let targetDoc = view.props.Document.layout instanceof Doc ? view.props.Document.layout : view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); let oldColor = StrCast(targetDoc.backgroundColor); - if (view.props.ContainingCollectionView && view.props.ContainingCollectionView.props.Document.colorPalette) { + if (view.props.ContainingCollectionView) { + if (!view.props.ContainingCollectionView.props.Document.colorPalette) { + let defaultPalette = ["rg14,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)",]; + let colorPalette = Cast(view.props.ContainingCollectionView.props.Document.colorPalette, listSpec("string")); + if (!colorPalette) view.props.ContainingCollectionView.props.Document.colorPalette = new List(defaultPalette); + } let cp = Cast(view.props.ContainingCollectionView.props.Document.colorPalette, listSpec("string")) as string[]; let closest = 0; let dist = 10000000; diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index c59107b53..17a3f4f7c 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -149,6 +149,7 @@ export class CollectionSchemaCell extends React.Component { DataDoc: this.props.rowProps.original, fieldKey: this.props.rowProps.column.id as string, fieldExt: "", + ruleProvider: undefined, ContainingCollectionView: this.props.CollectionView, isSelected: returnFalse, select: emptyFunction, diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index dca1d7c1d..1a84f94c8 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -32,6 +32,7 @@ import { CellProps, CollectionSchemaCell, CollectionSchemaNumberCell, Collection import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC"; import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { DocumentType } from "../../documents/DocumentTypes"; library.add(faCog, faPlus, faSortUp, faSortDown); @@ -161,6 +162,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined} childDocs={this.childDocs} renderDepth={this.props.renderDepth} + ruleProvider={this.props.Document.isRuleProvider && layoutDoc && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} width={this.previewWidth} height={this.previewHeight} getTransform={this.getPreviewTransform} @@ -901,6 +903,7 @@ interface CollectionSchemaPreviewProps { fitToBox?: boolean; width: () => number; height: () => number; + ruleProvider: Doc | undefined; showOverlays?: (doc: Doc) => { title?: string, caption?: string }; CollectionView?: CollectionView | CollectionPDFView | CollectionVideoView; onClick?: ScriptField; @@ -995,7 +998,7 @@ export class CollectionSchemaPreview extends React.Component doc) { DataDocument={dataDoc} showOverlays={this.overlays} renderDepth={this.props.renderDepth} + ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} fitToBox={this.props.fitToBox} onClick={layoutDoc.isTemplate ? this.onClickHandler : this.onChildClickHandler} width={width} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f5bb76966..b1e063997 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -37,6 +37,7 @@ export interface TreeViewProps { containingCollection: Doc; renderDepth: number; deleteDoc: (doc: Doc) => boolean; + ruleProvider: Doc | undefined; moveDocument: DragManager.MoveFunction; dropAction: "alias" | "copy" | undefined; addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => void; @@ -324,6 +325,7 @@ class TreeView extends React.Component { DataDocument={this.resolvedDataDoc} renderDepth={this.props.renderDepth} showOverlays={this.noOverlays} + ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider} fitToBox={this.boundsOfCollectionDocument !== undefined} width={this.docWidth} height={this.docHeight} @@ -491,6 +493,7 @@ class TreeView extends React.Component { dataDoc={pair.data} containingCollection={containingCollection} treeViewId={treeViewId} + ruleProvider={containingCollection.isRuleProvider && pair.layout.type !== DocumentType.TEXT ? containingCollection : containingCollection.ruleProvider as Doc} key={child[Id]} indentDocument={indent} renderDepth={renderDepth} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e46e8cb88..cc5e887b2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -287,7 +287,7 @@ export class MarqueeView extends React.Component let palette = Array.from(Cast(this.props.container.props.Document.colorPalette, listSpec("string")) as string[]); let usedPaletted = new Map(); [...this.props.activeDocuments(), this.props.container.props.Document].map(child => { - let bg = StrCast(child.backgroundColor); + let bg = StrCast(child.layout instanceof Doc ? child.layout.backgroundColor : child.backgroundColor); if (palette.indexOf(bg) !== -1) { palette.splice(palette.indexOf(bg), 1); if (usedPaletted.get(bg)) usedPaletted.set(bg, usedPaletted.get(bg)! + 1); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cc04c5a9f..591a507eb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -811,7 +811,7 @@ export class DocumentView extends DocComponent(Docu let backgroundColor = this.layoutDoc.isBackground || (clusterCol && !colorSet) ? this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : - ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); + ruleColor ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a0dc054cf..ffb829825 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -285,6 +285,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } else if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; if (draggedDoc && draggedDoc.type === DocumentType.TEXT) { + // let m = Doc.MakeDelegate(draggedDoc); // under construction + // m.layout = m.layout.replace(/fieldKey={}) this.props.Document.layout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc; draggedDoc.isTemplate = true; e.stopPropagation(); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index a27dbd83d..7e0f3735d 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -55,6 +55,7 @@ export class KeyValuePair extends React.Component { Document: this.props.doc, DataDoc: this.props.doc, ContainingCollectionView: undefined, + ruleProvider: undefined, fieldKey: this.props.keyName, fieldExt: "", isSelected: returnFalse, -- cgit v1.2.3-70-g09d2 From 827cee4d7ac4f1e761b141097d20671e7873bea8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 15 Sep 2019 01:14:21 -0400 Subject: changed moveDocument to move the draggedDoc -- its up to the caller to add the droppedDoc if it wants to. cleaned up some old code related to passing dataDoc along with doc's to drag and other functinos --- src/client/util/DragManager.ts | 16 ++++----- src/client/views/DocumentDecorations.tsx | 20 +++++------ src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionBaseView.tsx | 13 ++++--- .../views/collections/CollectionDockingView.tsx | 14 +++----- .../views/collections/CollectionSchemaCells.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../CollectionStackingViewFieldColumn.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 8 +++-- src/client/views/collections/CollectionView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 40 +++++++--------------- src/client/views/linking/LinkMenuGroup.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 35 ++++++------------- src/client/views/nodes/DragBox.tsx | 2 +- src/client/views/pdf/Page.tsx | 2 +- src/client/views/search/SearchItem.tsx | 2 +- 18 files changed, 67 insertions(+), 103 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4c9c9c17c..252accefa 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -32,7 +32,7 @@ export function SetupDrag( document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); let doc = await docFunc(); - var dragData = new DragManager.DocumentDragData([doc], [undefined]); + var dragData = new DragManager.DocumentDragData([doc]); dragData.dropAction = dropAction; dragData.moveDocument = moveFunc; dragData.options = options; @@ -76,7 +76,7 @@ export async function DragLinkAsDocument(dragEle: HTMLElement, x: number, y: num if (draggeddoc) { let moddrag = await Cast(draggeddoc.annotationOn, Doc); let dragdocs = moddrag ? [moddrag] : [draggeddoc]; - let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs); + let dragData = new DragManager.DocumentDragData(dragdocs); dragData.moveDocument = moveLinkedDocument; DragManager.StartLinkedDocumentDrag([dragEle], dragData, x, y, { handlers: { @@ -107,7 +107,7 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n if (doc) moddrag.push(doc); } let dragdocs = moddrag.length ? moddrag : draggedDocs; - let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs); + let dragData = new DragManager.DocumentDragData(dragdocs); dragData.moveDocument = moveLinkedDocument; DragManager.StartLinkedDocumentDrag([dragEle], dragData, x, y, { handlers: { @@ -201,15 +201,13 @@ export namespace DragManager { export type MoveFunction = (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; export class DocumentDragData { - constructor(dragDoc: Doc[], dragDataDocs: (Doc | undefined)[]) { + constructor(dragDoc: Doc[]) { this.draggedDocuments = dragDoc; - this.draggedDataDocs = dragDataDocs; this.droppedDocuments = dragDoc; this.xOffset = 0; this.yOffset = 0; } draggedDocuments: Doc[]; - draggedDataDocs: (Doc | undefined)[]; droppedDocuments: Doc[]; xOffset: number; yOffset: number; @@ -253,7 +251,7 @@ export namespace DragManager { } export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize?: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { - let dragData = new DragManager.DocumentDragData([], [undefined]); + let dragData = new DragManager.DocumentDragData([]); runInAction(() => StartDragFunctions.map(func => func())); StartDrag(eles, dragData, downX, downY, options, options && options.finishDrag ? options.finishDrag : (dropData: { [id: string]: any }) => { @@ -363,8 +361,6 @@ export namespace DragManager { const docs: Doc[] = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnnotationDragData ? [dragData.dragDocument] : []; - const datadocs: (Doc | undefined)[] = - dragData instanceof DocumentDragData ? dragData.draggedDataDocs : dragData instanceof AnnotationDragData ? [dragData.dragDocument] : []; let dragElements = eles.map(ele => { const w = ele.offsetWidth, h = ele.offsetHeight; @@ -449,7 +445,7 @@ export namespace DragManager { pageY: e.pageY, preventDefault: emptyFunction, button: 0 - }, docs, datadocs); + }, docs); } //TODO: Why can't we use e.movementX and e.movementY? let moveX = e.pageX - lastX; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ac103b2ea..ac1f51688 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -253,7 +253,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let dragDocView = SelectionManager.SelectedDocuments()[0]; const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0); const [xoff, yoff] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top); - let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document), SelectionManager.SelectedDocuments().map(dv => dv.props.DataDoc ? dv.props.DataDoc : dv.props.Document)); + let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); dragData.xOffset = xoff; dragData.yOffset = yoff; dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument; @@ -358,15 +358,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (this._iconDoc && selectedDocs.length === 1 && this._removeIcon) { selectedDocs[0].props.removeDocument && selectedDocs[0].props.removeDocument(this._iconDoc); } - if (!this._removeIcon) { - if (selectedDocs.length === 1) { - this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].toggleMinimized()); - } else if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && - Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { - let docViews = SelectionManager.ViewsSortedVertically(); - let topDocView = docViews[0]; - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); - } + if (!this._removeIcon && selectedDocs.length === 1) { // if you click on the top-left button when just 1 doc is selected, then collapse it. not sure why we don't do it for multiple selections + this.getIconDoc(selectedDocs[0]).then(async icon => { + let minimizedDoc = await Cast(selectedDocs[0].props.Document.minimizedDoc, Doc); + if (minimizedDoc) { + let scrpt = selectedDocs[0].props.ScreenToLocalTransform().scale(selectedDocs[0].props.ContentScaling()).inverse().transformPoint( + NumCast(minimizedDoc.x) - NumCast(selectedDocs[0].Document.x), NumCast(minimizedDoc.y) - NumCast(selectedDocs[0].Document.y)); + selectedDocs[0].collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); + } + }); } this._removeIcon = false; } diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 71fb2707d..cd8423a12 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -102,7 +102,7 @@ export class MainOverlayTextBox extends React.Component if ((e.movementX > 1 || e.movementY > 1) && FormattedTextBox.InputBoxOverlay) { document.removeEventListener("pointermove", this.textBoxMove); document.removeEventListener('pointerup', this.textBoxUp); - let dragData = new DragManager.DocumentDragData([FormattedTextBox.InputBoxOverlay.props.Document], [FormattedTextBox.InputBoxOverlay.props.DataDoc]); + let dragData = new DragManager.DocumentDragData([FormattedTextBox.InputBoxOverlay.props.Document]); const [left, top] = this._textXf().inverse().transformPoint(0, 0); dragData.xOffset = e.clientX - left; dragData.yOffset = e.clientY - top; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index af3fcaa24..d57a72dad 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -67,7 +67,7 @@ export class TemplateMenu extends React.Component { setTimeout(() => { let newDocView = DocumentManager.Instance.getDocumentView(topDoc); if (newDocView) { - let de = new DragManager.DocumentDragData([topDoc], [undefined]); + let de = new DragManager.DocumentDragData([topDoc]); de.moveDocument = topDocView.props.moveDocument; let xf = newDocView.ContentDiv!.getBoundingClientRect(); DragManager.StartDocumentDrag([newDocView.ContentDiv!], de, ex, ey, { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index b7036b3ff..a54718e9e 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -141,17 +141,16 @@ export class CollectionBaseView extends React.Component { return false; } + // this is called with the document that was dragged and the collection to move it into. + // if the target collection is the same as this collection, then the move will be allowed. + // otherwise, the document being moved must be able to be removed from its container before + // moving it into the target. @action.bound moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean { - let self = this; - let targetDataDoc = this.props.Document; - if (Doc.AreProtosEqual(targetDataDoc, targetCollection)) { + if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } - if (this.removeDocument(doc)) { - return addDocument(doc); - } - return false; + return this.removeDocument(doc) ? addDocument(doc) : false; } render() { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 166fa0811..bf55dba31 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -66,15 +66,15 @@ export class CollectionDockingView extends React.Component { - CollectionDockingView.makeDocumentConfig(doc, dragDataDocs[i]); + CollectionDockingView.makeDocumentConfig(doc, undefined); }) }; } @@ -84,12 +84,6 @@ export class CollectionDockingView extends React.Component - // this.AddRightSplit(dragDoc, dragDataDocs[i], true).contentItems[0].tab._dragListener. - // onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 })); } @action @@ -412,7 +406,7 @@ export class CollectionDockingView extends React.Component { e.preventDefault(); e.stopPropagation(); - DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc], [dataDoc]), e.clientX, e.clientY, { + DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY, { handlers: { dragComplete: emptyFunction }, hideSource: false }); diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 17a3f4f7c..3452e8702 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -172,7 +172,8 @@ export class CollectionSchemaCell extends React.Component { let onItemDown = (e: React.PointerEvent) => { if (fieldIsDoc) { SetupDrag(this._focusRef, () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document, - this._document[props.fieldKey] instanceof Doc ? (doc: Doc, target: Doc, addDoc: (newDoc: Doc) => any) => addDoc(doc) : this.props.moveDocument, this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e); + this._document[props.fieldKey] instanceof Doc ? (doc: Doc, target: Doc, addDoc: (newDoc: Doc) => any) => addDoc(doc) : this.props.moveDocument, + this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e); } }; let onPointerEnter = (e: React.PointerEvent): void => { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 1a84f94c8..25d3bd128 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -14,7 +14,7 @@ import { listSpec } from "../../../new_fields/Schema"; import { Docs, DocumentOptions } from "../../documents/Documents"; import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { Gateway } from "../../northstar/manager/Gateway"; -import { SetupDrag, DragManager } from "../../util/DragManager"; +import { DragManager } from "../../util/DragManager"; import { CompileScript, ts, Transformer } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss'; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 185bec7a2..34f2652ff 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -183,7 +183,7 @@ export class CollectionStackingViewFieldColumn extends React.Component(schemaCtor: (doc: Doc) => T) { if (de.data.dropAction || de.data.userDropAction) { added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); } else if (de.data.moveDocument) { - let movedDocs = de.data.options === this.props.Document[Id] ? de.data.draggedDocuments : de.data.droppedDocuments; - added = movedDocs.reduce((added: boolean, d) => - de.data.moveDocument(d, this.props.Document, this.props.addDocument) || added, false); + let movedDocs = de.data.draggedDocuments;// de.data.options === this.props.Document[Id] ? de.data.draggedDocuments : de.data.droppedDocuments; + // note that it's possible the drag function might create a drop document that's not the same as the + // original dragged document. So we explicitly call addDocument() with a droppedDocument and + added = movedDocs.reduce((added: boolean, d, i) => + de.data.moveDocument(d, this.props.Document, (doc: Doc) => this.props.addDocument(de.data.droppedDocuments[i])) || added, false); } else { added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index bce4eb427..548f663ec 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -95,8 +95,9 @@ export class CollectionView extends React.Component { } subItems.push({ description: "Schema", event: () => this.props.Document.viewType = CollectionViewType.Schema, icon: "th-list" }); subItems.push({ description: "Treeview", event: () => this.props.Document.viewType = CollectionViewType.Tree, icon: "tree" }); + subItems.push({ description: "Stacking", event: () => this.props.Document.viewType = CollectionViewType.Stacking, icon: "ellipsis-v" }); subItems.push({ - description: "Stacking", event: () => { + description: "Stacking (AutoHeight)", event: () => { this.props.Document.viewType = CollectionViewType.Stacking; this.props.Document.autoHeight = true }, icon: "ellipsis-v" diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ad91eb007..f2ca645a7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -381,7 +381,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { SelectionManager.DeselectAll(); prevSelected.map(dv => SelectionManager.SelectDoc(dv, true)); - let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined)); + let de = new DragManager.DocumentDragData(eles); de.moveDocument = this.props.moveDocument; const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index cc5e887b2..5cab6f8e0 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -315,7 +315,7 @@ export class MarqueeView extends React.Component dataExtensionField.ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined; this.marqueeInkDelete(inkData); - if (e.key === "s") { + if (e.key === "s" || e.key === "S") { selected.map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; @@ -324,35 +324,19 @@ export class MarqueeView extends React.Component return d; }); newCollection.chromeStatus = "disabled"; - let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); - newCollection.proto!.summaryDoc = summary; - selected = [newCollection]; - newCollection.x = bounds.left + bounds.width; - summary.proto!.subBulletDocs = new List(selected); - let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); - container.viewType = CollectionViewType.Stacking; - container.autoHeight = true; - this.props.addLiveTextDocument(container); - // }); - } else if (e.key === "S") { - selected.map(d => { - this.props.removeDocument(d); - d.x = NumCast(d.x) - bounds.left - bounds.width / 2; - d.y = NumCast(d.y) - bounds.top - bounds.height / 2; - d.page = -1; - return d; - }); - newCollection.chromeStatus = "disabled"; - let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); + let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); + summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" newCollection.proto!.summaryDoc = summary; - selected = [newCollection]; newCollection.x = bounds.left + bounds.width; - //this.props.addDocument(newCollection, false); - summary.proto!.summarizedDocs = new List(selected); - summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" - summary.autoHeight = true; - - this.props.addLiveTextDocument(summary); + if (e.key === "s") { // summary is wrapped in an expand/collapse container that also contains the summarized documents in a free form view. + let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); + container.viewType = CollectionViewType.Stacking; + container.autoHeight = true; + this.props.addLiveTextDocument(container); + } else if (e.key === "S") { // the summary stands alone, but is linked to a collection of the summarized documents - set the OnCLick behavior to link follow to access them + summary.proto!.summarizedDocs = new List([newCollection]); + this.props.addLiveTextDocument(summary); + } } else { this.props.addDocument(newCollection, false); diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index b6a24b0c8..d711ac284 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -57,7 +57,7 @@ export class LinkMenuGroup extends React.Component { let opp = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc); if (opp) return opp; }) as Doc[]; - let dragData = new DragManager.DocumentDragData(draggedDocs, draggedDocs.map(d => undefined)); + let dragData = new DragManager.DocumentDragData(draggedDocs); DragManager.StartLinkedDocumentDrag([this._drag.current], dragData, e.x, e.y, { handlers: { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e95f484a4..17bf02448 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -138,7 +138,6 @@ export class DocumentView extends DocComponent(Docu private _downY: number = 0; private _lastTap: number = 0; private _doubleTap = false; - private _hitExpander = false; private _hitTemplateDrag = false; private _mainCont = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; @@ -221,20 +220,19 @@ export class DocumentView extends DocComponent(Docu } get dataDoc() { - if (this.props.DataDoc === undefined && (this.props.Document.layout instanceof Doc || this.props.Document instanceof Promise)) { - // if there is no dataDoc (ie, we're not rendering a temlplate layout), but this document - // has a template layout document, then we will render the template layout but use - // this document as the data document for the layout. - return this.props.Document; - } + // bcz: don't think we need this, but left it in in case strange behavior pops up. DocumentContentsView has this functionality + // if (this.props.DataDoc === undefined && (this.props.Document.layout instanceof Doc || this.props.Document instanceof Promise)) { + // // if there is no dataDoc (ie, we're not rendering a temlplate layout), but this document + // // has a template layout document, then we will render the template layout but use + // // this document as the data document for the layout. + // return this.props.Document; + // } return this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; } - startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean, applyAsTemplate?: boolean) { + startDragging(x: number, y: number, dropAction: dropActionType, applyAsTemplate?: boolean) { if (this._mainCont.current) { - let allConnected = [this.props.Document, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])]; - let alldataConnected = [this.dataDoc, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])]; const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0); - let dragData = new DragManager.DocumentDragData(allConnected, alldataConnected); + let dragData = new DragManager.DocumentDragData([this.props.Document]); const [xoff, yoff] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.xOffset = xoff; @@ -249,14 +247,6 @@ export class DocumentView extends DocComponent(Docu }); } } - toggleMinimized = async () => { - let minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc); - if (minimizedDoc) { - let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint( - NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y)); - this.collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); - } - } static _undoBatch?: UndoManager.Batch = undefined; @action @@ -315,15 +305,13 @@ export class DocumentView extends DocComponent(Docu SelectionManager.SelectDoc(this, e.ctrlKey); let isExpander = (e.target as any).id === "isExpander"; if (BoolCast(this.props.Document.isButton) || this.props.Document.type === DocumentType.BUTTON || isExpander) { - let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs); let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs); let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs); let linkedDocs = LinkManager.Instance.getAllRelatedLinks(this.props.Document); let expandedDocs: Doc[] = []; - expandedDocs = subBulletDocs ? [...subBulletDocs, ...expandedDocs] : expandedDocs; expandedDocs = maximizedDocs ? [...maximizedDocs, ...expandedDocs] : expandedDocs; expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs; - // let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),]; + // let expandedDocs = [ ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),]; if (expandedDocs.length) { // bcz: need a better way to associate behaviors with click events on widget-documents SelectionManager.DeselectAll(); let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); @@ -394,7 +382,6 @@ export class DocumentView extends DocComponent(Docu if (e.nativeEvent.cancelBubble) return; this._downX = e.clientX; this._downY = e.clientY; - this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; this._hitTemplateDrag = false; for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { @@ -416,7 +403,7 @@ export class DocumentView extends DocComponent(Docu if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander, this._hitTemplateDrag); + this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers diff --git a/src/client/views/nodes/DragBox.tsx b/src/client/views/nodes/DragBox.tsx index 1f2c88086..067d47de4 100644 --- a/src/client/views/nodes/DragBox.tsx +++ b/src/client/views/nodes/DragBox.tsx @@ -55,7 +55,7 @@ export class DragBox extends DocComponent(DragDocu let doc = res !== undefined && res.success ? res.result as Doc : Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" }); - doc && DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([doc], [undefined]), e.clientX, e.clientY); + doc && DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY); } e.stopPropagation(); e.preventDefault(); diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 856e883e7..533247170 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -137,7 +137,7 @@ export default class Page extends React.Component { view.nativeWidth = this.props.Document.nativeWidth; view.startY = marquee.top + this.props.getScrollFromPage(this.props.page); view.width = this.props.Document[WidthSym](); - DragManager.StartDocumentDrag([], new DragManager.DocumentDragData([view], [undefined]), 0, 0); + DragManager.StartDocumentDrag([], new DragManager.DocumentDragData([view]), 0, 0); } @action diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index cd3dd912c..510672788 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -270,7 +270,7 @@ export class SearchItem extends React.Component { onPointerDown = (e: React.PointerEvent) => { e.stopPropagation(); const doc = Doc.IsPrototype(this.props.doc) ? Doc.MakeDelegate(this.props.doc) : this.props.doc; - DragManager.StartDocumentDrag([e.currentTarget], new DragManager.DocumentDragData([doc], []), e.clientX, e.clientY, { + DragManager.StartDocumentDrag([e.currentTarget], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY, { handlers: { dragComplete: emptyFunction }, hideSource: false, }); -- cgit v1.2.3-70-g09d2 From 999cd7deb87ce5c6430a5f8e0e1721033736bbab Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 16 Sep 2019 17:13:16 -0400 Subject: cleaned up titling of icons and summaries. --- src/client/views/DocumentDecorations.tsx | 6 ++- .../collections/collectionFreeForm/MarqueeView.tsx | 10 ++-- src/client/views/nodes/DocumentView.tsx | 22 +-------- src/client/views/nodes/IconBox.tsx | 53 +++++++++++++--------- 4 files changed, 43 insertions(+), 48 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ac1f51688..240abaf6b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -32,6 +32,8 @@ import { CurrentUserUtils } from '../../server/authentication/models/current_use import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { ObjectField } from '../../new_fields/ObjectField'; import { DocServer } from '../DocServer'; +import { CompileScript } from '../util/Scripting'; +import { ComputedField } from '../../new_fields/ScriptField'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -378,8 +380,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let doc = selected[0].props.Document; let iconDoc = Docs.Create.IconDocument(layoutString); iconDoc.isButton = true; - iconDoc.proto!.title = selected.length > 1 ? "-multiple-.icon" : StrCast(doc.title) + ".icon"; - iconDoc.labelField = selected.length > 1 ? undefined : this._fieldKey; + + IconBox.AutomaticTitle(iconDoc); //iconDoc.proto![this._fieldKey] = selected.length > 1 ? "collection" : undefined; iconDoc.proto!.isMinimized = false; iconDoc.width = Number(MINIMIZED_ICON_SIZE); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 5cab6f8e0..d74fbafb3 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -23,6 +23,8 @@ import { SchemaHeaderField, RandomPastel } from "../../../../new_fields/SchemaHe import { string } from "prop-types"; import { listSpec } from "../../../../new_fields/Schema"; import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; +import { CompileScript } from "../../../util/Scripting"; +import { ComputedField } from "../../../../new_fields/ScriptField"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -309,7 +311,7 @@ export class MarqueeView extends React.Component defaultBackgroundColor: this.props.container.isAnnotationOverlay ? undefined : chosenColor, width: bounds.width, height: bounds.height, - title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection", + title: "a nested collection", }); let dataExtensionField = Doc.CreateDocumentExtensionForField(newCollection, "data"); dataExtensionField.ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined; @@ -325,9 +327,11 @@ export class MarqueeView extends React.Component }); newCollection.chromeStatus = "disabled"; let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); - summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" - newCollection.proto!.summaryDoc = summary; + Doc.GetProto(summary).maximizeLocation = "inTab"; // or "inPlace", or "onRight" + Doc.GetProto(newCollection).summaryDoc = summary; newCollection.x = bounds.left + bounds.width; + let computed = CompileScript(`return summaryTitle(this);`, { params: { this: "Doc" }, typecheck: false }); + computed.compiled && (Doc.GetProto(newCollection).title = new ComputedField(computed)); if (e.key === "s") { // summary is wrapped in an expand/collapse container that also contains the summarized documents in a free form view. let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); container.viewType = CollectionViewType.Stacking; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 760f4d584..50a9aa326 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -141,13 +141,11 @@ export class DocumentView extends DocComponent(Docu private _hitTemplateDrag = false; private _mainCont = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; - _animateToIconDisposer?: IReactionDisposer; - _reactionDisposer?: IReactionDisposer; + private _animateToIconDisposer?: IReactionDisposer; public get ContentDiv() { return this._mainCont.current; } @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } @computed get topMost(): boolean { return this.props.renderDepth === 0; } - screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); @action componentDidMount() { @@ -156,19 +154,6 @@ export class DocumentView extends DocComponent(Docu handlers: { drop: this.drop.bind(this) } }); } - // bcz: kind of ugly .. setup a reaction to update the title of a summary document's target (maximizedDocs) whenver the summary doc's title changes - this._reactionDisposer = reaction(() => [DocListCast(this.props.Document.maximizedDocs).map(md => md.title), - this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""], - () => { - let maxDoc = DocListCast(this.props.Document.maximizedDocs); - if (maxDoc.length === 1 && StrCast(this.props.Document.title).startsWith("-") && StrCast(this.props.Document.layout).indexOf("IconBox") !== -1) { - this.props.Document.proto!.title = "-" + maxDoc[0].title + ".icon"; - } - let sumDoc = Cast(this.props.Document.summaryDoc, Doc); - if (sumDoc instanceof Doc && StrCast(this.props.Document.title).startsWith("-")) { - this.props.Document.proto!.title = "-" + sumDoc.title + ".expanded"; - } - }, { fireImmediately: true }); this._animateToIconDisposer = reaction(() => this.props.Document.isIconAnimating, (values) => (values instanceof List) && this.animateBetweenIcon(values, values[2], values[3] ? true : false) , { fireImmediately: true }); @@ -209,16 +194,11 @@ export class DocumentView extends DocComponent(Docu } @action componentWillUnmount() { - this._reactionDisposer && this._reactionDisposer(); this._animateToIconDisposer && this._animateToIconDisposer(); this._dropDisposer && this._dropDisposer(); DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } - stopPropagation = (e: React.SyntheticEvent) => { - e.stopPropagation(); - } - get dataDoc() { // bcz: don't think we need this, but left it in in case strange behavior pops up. DocumentContentsView has this functionality // if (this.props.DataDoc === undefined && (this.props.Document.layout instanceof Doc || this.props.Document instanceof Promise)) { diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 7e78ec684..ef9885bcf 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -12,6 +12,8 @@ import { IconField } from "../../../new_fields/IconField"; import { ContextMenu } from "../ContextMenu"; import Measure from "react-measure"; import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss"; +import { Scripting, CompileScript } from "../../util/Scripting"; +import { ComputedField } from "../../../new_fields/ScriptField"; library.add(faCaretUp); @@ -27,6 +29,26 @@ export class IconBox extends React.Component { @computed get layout(): string { const field = Cast(this.props.Document[this.props.fieldKey], IconField); return field ? field.icon : "

Error loading icon data

"; } @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } + public static summaryTitleScript(inputDoc: Doc) { + const sumDoc = Cast(inputDoc.summaryDoc, Doc) as Doc; + if (sumDoc && StrCast(sumDoc.title).startsWith("-")) { + return sumDoc.title + ".expanded"; + } + return "???"; + } + public static titleScript(inputDoc: Doc) { + const maxDoc = DocListCast(inputDoc.maximizedDocs); + if (maxDoc.length === 1 && StrCast(maxDoc[0].title).startsWith("-")) { + return maxDoc[0].title + ".icon"; + } + return maxDoc.length > 1 ? "-multiple-.icon" : "???"; + } + + public static AutomaticTitle(doc: Doc) { + let computed = CompileScript(`return iconTitle(this);`, { params: { this: "Doc" }, typecheck: false }); + computed.compiled && (Doc.GetProto(doc).title = new ComputedField(computed)); + } + public static DocumentIcon(layout: string) { let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf : layout.indexOf("ImageBox") !== -1 ? faImage : @@ -38,35 +60,20 @@ export class IconBox extends React.Component { } setLabelField = (): void => { - this.props.Document.hideLabel = !BoolCast(this.props.Document.hideLabel); - } - setUseOwnTitleField = (): void => { - this.props.Document.useOwnTitle = !BoolCast(this.props.Document.useTargetTitle); + this.props.Document.hideLabel = !this.props.Document.hideLabel; } specificContextMenu = (): void => { - ContextMenu.Instance.addItem({ - description: BoolCast(this.props.Document.hideLabel) ? "Show label with icon" : "Remove label from icon", - event: this.setLabelField, - icon: "tag" - }); - let maxDocs = DocListCast(this.props.Document.maximizedDocs); - if (maxDocs.length === 1 && !BoolCast(this.props.Document.hideLabel)) { - ContextMenu.Instance.addItem({ - description: BoolCast(this.props.Document.useOwnTitle) ? "Use target title for label" : "Use own title label", - event: this.setUseOwnTitleField, - icon: "text-height" - }); + let cm = ContextMenu.Instance; + cm.addItem({ description: this.props.Document.hideLabel ? "Show label with icon" : "Remove label from icon", event: this.setLabelField, icon: "tag" }); + if (!this.props.Document.hideLabel) { + cm.addItem({ description: "Use Target Title", event: () => IconBox.AutomaticTitle(this.props.Document), icon: "text-height" }); } } @observable _panelWidth: number = 0; @observable _panelHeight: number = 0; render() { - let labelField = StrCast(this.props.Document.labelField); - let hideLabel = BoolCast(this.props.Document.hideLabel); - let maxDocs = DocListCast(this.props.Document.maximizedDocs); - let firstDoc = maxDocs.length ? maxDocs[0] : undefined; - let label = hideLabel ? "" : (firstDoc && labelField && !BoolCast(this.props.Document.useOwnTitle) ? firstDoc[labelField] : this.props.Document.title); + let label = this.props.Document.hideLabel ? "" : this.props.Document.title; return (
{this.minimizedIcon} @@ -82,4 +89,6 @@ export class IconBox extends React.Component {
); } -} \ No newline at end of file +} +Scripting.addGlobal(function iconTitle(doc: any) { return IconBox.titleScript(doc); }); +Scripting.addGlobal(function summaryTitle(doc: any) { return IconBox.summaryTitleScript(doc); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 624d44ad339d55df66a4ed8bf4b2cb91608efeef Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 16 Sep 2019 17:45:30 -0400 Subject: fixed maximizing of summarized documents and docs in stacking views. --- src/client/views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 5 +++-- src/client/views/nodes/DocumentView.tsx | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 14a9dc9d9..0a96676e3 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -163,7 +163,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ; } getDocHeight(d?: Doc) { - if (!d) return 0; + if (!d || d.willMaximize) return 0; let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (!d.ignoreAspect && nw && nh) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index d74fbafb3..8decebe0d 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -327,8 +327,8 @@ export class MarqueeView extends React.Component }); newCollection.chromeStatus = "disabled"; let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); - Doc.GetProto(summary).maximizeLocation = "inTab"; // or "inPlace", or "onRight" Doc.GetProto(newCollection).summaryDoc = summary; + Doc.GetProto(summary).summarizedDocs = new List([newCollection]); newCollection.x = bounds.left + bounds.width; let computed = CompileScript(`return summaryTitle(this);`, { params: { this: "Doc" }, typecheck: false }); computed.compiled && (Doc.GetProto(newCollection).title = new ComputedField(computed)); @@ -336,9 +336,10 @@ export class MarqueeView extends React.Component let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); container.viewType = CollectionViewType.Stacking; container.autoHeight = true; + Doc.GetProto(summary).maximizeLocation = "inPlace"; // or "inPlace", or "onRight" this.props.addLiveTextDocument(container); } else if (e.key === "S") { // the summary stands alone, but is linked to a collection of the summarized documents - set the OnCLick behavior to link follow to access them - summary.proto!.summarizedDocs = new List([newCollection]); + Doc.GetProto(summary).maximizeLocation = "inTab"; // or "inPlace", or "onRight" this.props.addLiveTextDocument(summary); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 50a9aa326..c9bd60d35 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -300,7 +300,7 @@ export class DocumentView extends DocComponent(Docu maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace")); if (!maxLocation || maxLocation === "inPlace") { let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); - let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized), false); + let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !d.isMinimized, false); expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false); let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); if (!hasView) { @@ -814,8 +814,8 @@ export class DocumentView extends DocComponent(Docu this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); let foregroundColor = StrCast(this.layoutDoc.color); - var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; - var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; + var nativeWidth = this.props.Document.willMaximize ? 0 : this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; + var nativeHeight = this.props.Document.willMaximize ? 0 : BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined; let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle); let showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : StrCast(this.layoutDoc.showCaption); -- cgit v1.2.3-70-g09d2 From 088a16c9589e640e814d9120fecc0003ab9d594e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 18 Sep 2019 09:48:15 -0400 Subject: cleaned up some CompileScript code --- src/client/documents/Documents.ts | 6 ++-- src/client/util/DragManager.ts | 10 +------ .../views/collections/CollectionSchemaView.tsx | 7 ++--- .../CollectionStackingViewFieldColumn.tsx | 10 ++----- .../views/collections/CollectionViewChromes.tsx | 17 ++++------- .../collections/collectionFreeForm/MarqueeView.tsx | 21 +++++--------- src/client/views/nodes/DocumentView.tsx | 15 ++-------- src/client/views/nodes/IconBox.tsx | 5 ++-- src/client/views/nodes/ImageBox.tsx | 5 +--- src/client/views/nodes/PDFBox.tsx | 6 ++-- src/client/views/nodes/VideoBox.tsx | 14 +-------- src/new_fields/Doc.ts | 9 ++---- src/new_fields/ScriptField.ts | 33 ++++++++++++++++++---- 13 files changed, 58 insertions(+), 100 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 206e2c4f1..99707db19 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -663,10 +663,8 @@ export namespace DocUtils { LinkManager.Instance.addLink(linkDocProto); - let script = `return links(this);`; - let computed = CompileScript(script, { params: { this: "Doc" }, typecheck: false }); - computed.compiled && (Doc.GetProto(source).links = new ComputedField(computed)); - computed.compiled && (Doc.GetProto(target).links = new ComputedField(computed)); + Doc.GetProto(source).links = ComputedField.MakeFunction("links(this)"); + Doc.GetProto(target).links = ComputedField.MakeFunction("links(this)"); }, "make link"); return linkDocProto; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index cb55e1bc6..bd7051993 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -256,15 +256,7 @@ export namespace DragManager { StartDrag(eles, dragData, downX, downY, options, options && options.finishDrag ? options.finishDrag : (dropData: { [id: string]: any }) => { let bd = Docs.Create.ButtonDocument({ width: 150, height: 50, title: title }); - let compiled = CompileScript(script, { - params: { doc: Doc.name }, - typecheck: false, - editable: true - }); - if (compiled.compiled) { - let scriptField = new ScriptField(compiled); - bd.onClick = scriptField; - } + bd.onClick = ScriptField.MakeScript(script); params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); initialize && initialize(bd); bd.buttonParams = new List(params); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 25d3bd128..5d09ade32 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -946,13 +946,10 @@ export class CollectionSchemaPreview extends React.Component { if (de.data instanceof DragManager.DocumentDragData) { - let docDrag = de.data; - let computed = CompileScript("return this.image_data[0]", { params: { this: "Doc" } }); this.props.childDocs && this.props.childDocs.map(otherdoc => { - let doc = docDrag.draggedDocuments[0]; let target = Doc.GetProto(otherdoc); - target.layout = target.detailedLayout = Doc.MakeDelegate(doc); - computed.compiled && (target.miniLayout = new ComputedField(computed)); + target.layout = target.detailedLayout = Doc.MakeDelegate(de.data.draggedDocuments[0]); + target.miniLayout = ComputedField.MakeFunction("this.image_data[0]"); }); e.stopPropagation(); } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 34f2652ff..b3b7b40dd 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -178,13 +178,9 @@ export class CollectionStackingViewFieldColumn extends React.Component { - let compiled = CompileScript("return true", { params: { doc: Doc.name }, typecheck: false }); - if (compiled.compiled) { - this.props.CollectionView.props.Document.viewSpecScript = new ScriptField(compiled); - } - + this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name }); this._keyRestrictions = []; this.addKeyRestrictions([]); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8decebe0d..479e98840 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,30 +1,24 @@ -import * as htmlToImage from "html-to-image"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, FieldResult, DocListCast } from "../../../../new_fields/Doc"; -import { Id } from "../../../../new_fields/FieldSymbols"; +import { Doc, DocListCast } from "../../../../new_fields/Doc"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; +import { listSpec } from "../../../../new_fields/Schema"; +import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; +import { ComputedField } from "../../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../../new_fields/Types"; +import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; import { Utils } from "../../../../Utils"; -import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; import { PreviewCursor } from "../../PreviewCursor"; -import { Templates } from "../../Templates"; import { CollectionViewType } from "../CollectionBaseView"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); -import { SchemaHeaderField, RandomPastel } from "../../../../new_fields/SchemaHeaderField"; -import { string } from "prop-types"; -import { listSpec } from "../../../../new_fields/Schema"; -import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; -import { CompileScript } from "../../../util/Scripting"; -import { ComputedField } from "../../../../new_fields/ScriptField"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -327,11 +321,10 @@ export class MarqueeView extends React.Component }); newCollection.chromeStatus = "disabled"; let summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); - Doc.GetProto(newCollection).summaryDoc = summary; Doc.GetProto(summary).summarizedDocs = new List([newCollection]); newCollection.x = bounds.left + bounds.width; - let computed = CompileScript(`return summaryTitle(this);`, { params: { this: "Doc" }, typecheck: false }); - computed.compiled && (Doc.GetProto(newCollection).title = new ComputedField(computed)); + Doc.GetProto(newCollection).summaryDoc = summary; + Doc.GetProto(newCollection).title = ComputedField.MakeFunction(`summaryTitle(this);`); if (e.key === "s") { // summary is wrapped in an expand/collapse container that also contains the summarized documents in a free form view. let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); container.viewType = CollectionViewType.Stacking; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 152dc3ddd..16f8275c7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -40,7 +40,7 @@ import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import { FormattedTextBox } from './FormattedTextBox'; import React = require("react"); -import { CompileScript, Scripting } from '../../util/Scripting'; +import { Scripting } from '../../util/Scripting'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -559,18 +559,7 @@ export class DocumentView extends DocComponent(Docu let existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); let onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); - onClicks.push({ - description: "Toggle Detail", event: () => { - let compiled = CompileScript("toggleDetail(this)", { - params: { this: "Doc" }, - typecheck: false, - editable: true, - }); - if (compiled.compiled) { - this.Document.onClick = new ScriptField(compiled); - } - }, icon: "window-restore" - }); + onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript("toggleDetail(this)"), icon: "window-restore" }); onClicks.push({ description: this.layoutDoc.ignoreClick ? "Select" : "Do Nothing", event: () => this.layoutDoc.ignoreClick = !this.layoutDoc.ignoreClick, icon: this.layoutDoc.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) }); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 92cb5a9c9..63a504d1a 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -12,7 +12,7 @@ import { IconField } from "../../../new_fields/IconField"; import { ContextMenu } from "../ContextMenu"; import Measure from "react-measure"; import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss"; -import { Scripting, CompileScript } from "../../util/Scripting"; +import { Scripting } from "../../util/Scripting"; import { ComputedField } from "../../../new_fields/ScriptField"; @@ -45,8 +45,7 @@ export class IconBox extends React.Component { } public static AutomaticTitle(doc: Doc) { - let computed = CompileScript(`return iconTitle(this);`, { params: { this: "Doc" }, typecheck: false }); - computed.compiled && (Doc.GetProto(doc).title = new ComputedField(computed)); + Doc.GetProto(doc).title = ComputedField.MakeFunction('iconTitle(this);'); } public static DocumentIcon(layout: string) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 42307ee02..bbcc296e6 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -17,7 +17,6 @@ import { Utils } from '../../../Utils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; -import { CompileScript } from '../../util/Scripting'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; import { ContextMenuProps } from '../ContextMenuItem'; @@ -244,9 +243,7 @@ export class ImageBox extends DocComponent(ImageD results.tags.map((tag: Tag) => { tagsList.push(tag.name); let sanitized = tag.name.replace(" ", "_"); - let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`; - let computed = CompileScript(script, { params: { this: "Doc" } }); - computed.compiled && (tagDoc[sanitized] = new ComputedField(computed)); + tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`); }); this.extensionDoc.generatedTags = tagsList; tagDoc.title = "Generated Tags Doc"; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 31e8f122b..64b84ba55 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -10,7 +10,6 @@ import { ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast } from "../../../new_fields/Types"; import { PdfField } from "../../../new_fields/URLField"; import { KeyCodes } from '../../northstar/utils/KeyCodes'; -import { CompileScript } from '../../util/Scripting'; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; import { PDFViewer } from "../pdf/PDFViewer"; @@ -104,9 +103,8 @@ export class PDFBox extends DocComponent(PdfDocumen private applyFilter = () => { let scriptText = this._scriptValue.length > 0 ? this._scriptValue : this._keyValue.length > 0 && this._valueValue.length > 0 ? - `return this.${this._keyValue} === ${this._valueValue}` : "return true"; - let script = CompileScript(scriptText, { params: { this: Doc.name } }); - script.compiled && (this.props.Document.filterScript = new ScriptField(script)); + `this.${this._keyValue} === ${this._valueValue}` : "true"; + this.props.Document.filterScript = ScriptField.MakeFunction(scriptText); } scrollTo = (y: number) => { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index a696f255d..aa6be56bb 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -20,7 +20,6 @@ import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; import { library } from "@fortawesome/fontawesome-svg-core"; import { faVideo } from "@fortawesome/free-solid-svg-icons"; -import { CompileScript } from "../../util/Scripting"; import { Doc } from "../../../new_fields/Doc"; import { ScriptField } from "../../../new_fields/ScriptField"; var path = require('path'); @@ -116,18 +115,7 @@ export class VideoBox extends DocComponent(VideoD x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), width: 150, height: 50, title: NumCast(this.props.Document.curPage).toString() }); - const script = CompileScript(`(self as any).curPage = ${NumCast(this.props.Document.curPage)}`, { - params: { this: Doc.name }, - capturedVariables: { self: this.props.Document }, - typecheck: false, - editable: true, - }); - if (script.compiled) { - b.onClick = new ScriptField(script); - this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.addDocument && this.props.ContainingCollectionView.props.addDocument(b, false); - } else { - console.log(script.errors.map(error => error.messageText).join("\n")); - } + b.onClick = ScriptField.MakeScript(`this.curPage = ${NumCast(this.props.Document.curPage)}`); } else { //convert to desired file format var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index ffa9a4e98..98b3d824e 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -2,7 +2,7 @@ import { observable, ObservableMap, runInAction, action } from "mobx"; import { alias, map, serializable } from "serializr"; import { DocServer } from "../client/DocServer"; import { DocumentType } from "../client/documents/DocumentTypes"; -import { CompileScript, Scripting, scriptingGlobal } from "../client/util/Scripting"; +import { Scripting, scriptingGlobal } from "../client/util/Scripting"; import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper"; import { Copy, HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, Update } from "./FieldSymbols"; import { List } from "./List"; @@ -426,12 +426,7 @@ export namespace Doc { alias.layout = Doc.MakeAlias(alias.layout); } let aliasNumber = Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1; - let script = `return renameAlias(self, ${aliasNumber})`; - //let script = "StrCast(self.title).replace(/\\([0-9]*\\)/, \"\") + `(${n})`"; - let compiled = CompileScript(script, { params: { this: "Doc" }, capturedVariables: { self: doc }, typecheck: false }); - if (compiled.compiled) { - alias.title = new ComputedField(compiled); - } + alias.title = ComputedField.MakeFunction(`renameAlias(this, ${aliasNumber})`); return alias; } diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index 83fb52d07..8f10766df 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -1,5 +1,5 @@ import { ObjectField } from "./ObjectField"; -import { CompiledScript, CompileScript, scriptingGlobal } from "../client/util/Scripting"; +import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions } from "../client/util/Scripting"; import { Copy, ToScriptString, Parent, SelfProxy } from "./FieldSymbols"; import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; import { Deserializable, autoObject } from "../client/util/SerializationHelper"; @@ -101,6 +101,24 @@ export class ScriptField extends ObjectField { [ToScriptString]() { return "script field"; } + public static CompileScript(script: string, params: object = {}, addReturn = false) { + let compiled = CompileScript(script, { + params: { this: Doc.name, ...params }, + typecheck: false, + editable: true, + addReturn: addReturn + }); + return compiled; + } + public static MakeFunction(script: string, params: object = {}) { + let compiled = ScriptField.CompileScript(script, params, true); + return compiled.compiled ? new ScriptField(compiled) : undefined; + } + + public static MakeScript(script: string, params: object = {}) { + let compiled = ScriptField.CompileScript(script, params, false); + return compiled.compiled ? new ScriptField(compiled) : undefined; + } } @scriptingGlobal @@ -109,11 +127,16 @@ export class ComputedField extends ScriptField { //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc value = computedFn((doc: Doc) => { const val = this.script.run({ this: doc }); - if (val.success) { - return val.result; - } - return undefined; + return val.success ? val.result : undefined; }); + public static MakeScript(script: string, params: object = {}, ) { + let compiled = ScriptField.CompileScript(script, params, false); + return compiled.compiled ? new ComputedField(compiled) : undefined; + } + public static MakeFunction(script: string, params: object = {}) { + let compiled = ScriptField.CompileScript(script, params, true); + return compiled.compiled ? new ComputedField(compiled) : undefined; + } } export namespace ComputedField { -- cgit v1.2.3-70-g09d2 From 4652881dbdffefab2240a2a0a509f8505376f91b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 18 Sep 2019 17:25:10 -0400 Subject: cleaned up navigate into portal and alt-dragging to copy contents --- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 160 +++++++++------------ src/client/views/nodes/FormattedTextBox.tsx | 9 +- src/client/views/nodes/ImageBox.tsx | 26 +--- 5 files changed, 92 insertions(+), 118 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 359731bda..baf907634 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -607,7 +607,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } } - focusDocument = (doc: Doc, willZoom: boolean, scale?: number) => { + focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => { const state = HistoryUtil.getState(); // TODO This technically isn't correct if type !== "doc", as // currently nothing is done, but we should probably push a new state @@ -628,6 +628,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const newState = HistoryUtil.getState(); newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; HistoryUtil.pushState(newState); + + let px = this.Document.panX; + let py = this.Document.panY; + let s = this.Document.scale; this.setPan(newPanX, newPanY); this.props.Document.panTransformType = "Ease"; @@ -635,6 +639,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (willZoom) { this.setScaleToZoom(doc, scale); } + afterFocus && setTimeout(() => { + if (afterFocus && afterFocus()) { + this.Document.panX = px; + this.Document.panY = py; + this.Document.scale = s; + } + }, 1000); } setScaleToZoom = (doc: Doc, scale: number = 0.5) => { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 479e98840..18d0fea8c 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -329,7 +329,7 @@ export class MarqueeView extends React.Component let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); container.viewType = CollectionViewType.Stacking; container.autoHeight = true; - Doc.GetProto(summary).maximizeLocation = "inPlace"; // or "inPlace", or "onRight" + Doc.GetProto(summary).maximizeLocation = "inPlace"; // or "onRight" this.props.addLiveTextDocument(container); } else if (e.key === "S") { // the summary stands alone, but is linked to a collection of the summarized documents - set the OnCLick behavior to link follow to access them Doc.GetProto(summary).maximizeLocation = "inTab"; // or "inPlace", or "onRight" diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 11924f86a..90dbe4c86 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -81,7 +81,7 @@ export interface DocumentViewProps { ruleProvider: Doc | undefined; PanelWidth: () => number; PanelHeight: () => number; - focus: (doc: Doc, willZoom: boolean, scale?: number) => void; + focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => void; parentActive: () => boolean; whenActiveChanged: (isActive: boolean) => void; bringToFront: (doc: Doc, sendToBack?: boolean) => void; @@ -136,8 +136,11 @@ export class DocumentView extends DocComponent(Docu private _dropDisposer?: DragManager.DragDropDisposer; public get ContentDiv() { return this._mainCont.current; } - @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } - @computed get topMost(): boolean { return this.props.renderDepth === 0; } + @computed get active() { return SelectionManager.IsSelected(this) || this.props.parentActive(); } + @computed get topMost() { return this.props.renderDepth === 0; } + @computed get nativeWidth() { return this.Document.nativeWidth || 0; } + @computed get nativeHeight() { return this.Document.nativeHeight || 0; } + @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } @action componentDidMount() { @@ -280,19 +283,8 @@ export class DocumentView extends DocComponent(Docu let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab"); let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined; DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, - document => { // open up target if it's not already in view ... - let cv = this.props.ContainingCollectionView; // bcz: ugh --- maybe need to have a props.unfocus() method so that we leave things in the state we found them?? - let px = cv && cv.props.Document.panX; - let py = cv && cv.props.Document.panY; - let s = cv && cv.props.Document.scale; - this.props.focus(this.props.Document, true, 1); // by zooming into the button document first - setTimeout(() => { - this.props.addDocTab(document, undefined, maxLocation); - cv && (cv.props.Document.panX = px); - cv && (cv.props.Document.panY = py); - cv && (cv.props.Document.scale = s); - }, 1000); // then after the 1sec animation, open up the target in a new tab - }, + // open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards + doc => this.props.focus(this.props.Document, true, 1, () => { this.props.addDocTab(doc, undefined, maxLocation); return true; }), linkedFwdPage[altKey ? 1 : 0], targetContext); } } @@ -300,12 +292,13 @@ export class DocumentView extends DocComponent(Docu } } - onPointerDown = (e: React.PointerEvent): void => { if (e.nativeEvent.cancelBubble) return; this._downX = e.clientX; this._downY = e.clientY; this._hitTemplateDrag = false; + // this whole section needs to move somewhere else. We're trying to initiate a special "template" drag where + // this document is the template and we apply it to whatever we drop it on. for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { this._hitTemplateDrag = true; @@ -386,16 +379,17 @@ export class DocumentView extends DocComponent(Docu @action drop = async (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.AnnotationDragData) { + /// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner e.stopPropagation(); - let annotationDoc = de.data.annotationDocument; - annotationDoc.linkedToDoc = true; - de.data.targetContext = this.props.ContainingCollectionView!.props.Document; + let sourceDoc = de.data.annotationDocument; let targetDoc = this.props.Document; + let annotations = await DocListCastAsync(sourceDoc.annotations); + sourceDoc.linkedToDoc = true; + de.data.targetContext = this.props.ContainingCollectionView!.props.Document; targetDoc.targetContext = de.data.targetContext; - let annotations = await DocListCastAsync(annotationDoc.annotations); annotations && annotations.forEach(anno => anno.target = targetDoc); - DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Link from ${StrCast(annotationDoc.title)}`); + DocUtils.MakeLink(sourceDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Link from ${StrCast(sourceDoc.title)}`); } if (de.data instanceof DragManager.DocumentDragData && de.data.applyAsTemplate) { Doc.ApplyTemplateTo(de.data.draggedDocuments[0], this.props.Document, this.props.DataDoc); @@ -406,22 +400,10 @@ export class DocumentView extends DocComponent(Docu let destDoc = this.props.Document; e.stopPropagation(); - if (de.mods === "AltKey") { - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - let src = protoSrc ? protoSrc : sourceDoc; - let dst = protoDest ? protoDest : destDoc; - dst.data = (src.data! as ObjectField)[Copy](); - dst.nativeWidth = src.nativeWidth; - dst.nativeHeight = src.nativeHeight; - } - else { - // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); - // const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); - let linkDoc = DocUtils.MakeLink(sourceDoc, destDoc, this.props.ContainingCollectionView ? this.props.ContainingCollectionView.props.Document : undefined); - de.data.droppedDocuments.push(destDoc); - de.data.linkDocument = linkDoc; - } + // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); + // const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); + de.data.droppedDocuments.push(destDoc); + de.data.linkDocument = DocUtils.MakeLink(sourceDoc, destDoc, this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document); } } @@ -448,13 +430,12 @@ export class DocumentView extends DocComponent(Docu proto.nativeHeight = this.props.PanelHeight(); } } + @undoBatch @action - makeIntoPortal = (): void => { - if (!DocListCast(this.props.Document.links).find(doc => { - if (Cast(doc.anchor2, Doc) instanceof Doc && (Cast(doc.anchor2, Doc) as Doc)!.title === this.Document.title + ".portal") return true; - return false; - })) { + makeIntoPortal = async () => { + let anchors = await Promise.all(DocListCast(this.props.Document.links).map(async (d: Doc) => await Cast(d.anchor2, Doc))); + if (!anchors.find(anchor2 => anchor2 && anchor2.title === this.Document.title + ".portal" ? true : false)) { let portalID = (this.Document.title + ".portal").replace(/^-/, "").replace(/\([0-9]*\)$/, ""); DocServer.GetRefField(portalID).then(existingPortal => { let portal = existingPortal instanceof Doc ? existingPortal : Docs.Create.FreeformDocument([], { width: (this.Document.width || 0) + 10, height: this.Document.height || 0, title: portalID }); @@ -463,17 +444,14 @@ export class DocumentView extends DocComponent(Docu }); } } + @undoBatch @action toggleCustomView = (): void => { if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.DataDoc) { Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.DataDoc); - } else { - if (typeof this.props.Document.layout === "string") { - this.makeCustomViewClicked(); - } else { - this.makeNativeViewClicked(); - } + } else { // bcz: not robust -- for now documents with string layout are native documents, and those with Doc layouts are customized + typeof this.props.Document.layout === "string" ? this.makeCustomViewClicked() : this.makeNativeViewClicked(); } } @@ -572,49 +550,46 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin" }); //I think this should work... and it does! A miracle! cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); cm.addItem({ - description: "Download document", icon: "download", event: async () => { - let y = JSON.parse(await rp.get(Utils.CorsProxy("http://localhost:8983/solr/dash/select"), { + description: "Download document", icon: "download", event: async () => + console.log(JSON.parse(await rp.get(Utils.CorsProxy("http://localhost:8983/solr/dash/select"), { qs: { q: 'world', fq: 'NOT baseProto_b:true AND NOT deleted:true', start: '0', rows: '100', hl: true, 'hl.fl': '*' } - })); - console.log(y); - // const a = document.createElement("a"); - // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); - // a.href = url; - // a.download = `DocExport-${this.props.Document[Id]}.zip`; - // a.click(); - } + }))) + // const a = document.createElement("a"); + // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); + // a.href = url; + // a.download = `DocExport-${this.props.Document[Id]}.zip`; + // a.click(); }); cm.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" }); cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); - type User = { email: string, userDocumentId: string }; - let usersMenu: ContextMenuProps[] = []; try { - let stuff = await rp.get(Utils.prepend(RouteStore.getUsers)); - const users: User[] = JSON.parse(stuff); - usersMenu = users.filter(({ email }) => email !== Doc.CurrentUserEmail).map(({ email, userDocumentId }) => ({ - description: email, event: async () => { + type User = { email: string, userDocumentId: string }; + const users: User[] = JSON.parse(await rp.get(Utils.prepend(RouteStore.getUsers))); + let usersMenu = users.filter(({ email }) => email !== Doc.CurrentUserEmail).map(({ email, userDocumentId }) => ({ + description: email, + event: async () => { const userDocument = await Cast(DocServer.GetRefField(userDocumentId), Doc); - if (!userDocument) { - throw new Error(`Couldn't get user document of user ${email}`); - } - const notifDoc = await Cast(userDocument.optionalRightCollection, Doc); - if (notifDoc instanceof Doc) { - const data = await Cast(notifDoc.data, listSpec(Doc)); - const sharedDoc = Doc.MakeAlias(this.props.Document); - if (data) { - data.push(sharedDoc); - } else { - notifDoc.data = new List([sharedDoc]); + if (userDocument) { + const notifDoc = await Cast(userDocument.optionalRightCollection, Doc); + if (notifDoc) { + const data = await Cast(notifDoc.data, listSpec(Doc)); + const sharedDoc = Doc.MakeAlias(this.props.Document); + if (data) { + data.push(sharedDoc); + } else { + notifDoc.data = new List([sharedDoc]); + } } } - }, icon: "male" - })); + }, + icon: "male" + } as ContextMenuProps)); + cm.addItem({ description: "Share...", subitems: usersMenu, icon: "share" }); } catch { } runInAction(() => { - cm.addItem({ description: "Share...", subitems: usersMenu, icon: "share" }); if (!ClientUtils.RELEASE) { let setWriteMode = (mode: DocServer.WriteMode) => { DocServer.AclsMode = mode; @@ -651,19 +626,7 @@ export class DocumentView extends DocComponent(Docu } isSelected = () => SelectionManager.IsSelected(this); - @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; - @computed get nativeWidth() { return this.Document.nativeWidth || 0; } - @computed get nativeHeight() { return this.Document.nativeHeight || 0; } - @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } - @computed get contents() { - return (); - } + select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; chromeHeight = () => { let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; @@ -715,6 +678,13 @@ export class DocumentView extends DocComponent(Docu SetValue={(value: string) => (Doc.GetProto(this.Document)[showTitle] = value) ? true : true} /> ); + const contents = (); return (
(Docu {!showTitle && !showCaption ? this.Document.searchFields ? (
- {this.contents} + {contents} {searchHighlight}
) : - this.contents + contents :
- {this.contents} + {contents}
{titleView} {captionView} diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 3883886e8..ab0412c37 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -297,8 +297,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe e.stopPropagation(); } else if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; - if (draggedDoc && draggedDoc.type === DocumentType.TEXT) { - if (!Doc.AreProtosEqual(draggedDoc, this.props.Document)) { + if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document)) { + if (de.mods === "AltKey") { + if (draggedDoc.data instanceof RichTextField) { + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data); + e.stopPropagation(); + } + } else { draggedDoc.isTemplate = true; if (typeof (draggedDoc.layout) === "string") { let layoutDelegateToOverrideFieldKey = Doc.MakeDelegate(draggedDoc); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index bbcc296e6..3cb64aa40 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -87,26 +87,14 @@ export class ImageBox extends DocComponent(ImageD @action drop = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - de.data.droppedDocuments.forEach(action((drop: Doc) => { - if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { - Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url); - e.stopPropagation(); - } else if (de.mods === "MetaKey") { - if (this.extensionDoc !== this.dataDoc) { - let layout = StrCast(drop.backgroundLayout); - if (layout.indexOf(ImageBox.name) !== -1) { - let imgData = this.extensionDoc.Alternates; - if (!imgData) { - Doc.GetProto(this.extensionDoc).Alternates = new List([]); - } - let imgList = Cast(this.extensionDoc.Alternates, listSpec(Doc), [] as any[]); - imgList && imgList.push(drop); - e.stopPropagation(); - } - } - } + if (de.mods === "AltKey" && de.data.draggedDocuments.length && de.data.draggedDocuments[0].data instanceof ImageField) { + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(de.data.draggedDocuments[0].data.url); + e.stopPropagation(); + } + de.mods === "MetaKey" && de.data.droppedDocuments.forEach(action((drop: Doc) => { + Doc.AddDocToList(Doc.GetProto(this.extensionDoc), "Alternates", drop); + e.stopPropagation(); })); - // de.data.removeDocument() bcz: need to implement } } -- cgit v1.2.3-70-g09d2 From 6f7936d5c71bf3c802d73f47b19abe96c6d61848 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 20 Sep 2019 15:11:30 -0400 Subject: simplified script execution api a little. fixed dataDoc() related stuff in various Box's. fixed some template stuff. --- src/client/util/Scripting.ts | 8 ++-- src/client/util/SelectionManager.ts | 4 ++ src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/ScriptingRepl.tsx | 20 ++++---- src/client/views/TemplateMenu.tsx | 11 ++++- .../views/collections/CollectionBaseView.tsx | 4 +- .../views/collections/CollectionSchemaCells.tsx | 10 ++-- src/client/views/collections/CollectionSubView.tsx | 40 ++++++---------- .../views/collections/CollectionTreeView.tsx | 13 +---- .../collectionFreeForm/CollectionFreeFormView.tsx | 56 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 14 ++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 29 +++++++---- src/client/views/nodes/DragBox.tsx | 8 ++-- src/client/views/nodes/FormattedTextBox.tsx | 7 ++- src/client/views/nodes/ImageBox.tsx | 6 +-- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 22 ++++----- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/pdf/PDFAnnotationLayer.scss | 6 --- src/client/views/pdf/PDFAnnotationLayer.tsx | 21 -------- src/client/views/pdf/PDFViewer.tsx | 17 ++----- src/debug/Repl.tsx | 8 +--- src/new_fields/Doc.ts | 6 +-- src/new_fields/ScriptField.ts | 5 +- 25 files changed, 136 insertions(+), 189 deletions(-) delete mode 100644 src/client/views/pdf/PDFAnnotationLayer.scss delete mode 100644 src/client/views/pdf/PDFAnnotationLayer.tsx (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 1d0916ac0..ff4451824 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -19,6 +19,7 @@ export interface ScriptSucccess { export interface ScriptError { success: false; error: any; + result: any; } export type ScriptResult = ScriptSucccess | ScriptError; @@ -27,7 +28,7 @@ export interface CompiledScript { readonly compiled: true; readonly originalScript: string; readonly options: Readonly; - run(args?: { [name: string]: any }): ScriptResult; + run(args?: { [name: string]: any }, onError?: (res: any) => void, errorVal?: any): ScriptResult; } export interface CompileError { @@ -100,7 +101,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an // let params: any[] = [Docs, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); let { capturedVariables = {} } = options; - let run = (args: { [name: string]: any } = {}): ScriptResult => { + let run = (args: { [name: string]: any } = {}, onError?: (e: any) => void, errorVal?: any): ScriptResult => { let argsArray: any[] = []; for (let name of customParams) { if (name === "this") { @@ -127,7 +128,8 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an if (batch) { batch.end(); } - return { success: false, error }; + onError && onError(error); + return { success: false, error, result: errorVal }; } }; return { compiled: true, run, originalScript, options }; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 9efef888d..4c97a1056 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -24,6 +24,10 @@ export namespace SelectionManager { manager.SelectedDocuments.push(docView); // console.log(manager.SelectedDocuments); docView.props.whenActiveChanged(true); + } else if (!ctrlPressed && manager.SelectedDocuments.length > 1) { + manager.SelectedDocuments.map(dv => dv !== docView && dv.props.whenActiveChanged(false)); + manager.SelectedDocuments = [docView]; + FormattedTextBox.InputBoxOverlay = undefined; } } @action diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 6c29a2dc7..b482e3298 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -339,7 +339,7 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], let templates: Map = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => - templates.set(template, this.props.views.reduce((checked, doc) => checked || (doc.props.Document["show" + template.Name] ? true : false), false as boolean))); + templates.set(template, this.props.views.reduce((checked, doc) => checked || doc.getLayoutPropStr("show" + template.Name) ? true : false, false as boolean))); return (
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index e05195ca0..1eb380e0b 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -135,19 +135,17 @@ export class ScriptingRepl extends React.Component { this.commands.push({ command: this.commandString, result: script.errors }); return; } - const result = script.run({ args: this.args }); - if (!result.success) { - this.commands.push({ command: this.commandString, result: result.error.toString() }); - return; - } - this.commands.push({ command: this.commandString, result: result.result }); - this.commandsHistory.push(this.commandString); + const result = script.run({ args: this.args }, e => this.commands.push({ command: this.commandString, result: e.toString() })); + if (result.success) { + this.commands.push({ command: this.commandString, result: result.result }); + this.commandsHistory.push(this.commandString); - this.maybeScrollToBottom(); + this.maybeScrollToBottom(); - this.commandString = ""; - this.commandBuffer = ""; - this.historyIndex = -1; + this.commandString = ""; + this.commandBuffer = ""; + this.historyIndex = -1; + } break; } case "ArrowUp": { diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index bfb8168e4..e4ef8313d 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -98,7 +98,14 @@ export class TemplateMenu extends React.Component { @undoBatch @action clearTemplates = (event: React.MouseEvent) => { - Templates.TemplateList.map(template => this.props.docs.map(d => d.Document["show" + template.Name] = undefined)); + Templates.TemplateList.forEach(template => this.props.docs.forEach(d => d.Document["show" + template.Name] = undefined)); + ["backgroundColor", "borderRounding", "width", "height"].forEach(field => this.props.docs.forEach(d => { + if (d.Document.isTemplate && d.props.DataDoc) { + d.Document[field] = undefined; + } else if (d.Document["default" + field[0].toUpperCase() + field.slice(1)] !== undefined) { + d.Document[field] = Doc.GetProto(d.Document)[field] = undefined; + } + })); } @action @@ -128,7 +135,7 @@ export class TemplateMenu extends React.Component {
this.toggleTemplateActivity()}>+
    {templateMenu} - {/* */} + {}
); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 0399371ff..56d12bd84 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -79,7 +79,7 @@ export class CollectionBaseView extends React.Component { } } - @computed get dataDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc ? this.props.DataDoc : this.props.Document : this.props.Document, this.props.fieldKey, this.props.fieldExt); } + @computed get dataDoc() { return Doc.fieldExtensionDoc(this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } @computed get dataField() { return this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; } active = (): boolean => { @@ -94,7 +94,7 @@ export class CollectionBaseView extends React.Component { this.props.whenActiveChanged(isActive); } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 0306d415c..4dac27e60 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -238,13 +238,11 @@ export class CollectionSchemaCell extends React.Component { return this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); }} OnFillDown={async (value: string) => { - let script = CompileScript(value, { requiredType: type, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - if (!script.compiled) { - return; + const script = CompileScript(value, { requiredType: type, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + if (script.compiled) { + DocListCast(this.props.Document[this.props.fieldKey]). + forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, script.run)); } - const run = script.run; - const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]); - val && val.forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, run)); }} />
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 804bfa2b2..774e6b1b9 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -40,6 +40,8 @@ export interface SubCollectionViewProps extends CollectionViewProps { export function CollectionSubView(schemaCtor: (doc: Doc) => T) { class CollectionSubView extends DocComponent(schemaCtor) { private dropDisposer?: DragManager.DragDropDisposer; + private _childLayoutDisposer?: IReactionDisposer; + protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer && this.dropDisposer(); if (ele) { @@ -50,8 +52,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this.createDropTarget(ele); } - _childLayoutDisposer?: IReactionDisposer; - componentDidMount() { this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)], async (args) => args[1] instanceof Doc && @@ -62,35 +62,25 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this._childLayoutDisposer && this._childLayoutDisposer(); } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } + // The data field for rendeing this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc. + // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through + // to its children which may be templates. + // The name of the data field comes from fieldExt if it's an extension, or fieldKey otherwise. + @computed get dataField() { + return Doc.fieldExtensionDoc(this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt)[this.props.fieldExt || this.props.fieldKey]; + } get childLayoutPairs() { return this.childDocs.map(cd => Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, cd)).filter(pair => pair.layout).map(pair => ({ layout: pair.layout!, data: pair.data! })); } - get childDocs() { - //TODO tfs: This might not be what we want? - //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) - let docs = DocListCast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); - let viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); - if (viewSpecScript) { - let script = viewSpecScript.script; - docs = docs.filter(d => { - let res = script.run({ doc: d }); - if (res.success) { - return res.result; - } - else { - console.log(res.error); - } - }); - } - return docs; - } get childDocList() { - //TODO tfs: This might not be what we want? - //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) - return Cast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc)); + return Cast(this.dataField, listSpec(Doc)); + } + get childDocs() { + let docs = DocListCast(this.dataField); + const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); + return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; } @action diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 08d87c7b2..e5313f68c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -425,18 +425,9 @@ class TreeView extends React.Component { preventTreeViewOpen: boolean, renderedIds: string[] ) { - let viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField); + const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField); if (viewSpecScript) { - let script = viewSpecScript.script; - docs = docs.filter(d => { - let res = script.run({ doc: d }); - if (res.success) { - return res.result; - } - else { - console.log(res.error); - } - }); + docs = docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } let ascending = Cast(containingCollection.sortAscending, "boolean", null); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7383c5551..36e62842c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -156,6 +156,7 @@ export namespace PivotView { y={pos.y} width={pos.width} height={pos.height} + transition={"transform 1s"} jitterRotation={NumCast(target.props.Document.jitterRotation)} {...target.getChildDocumentViewProps(doc)} />, @@ -183,11 +184,9 @@ const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSch export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _lastX: number = 0; private _lastY: number = 0; - private _inkKey = "ink"; // the document key used to store ink annotation strokes private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } - - get parentScaling() { + private get parentScaling() { return (this.props as any).ContentScaling && this.fitToBox && !this.isAnnotationOverlay ? (this.props as any).ContentScaling() : 1; } @@ -264,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } @computed get fieldExtensionDoc() { - return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); + return Doc.fieldExtensionDoc(this.props.DataDoc || this.props.Document, this.props.fieldKey); } intersectRect(r1: { left: number, top: number, width: number, height: number }, @@ -700,10 +699,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - getCalculatedPositions(script: ScriptField, params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, state?: any } { - const result = script.script.run(params); - return !result.success ? {} : result.result !== undefined ? result.result : - { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(params.doc.width, "number"), height: Cast(params.doc.height, "number") }; + getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, transition?: string, state?: any } { + const script = this.Document.arrangeScript; + const result = script && script.script.run(params, console.log); + if (result && result.success) { + return { ...result, transition: "transform 1s" }; + } + return { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(params.doc.width, "number"), height: Cast(params.doc.height, "number") }; } viewDefsToJSX = (views: any[]) => { @@ -745,12 +747,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (this.Document.usePivotLayout) return PivotView.elements(this); let curPage = FieldValue(this.Document.curPage, -1); const initScript = this.Document.arrangeInit; - const script = this.Document.arrangeScript; let state: any = undefined; let pairs = this.childLayoutPairs; let elements: ViewDefResult[] = []; if (initScript) { - const initResult = initScript.script.run({ docs: pairs.map(pair => pair.layout), collection: this.Document }); + const initResult = initScript.script.run({ docs: pairs.map(pair => pair.layout), collection: this.Document }, console.log); if (initResult.success) { const result = initResult.result; const { state: scriptState, views } = result; @@ -760,23 +761,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } let docviews = pairs.reduce((prev, pair) => { var page = NumCast(pair.layout.page, -1); - if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) { - let minim = BoolCast(pair.layout.isMinimized); - if (minim === undefined || !minim) { - const pos = script ? this.getCalculatedPositions(script, { doc: pair.layout, index: prev.length, collection: this.Document, docs: pairs.map(pair => pair.layout), state }) : - { x: Cast(pair.layout.x, "number"), y: Cast(pair.layout.y, "number"), z: Cast(pair.layout.z, "number"), width: Cast(pair.layout.width, "number"), height: Cast(pair.layout.height, "number") }; - state = pos.state === undefined ? state : pos.state; - if (pair.layout && !(pair.data instanceof Promise)) { - prev.push({ - ele: , - bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } - }); - } - } + if (!pair.layout.isMinimized && ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1)) { + const pos = this.getCalculatedPositions({ doc: pair.layout, index: prev.length, collection: this.Document, docs: pairs.map(pair => pair.layout), state }); + state = pos.state === undefined ? state : pos.state; + prev.push({ + ele: , + bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: pos.width || 0, height: pos.height || 0 } + }); } return prev; }, elements); @@ -838,7 +833,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } analyzeStrokes = async () => { - let data = Cast(this.fieldExtensionDoc[this._inkKey], InkField); + let data = Cast(this.fieldExtensionDoc.ink, InkField); if (data) { CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.fieldExtensionDoc, ["inkAnalysis", "handwriting"], data.inkData); } @@ -932,12 +927,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } render() { + // update the actual dimensions of the collection so that they can inquired (e.g., by a minimap) this.props.Document.fitX = this.actualContentBounds && this.actualContentBounds.x; this.props.Document.fitY = this.actualContentBounds && this.actualContentBounds.y; this.props.Document.fitW = this.actualContentBounds && (this.actualContentBounds.r - this.actualContentBounds.x); this.props.Document.fitH = this.actualContentBounds && (this.actualContentBounds.b - this.actualContentBounds.y); + // if fieldExt is set, then children will be stored in the extension document for the fieldKey. + // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document + Doc.UpdateDocumentExtensionForField(this.props.DataDoc || this.props.Document, this.props.fieldKey); const easing = () => this.props.Document.panTransformType === "Ease"; - Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); return (
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 18d0fea8c..bbea4a555 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -228,18 +228,14 @@ export class MarqueeView extends React.Component return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; } - get ink() { - let container = this.props.container.props.Document; - let containerKey = this.props.container.props.fieldKey; - let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true"); - return Cast(extensionDoc.ink, InkField); + get ink() { // ink will be stored on the extension doc for the field (fieldKey) where the container's data is stored. + let cprops = this.props.container.props; + return Cast(Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink, InkField); } set ink(value: InkField | undefined) { - let container = Doc.GetProto(this.props.container.props.Document); - let containerKey = this.props.container.props.fieldKey; - let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true"); - extensionDoc.ink = value; + let cprops = this.props.container.props; + Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink = value; } @undoBatch diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d05e39e2b..9685f9bca 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -17,6 +17,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { width?: number; height?: number; jitterRotation: number; + transition?: string; } export const positionSchema = createSchema({ zIndex: "number", @@ -98,7 +99,6 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else if (this.onClickHandler && this.onClickHandler.script) { - this.onClickHandler.script.run({ this: this.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }); + this.onClickHandler.script.run({ this: this.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log); } else if (this.Document.isButton) { SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered. this.buttonClick(e.altKey, e.ctrlKey); @@ -569,32 +569,45 @@ export class DocumentView extends DocComponent(Docu }); } + + // the document containing the view layout information - will be the Document itself unless the Document has + // a layout field. In that case, all layout information comes from there unless overriden by Document + get layoutDoc(): Document { + return Document(this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document); + } + + // does Document set a layout prop + setsLayoutProp = (prop: string) => this.props.Document[prop] !== this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)]; + // get the a layout prop by first choosing the prop from Document, then falling back to the layout doc otherwise. + getLayoutPropStr = (prop: string) => StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]); + getLayoutPropNum = (prop: string) => NumCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]); + isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; chromeHeight = () => { let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.Document.showTitle); - return (showTitle ? 25 : 0) + 1;// bcz: why 8?? + return (showTitle ? 25 : 0) + 1; } render() { const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined; const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; - const colorSet = this.Document.backgroundColor !== this.Document.defaultBackgroundColor; + const colorSet = this.setsLayoutProp("backgroundColor"); const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground; const backgroundColor = this.Document.isBackground || (clusterCol && !colorSet) ? - this.props.backgroundColor(this.Document) || StrCast(this.Document.backgroundColor) : - ruleColor && !colorSet ? ruleColor : StrCast(this.Document.backgroundColor) || this.props.backgroundColor(this.Document); + this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) : + ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document); const nativeWidth = this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; const nativeHeight = this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; - const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.Document.showTitle; - const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.Document.showCaption; + const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle"); + const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption"); const showTextTitle = showTitle && StrCast(this.Document.layout).indexOf("FormattedTextBox") !== -1 ? showTitle : undefined; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); - const borderRounding = this.Document.borderRounding || ruleRounding; + const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding; const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree; const searchHighlight = (!this.Document.searchFields ? (null) :
diff --git a/src/client/views/nodes/DragBox.tsx b/src/client/views/nodes/DragBox.tsx index 2d1a98df2..6c3db18c4 100644 --- a/src/client/views/nodes/DragBox.tsx +++ b/src/client/views/nodes/DragBox.tsx @@ -51,11 +51,9 @@ export class DragBox extends DocComponent(DragDocu const onDragStart = this.Document.onDragStart; e.stopPropagation(); e.preventDefault(); - let res = onDragStart ? onDragStart.script.run({ this: this.props.Document }) : undefined; - let doc = res !== undefined && res.success ? - res.result as Doc : - Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" }); - doc && DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY); + let res = onDragStart && onDragStart.script.run({ this: this.props.Document }).result; + let doc = (res as Doc) || Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" }); + DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY); } e.stopPropagation(); e.preventDefault(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 031929bbd..eb4718581 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -142,10 +142,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); } - - @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); } // this should be internal to prosemirror, but is needed // here to make sure that footnote view nodes in the overlay editor @@ -641,7 +640,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let annotations = DocListCast(region.annotations); annotations.forEach(anno => anno.target = this.props.Document); - let fieldExtDoc = Doc.resolvedFieldDataDoc(doc, "data", "true"); + let fieldExtDoc = Doc.fieldExtensionDoc(doc, "data"); let targetAnnotations = DocListCast(fieldExtDoc.annotations); if (targetAnnotations) { targetAnnotations.push(region); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3cb64aa40..624593245 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -63,9 +63,9 @@ export class ImageBox extends DocComponent(ImageD @observable private _isOpen: boolean = false; private dropDisposer?: DragManager.DragDropDisposer; + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } - @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } - + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); } protected createDropTarget = (ele: HTMLDivElement) => { if (this.dropDisposer) { @@ -81,8 +81,6 @@ export class ImageBox extends DocComponent(ImageD console.log("IMPLEMENT ME PLEASE"); } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "Alternates"); } - @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8fcd44f46..3a9318469 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -76,7 +76,7 @@ export class KeyValueBox extends React.Component { } else if (type === "script") { field = new ScriptField(script); } else { - let res = script.run({ this: target }); + let res = script.run({ this: target }, console.log); if (!res.success) return false; field = res.result; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index c8534ed0d..37bf6dbb7 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -31,11 +31,9 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _alt = false; @observable private _pdf: Opt; - @computed get containingCollectionDocument() { return this.props.ContainingCollectionDoc; } - @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } - - @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); } private _mainCont: React.RefObject = React.createRef(); private _reactionDisposer?: IReactionDisposer; @@ -96,7 +94,7 @@ export class PDFBox extends DocComponent(PdfDocumen @action setPanY = (y: number) => { - this.containingCollectionDocument && (this.containingCollectionDocument.panY = y); + this.props.ContainingCollectionDoc && (this.props.ContainingCollectionDoc.panY = y); } @action @@ -113,7 +111,7 @@ export class PDFBox extends DocComponent(PdfDocumen private resetFilters = () => { this._keyValue = this._valueValue = ""; - this._scriptValue = "return true"; + this._scriptValue = ""; this._keyRef.current && (this._keyRef.current.value = ""); this._valueRef.current && (this._valueRef.current.value = ""); this._scriptRef.current && (this._scriptRef.current.value = ""); @@ -127,7 +125,7 @@ export class PDFBox extends DocComponent(PdfDocumen return !this.props.active() ? (null) : (
e.stopPropagation()}>
  • +
  • ; @@ -520,12 +521,8 @@ export class MainView extends React.Component { /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ @computed get miscButtons() { - let logoutRef = React.createRef(); - return [ this.isSearchVisible ?
    : null, -
    -
    ]; } diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 0e7e0afa7..6f5abd05b 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -1,8 +1,5 @@ @import "../../views/globalCssVariables.scss"; -.collectiondockingview-content { - height: 100%; -} .lm_active .messageCounter{ color:white; background: #999999; @@ -21,7 +18,7 @@ .collectiondockingview-container { width: 100%; - height: 100%; + height:100%; border-style: solid; border-width: $COLLECTION_BORDER_WIDTH; position: absolute; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index b6bc4b4ba..b047e77a8 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -32,6 +32,7 @@ import React = require("react"); import { ButtonSelector } from './ParentDocumentSelector'; import { DocumentType } from '../../documents/DocumentTypes'; library.add(faFile); +const _global = (window /* browser */ || global /* node */) as any; @observer export class CollectionDockingView extends React.Component { @@ -534,12 +535,11 @@ interface DockedFrameProps { } @observer export class DockedFrameRenderer extends React.Component { - _mainCont: HTMLDivElement | undefined = undefined; + _mainCont: HTMLDivElement | null = null; @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; @observable private _dataDoc: Opt; - @observable private _isActive: boolean = false; get _stack(): any { @@ -577,6 +577,13 @@ export class DockedFrameRenderer extends React.Component { } componentDidMount() { + let observer = new _global.ResizeObserver(action((entries: any) => { + for (let entry of entries) { + this._panelWidth = entry.contentRect.width; + this._panelHeight = entry.contentRect.height; + } + })); + observer.observe(this.props.glContainer._element[0]); this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged); this.props.glContainer.on("tab", this.onActiveContentItemChanged); this.onActiveContentItemChanged(); @@ -595,15 +602,16 @@ export class DockedFrameRenderer extends React.Component { } } - panelWidth = () => this._document!.ignoreAspect ? this._panelWidth : Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth())); - panelHeight = () => this._document!.ignoreAspect ? this._panelHeight : Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), this.nativeHeight())); + panelWidth = () => this._document!.ignoreAspect || this._document!.fitWidth ? this._panelWidth : Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth())); + panelHeight = () => this._document!.ignoreAspect || this._document!.fitWidth ? this._panelHeight : Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), this.nativeHeight())); - nativeWidth = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeWidth) || this._panelWidth : 0; - nativeHeight = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeHeight) || this._panelHeight : 0; + nativeWidth = () => !this._document!.ignoreAspect && !this._document!.fitWidth ? NumCast(this._document!.nativeWidth) || this._panelWidth : 0; + nativeHeight = () => !this._document!.ignoreAspect && !this._document!.fitWidth ? NumCast(this._document!.nativeHeight) || this._panelHeight : 0; contentScaling = () => { if (this._document!.type === DocumentType.PDF) { - if (this._panelHeight / NumCast(this._document!.nativeHeight) > this._panelWidth / NumCast(this._document!.nativeWidth)) { + if ((this._document && this._document.fitWidth) || + this._panelHeight / NumCast(this._document!.nativeHeight) > this._panelWidth / NumCast(this._document!.nativeWidth)) { return this._panelWidth / NumCast(this._document!.nativeWidth); } else { return this._panelHeight / NumCast(this._document!.nativeHeight); @@ -639,13 +647,10 @@ export class DockedFrameRenderer extends React.Component { return CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc); } } - @computed get docView() { - if (!this._document) { - return (null); - } - let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc; - return { getScale={returnOne} />; } - @computed get content() { - return ( -
    { - this._mainCont = ref; - if (ref) { - this._panelWidth = Number(getComputedStyle(ref).width!.replace("px", "")); - this._panelHeight = Number(getComputedStyle(ref).height!.replace("px", "")); - } - })} - style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}> - {this.docView} -
    ); - } - render() { - if (!this._isActive || !this._document) return null; - let theContent = this.content; - return !this._document ? (null) : - { this._panelWidth = r.offset.width; this._panelHeight = r.offset.height; })}> - {({ measureRef }) =>
    - {theContent} -
    } -
    ; + return (!this._isActive || !this._document) ? (null) : + (
    this._mainCont = ref} + style={{ + transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`, + height: this._document && this._document.fitWidth ? undefined : "100%" + }}> + {this.docView(this._document)} +
    ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 721732774..4b260d111 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -401,27 +401,34 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } } SelectionManager.DeselectAll(); - const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2; - const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2; - const newState = HistoryUtil.getState(); - newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; - HistoryUtil.pushState(newState); - - let savedState = { px: this.Document.panX, py: this.Document.panY, s: this.Document.scale, pt: this.Document.panTransformType }; - - this.setPan(newPanX, newPanY); - this.Document.panTransformType = "Ease"; - this.props.focus(this.props.Document); - willZoom && this.setScaleToZoom(doc, scale); - - afterFocus && setTimeout(() => { - if (afterFocus && afterFocus()) { - this.Document.panX = savedState.px; - this.Document.panY = savedState.py; - this.Document.scale = savedState.s; - this.Document.panTransformType = savedState.pt; - } - }, 1000); + if (this.props.Document.scrollHeight) { + let annotOn = Cast(doc.annotationOn, Doc) as Doc; + let offset = annotOn && (NumCast(annotOn.height) / 2); + this.props.Document.scrollY = NumCast(doc.y) - offset; + } else { + const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2; + const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2; + const newState = HistoryUtil.getState(); + newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; + HistoryUtil.pushState(newState); + + let savedState = { px: this.Document.panX, py: this.Document.panY, s: this.Document.scale, pt: this.Document.panTransformType }; + + this.setPan(newPanX, newPanY); + this.Document.panTransformType = "Ease"; + this.props.focus(this.props.Document); + willZoom && this.setScaleToZoom(doc, scale); + + afterFocus && setTimeout(() => { + if (afterFocus && afterFocus()) { + this.Document.panX = savedState.px; + this.Document.panY = savedState.py; + this.Document.scale = savedState.s; + this.Document.panTransformType = savedState.pt; + } + }, 1000); + } + } setScaleToZoom = (doc: Doc, scale: number = 0.5) => { @@ -449,7 +456,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { PanelHeight: childLayout[HeightSym], ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, - ContainingCollectionDoc: this.props.ContainingCollectionDoc, + ContainingCollectionDoc: this.props.Document, focus: this.focusDocument, backgroundColor: this.getClusterColor, parentActive: this.props.active, diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 44611869e..82193aefa 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -188,16 +188,13 @@ export class MarqueeView extends React.Component @action onPointerUp = (e: PointerEvent): void => { if (!this.props.container.props.active()) this.props.selectDocuments([this.props.container.props.Document]); - // console.log("pointer up!"); if (this._visible) { - // console.log("visible"); let mselect = this.marqueeSelect(); if (!e.shiftKey) { SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document); } this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } - //console.log("invisible"); this.cleanupInteractions(true); if (e.altKey) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c3d2c9e51..c4fed200f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -77,7 +77,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { let ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; - let ld = this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout as Doc : undefined; + let ld = this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout : undefined; let br = StrCast((ld || this.props.Document).borderRounding); br = !br && ruleRounding ? ruleRounding : br; if (br.endsWith("%")) { @@ -100,7 +100,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.dataProvider ? this.dataProvider.width : this.panelWidth(); + finalPanelWidth = () => this.dataProvider ? this.dataProvider.width : this.panelWidth(); finalPanelHeight = () => this.dataProvider ? this.dataProvider.height : this.panelHeight(); render() { @@ -124,7 +124,7 @@ export class CollectionFreeFormDocumentView extends DocComponent
    diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6ee88f834..bd702c6a2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -223,15 +223,18 @@ export class DocumentView extends DocComponent(Docu else if (linkedDocs.length) { SelectionManager.DeselectAll(); let first = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor1 as Doc, this.props.Document) && !d.anchor1anchored); + let second = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor2 as Doc, this.props.Document) && !d.anchor2anchored); let firstUnshown = first.filter(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0); + let secondUnshown = second.filter(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0); if (firstUnshown.length) first = [firstUnshown[0]]; - let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : [expandedDocs[0], expandedDocs[0]]; + if (secondUnshown.length) second = [secondUnshown[0]]; + let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : second.length ? [second[0].anchor1 as Doc, second[0].anchor1 as Doc] : undefined; // @TODO: shouldn't always follow target context let linkedFwdContextDocs = [first.length ? await (first[0].targetContext) as Doc : undefined, undefined]; let linkedFwdPage = [first.length ? NumCast(first[0].anchor2Page, undefined) : undefined, undefined]; - if (!linkedFwdDocs.some(l => l instanceof Promise)) { + if (linkedFwdDocs && !linkedFwdDocs.some(l => l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab"); let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionDoc) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined; DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, @@ -601,7 +604,7 @@ export class DocumentView extends DocComponent(Docu ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document); const nativeWidth = this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; - const nativeHeight = this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : nativeWidth !== "100%" ? nativeWidth : "100%"; + const nativeHeight = this.Document.ignoreAspect || this.props.Document.fitWidth ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : nativeWidth !== "100%" ? nativeWidth : "100%"; const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle"); const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption"); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 923dd1544..565fb0505 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -815,6 +815,40 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); } + let ctrlKey = e.ctrlKey; + if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { + e.preventDefault(); + } + } + + onPointerUp = (e: React.PointerEvent): void => { + FormattedTextBoxComment.textBox = this; + if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { + e.stopPropagation(); + } + } + + @action + onFocused = (e: React.FocusEvent): void => { + document.removeEventListener("keypress", this.recordKeyHandler); + document.addEventListener("keypress", this.recordKeyHandler); + this.tryUpdateHeight(); + if (!this.props.isOverlay) { + FormattedTextBox.InputBoxOverlay = this; + } else { + if (this._ref.current) { + this._ref.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; + } + } + } + onPointerWheel = (e: React.WheelEvent): void => { + // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time + if (this.props.isSelected() || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { + e.stopPropagation(); + } + } + + onClick = (e: React.MouseEvent): void => { let ctrlKey = e.ctrlKey; if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) { let href = (e.target as any).href; @@ -829,8 +863,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); if (node) { let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link); - href = link && link.attrs.href; - location = link && link.attrs.location; + if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above). + href = link && link.attrs.href; + location = link && link.attrs.location; + } } if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { @@ -848,7 +884,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return; } } - if (targetContext) { + if (targetContext && (!jumpToDoc || targetContext !== await jumpToDoc.annotationOn)) { DocumentManager.Instance.jumpToDocument(targetContext, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); } else if (jumpToDoc) { DocumentManager.Instance.jumpToDocument(jumpToDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); @@ -870,39 +906,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { - e.preventDefault(); - } - } - - onPointerUp = (e: React.PointerEvent): void => { - FormattedTextBoxComment.textBox = this; - if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { - e.stopPropagation(); - } - } - - @action - onFocused = (e: React.FocusEvent): void => { - document.removeEventListener("keypress", this.recordKeyHandler); - document.addEventListener("keypress", this.recordKeyHandler); - this.tryUpdateHeight(); - if (!this.props.isOverlay) { - FormattedTextBox.InputBoxOverlay = this; - } else { - if (this._ref.current) { - this._ref.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; - } - } - } - onPointerWheel = (e: React.WheelEvent): void => { - // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time - if (this.props.isSelected() || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { - e.stopPropagation(); - } - } - - onClick = (e: React.MouseEvent): void => { // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. if (this.props.isSelected() && e.nativeEvent.offsetX < 40) { let pos = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 624593245..004f50590 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -38,6 +38,7 @@ library.add(faFileAudio, faAsterisk); export const pageSchema = createSchema({ curPage: "number", + fitWidth: "boolean" }); interface Window { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 0fcbaaa7c..fe71e76fd 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -20,6 +20,9 @@ import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); import { undoBatch } from '../../util/UndoManager'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { ContextMenu } from '../ContextMenu'; +import { Utils } from '../../../Utils'; type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @@ -58,7 +61,7 @@ export class PDFBox extends DocComponent(PdfDocumen this.Document.nativeWidth = nw * 96 / 72; this.Document.nativeHeight = this.Document.nativeHeight ? nw * 96 / 72 * oldaspect : nh * 96 / 72; } - this.Document.height = this.Document[WidthSym]() * (nh / nw); + !this.Document.fitWidth && !this.Document.ignoreAspect && (this.Document.height = this.Document[WidthSym]() * (nh / nw)); } public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); } @@ -165,14 +168,23 @@ export class PDFBox extends DocComponent(PdfDocumen
    ); } + specificContextMenu = (e: React.MouseEvent): void => { + const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); + let funcs: ContextMenuProps[] = []; + pdfUrl && funcs.push({ description: "Copy path", event: () => Utils.CopyText(pdfUrl.url.pathname), icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Fit Width " + (this.Document.fitWidth ? "Off" : "On"), event: () => this.Document.fitWidth = !this.Document.fitWidth, icon: "expand-arrows-alt" }); + + ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); + } + render() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); let classname = "pdfBox-cont" + (InkingControl.Instance.selectedTool || !this.active ? "" : "-interactive"); return (!(pdfUrl instanceof PdfField) || !this._pdf ?
    {`pdf, ${this.dataDoc[this.props.fieldKey]}, not found`}
    : -
    { +
    { let hit = document.elementFromPoint(e.clientX, e.clientY); - if (hit && hit.localName === "span" && this.props.isSelected()) { + if (hit && hit.localName === "span" && this.props.isSelected()) { // drag selecting text stops propagation e.button === 0 && e.stopPropagation(); } }}> @@ -182,7 +194,7 @@ export class PDFBox extends DocComponent(PdfDocumen Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling} addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} pinToPres={this.props.pinToPres} addDocument={this.props.addDocument} - ScreenToLocalTransform={this.props.ScreenToLocalTransform} + ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select} isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged} fieldKey={this.props.fieldKey} fieldExtensionDoc={this.extensionDoc} /> {this.settingsPanel()} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 5ad4ffd48..13fd8ea98 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -9,14 +9,12 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, returnOne, Utils } from "../../../Utils"; +import smoothScroll, { Utils, emptyFunction, returnOne } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { CompiledScript, CompileScript } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; -import Annotation from "./Annotation"; import PDFMenu from "./PDFMenu"; import "./PDFViewer.scss"; import React = require("react"); @@ -24,7 +22,8 @@ import * as rp from "request-promise"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; -import { SelectionManager } from "../../util/SelectionManager"; +import Annotation from "./Annotation"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const pdfjsLib = require("pdfjs-dist"); @@ -41,6 +40,7 @@ interface IViewerProps { PanelWidth: () => number; PanelHeight: () => number; ContentScaling: () => number; + select: (isCtrlPressed: boolean) => void; renderDepth: number; isSelected: () => boolean; loaded: (nw: number, nh: number, np: number) => void; @@ -106,11 +106,20 @@ export class PDFViewer extends React.Component { // file address of the pdf this._coverPath = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${this.props.url.substring("files/".length, this.props.url.length - ".pdf".length)}-${NumCast(this.props.Document.curPage, 1)}.PNG`))); runInAction(() => this._showWaiting = this._showCover = true); - this._selectionReactionDisposer = reaction(() => this.props.isSelected(), () => { - this.setupPdfJsViewer(); - this._selectionReactionDisposer && this._selectionReactionDisposer(); - this._selectionReactionDisposer = undefined; - }) + this._selectionReactionDisposer = reaction(() => this.props.isSelected(), () => this.setupPdfJsViewer()); + this._reactionDisposer = reaction( + () => this.props.Document.scrollY, + (scrollY) => { + if (scrollY !== undefined) { + if (this._showCover || this._showWaiting) { + this.setupPdfJsViewer(); + } + this._mainCont.current && smoothScroll(1000, this._mainCont.current, NumCast(this.props.Document.scrollY) || 0); + this.props.Document.scrollY = undefined; + } + }, + { fireImmediately: true } + ); } componentWillUnmount = () => { @@ -153,12 +162,14 @@ export class PDFViewer extends React.Component { i === this.props.pdf.numPages - 1 && this.props.loaded((page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]), (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]), i); })))); - Doc.GetProto(this.props.Document).scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0); + Doc.GetProto(this.props.Document).scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0) * 96 / 72; } } @action setupPdfJsViewer = async () => { + this._selectionReactionDisposer && this._selectionReactionDisposer(); + this._selectionReactionDisposer = undefined; this._showWaiting = true; this.props.setPdfViewer(this); await this.initialLoad(); @@ -180,10 +191,6 @@ export class PDFViewer extends React.Component { }), { fireImmediately: true } ); - this._reactionDisposer = reaction( - () => this.props.Document.panY, - () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.props.Document.panY) || 0, behavior: "auto" }) - ); document.removeEventListener("copy", this.copy); document.addEventListener("copy", this.copy); @@ -228,10 +235,9 @@ export class PDFViewer extends React.Component { annoDocs.push(annoDoc); annoDoc.isButton = true; anno.remove(); - // this.props.addDocument && this.props.addDocument(annoDoc, false); mainAnnoDoc = annoDoc; + mainAnnoDocProto = Doc.GetProto(mainAnnoDoc); mainAnnoDocProto.y = annoDoc.y; - mainAnnoDocProto = Doc.GetProto(annoDoc); } else { this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => value.map(anno => { let annoDoc = new Doc(); @@ -381,7 +387,7 @@ export class PDFViewer extends React.Component { this._downX = e.clientX; this._downY = e.clientY; if (NumCast(this.props.Document.scale, 1) !== 1) return; - if (e.button !== 0 && this.active()) { + if ((e.button !== 0 || e.altKey) && this.active()) { this._setPreviewCursor && this._setPreviewCursor(e.clientX, e.clientY, true); } this._marqueeing = false; @@ -638,18 +644,15 @@ export class PDFViewer extends React.Component { } @computed get annotationLayer() { - trace(); return
    {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) => )}
    ; } @computed get pdfViewerDiv() { - trace(); return
    ; } @computed get standinViews() { - trace(); return <> {this._showCover ? this.getCoverImage() : (null)} {this._showWaiting ? : (null)} @@ -710,7 +713,7 @@ class PdfViewerMarquee extends React.Component { width: `${this.props.width()}px`, height: `${this.props.height()}px`, border: `${this.props.width() === 0 ? "" : "2px dashed black"}` }}> -
    +
    ; } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 1b3c8b0b0..79b73aba8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -344,7 +344,7 @@ export namespace Doc { let list = Cast(target[key], listSpec(Doc)); if (list) { if (allowDuplicates !== true) { - let pind = list.reduce((l, d, i) => d instanceof Doc && Doc.AreProtosEqual(d, doc) ? i : l, -1); + let pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1); if (pind !== -1) { list.splice(pind, 1); } -- cgit v1.2.3-70-g09d2 From 53685a27139886c1df74840cc9f451c046a32de6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 4 Oct 2019 01:50:57 -0400 Subject: got rid of MainOverlayTextBox! fixed some things with embedding docs in text --- src/client/util/RichTextSchema.tsx | 4 +- src/client/views/InkingControl.tsx | 3 +- src/client/views/MainOverlayTextBox.scss | 29 ---- src/client/views/MainOverlayTextBox.tsx | 156 --------------------- src/client/views/MainView.tsx | 5 +- .../collectionFreeForm/CollectionFreeFormView.scss | 6 - .../collectionFreeForm/MarqueeView.scss | 7 + .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- src/client/views/nodes/FormattedTextBox.scss | 7 +- src/client/views/nodes/FormattedTextBox.tsx | 52 ++----- 10 files changed, 31 insertions(+), 242 deletions(-) delete mode 100644 src/client/views/MainOverlayTextBox.scss delete mode 100644 src/client/views/MainOverlayTextBox.tsx (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 7be773475..12cf40b32 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -720,8 +720,8 @@ export class DashDocView { this._outer.style.overflow = "hidden"; (this._outer.style as any).float = node.attrs.float; - this._dashSpan.style.width = "100%"; - this._dashSpan.style.height = "100%"; + this._dashSpan.style.width = node.attrs.width; + this._dashSpan.style.height = node.attrs.height; this._dashSpan.style.position = "absolute"; this._dashSpan.style.display = "inline-block" this._handle.style.position = "absolute"; diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index a10df0e75..ee8b77050 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -10,7 +10,6 @@ import { InkTool } from "../../new_fields/InkField"; import { Doc } from "../../new_fields/Doc"; import { undoBatch, UndoManager } from "../util/UndoManager"; import { StrCast, NumCast, Cast } from "../../new_fields/Types"; -import { MainOverlayTextBox } from "./MainOverlayTextBox"; import { listSpec } from "../../new_fields/Schema"; import { List } from "../../new_fields/List"; import { Utils } from "../../Utils"; @@ -46,7 +45,7 @@ export class InkingControl extends React.Component { switchColor = action((color: ColorResult): void => { this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); if (InkingControl.Instance.selectedTool === InkTool.None) { - if (MainOverlayTextBox.Instance.SetColor(color.hex)) return; + // if (MainOverlayTextBox.Instance.SetColor(color.hex)) return; let selected = SelectionManager.SelectedDocuments(); let oldColors = selected.map(view => { let targetDoc = view.props.Document.layout instanceof Doc ? view.props.Document.layout : view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss deleted file mode 100644 index c9d44e194..000000000 --- a/src/client/views/MainOverlayTextBox.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import "globalCssVariables"; - -.mainOverlayTextBox-textInput { - background-color: rgba(248, 6, 6, 0.001); - width: 400px; - height: 200px; - position: absolute; - overflow: visible; - top: 0; - left: 0; - pointer-events: none; - z-index: $mainTextInput-zindex; - - .formattedTextBox-cont { - background-color: rgba(248, 6, 6, 0.001); - width: 100%; - height: 100%; - position: absolute; - top: 0; - left: 0; - } -} - -.mainOverlayTextBox-unscaled_div { - // width: 0px; - z-index: 10000; - position: absolute; - pointer-events: none; -} \ No newline at end of file diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx deleted file mode 100644 index 73eef9478..000000000 --- a/src/client/views/MainOverlayTextBox.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { action, observable, reaction, trace } from 'mobx'; -import { observer } from 'mobx-react'; -import "normalize.css"; -import * as React from 'react'; -import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; -import { BoolCast } from '../../new_fields/Types'; -import { emptyFunction, returnTrue, returnZero, Utils, returnOne } from '../../Utils'; -import { DragManager } from '../util/DragManager'; -import { Transform } from '../util/Transform'; -import { CollectionDockingView } from './collections/CollectionDockingView'; -import "./MainOverlayTextBox.scss"; -import { FormattedTextBox } from './nodes/FormattedTextBox'; - -interface MainOverlayTextBoxProps { - firstinstance?: boolean; -} - -@observer -export class MainOverlayTextBox extends React.Component { - public static Instance: MainOverlayTextBox; - @observable _textXf: () => Transform = () => Transform.Identity(); - public TextFieldKey: string = "data"; - private _textColor: string | null = null; - private _textHideOnLeave?: boolean; - private _textTargetDiv: HTMLDivElement | undefined; - private _textProxyDiv: React.RefObject; - private _textBottom: boolean | undefined; - private _setouterdiv = (outerdiv: HTMLElement | null) => { this._outerdiv = outerdiv; this.updateTooltip(); }; - private _outerdiv: HTMLElement | null = null; - private _textBox: FormattedTextBox | undefined; - private _tooltip?: HTMLElement; - ChromeHeight?: () => number; - @observable public TextDoc?: Doc; - @observable public TextDataDoc?: Doc; - - updateTooltip = () => { - this._outerdiv && this._tooltip && !this._outerdiv.contains(this._tooltip) && this._outerdiv.appendChild(this._tooltip); - } - - public SetColor(color: string) { - return this._textBox && this._textBox.setFontColor(color); - } - - constructor(props: MainOverlayTextBoxProps) { - super(props); - this._textProxyDiv = React.createRef(); - MainOverlayTextBox.Instance = this; - reaction(() => FormattedTextBox.InputBoxOverlay, - (box?: FormattedTextBox) => { - this._textBox = box; - if (box) { - this.ChromeHeight = box.props.ChromeHeight; - this.TextDoc = box.props.Document; - this.TextDataDoc = box.props.DataDoc; - let xf = () => { - box.props.ScreenToLocalTransform(); - let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined); - return new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale); - }; - this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight) || box.props.height === "min-content"); - } - else { - this.TextDoc = undefined; - this.TextDataDoc = undefined; - this.setTextDoc(); - } - }); - } - - @action - private setTextDoc(textFieldKey?: string, div?: HTMLDivElement, tx?: () => Transform, autoHeight?: boolean) { - if (this._textTargetDiv) { - this._textTargetDiv.style.color = this._textColor; - } - this.TextFieldKey = textFieldKey!; - let txf = tx ? tx : () => Transform.Identity(); - this._textXf = txf; - this._textTargetDiv = div; - this._textHideOnLeave = FormattedTextBox.InputBoxOverlay && FormattedTextBox.InputBoxOverlay.props.hideOnLeave; - if (div) { - let parTop = div.parentElement && getComputedStyle(div.parentElement).top; - this._textBottom = parTop && parTop !== "0px" && parTop != "auto" ? true : false; - this._textColor = (getComputedStyle(div) as any).color; - div.style.color = "transparent"; - } - } - - @action - textScroll = (e: React.UIEvent) => { - if (this._textProxyDiv.current && this._textTargetDiv) { - this._textTargetDiv.scrollTop = (e as any)._targetInst.stateNode.scrollTop; - } - } - - textBoxDown = (e: React.PointerEvent) => { - if (e.button !== 0 || e.metaKey || e.altKey) { - document.addEventListener("pointermove", this.textBoxMove); - document.addEventListener('pointerup', this.textBoxUp); - } - } - @action - textBoxMove = (e: PointerEvent) => { - if ((e.movementX > 1 || e.movementY > 1) && FormattedTextBox.InputBoxOverlay) { - document.removeEventListener("pointermove", this.textBoxMove); - document.removeEventListener('pointerup', this.textBoxUp); - let dragData = new DragManager.DocumentDragData([FormattedTextBox.InputBoxOverlay.props.Document]); - const [left, top] = this._textXf().inverse().transformPoint(0, 0); - dragData.offset = [e.clientX - left, e.clientY - top]; - DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, { - handlers: { - dragComplete: action(emptyFunction), - }, - hideSource: false - }); - } - } - textBoxUp = (e: PointerEvent) => { - document.removeEventListener("pointermove", this.textBoxMove); - document.removeEventListener('pointerup', this.textBoxUp); - } - - addDocTab = (doc: Doc, dataDoc: Opt, location: string) => { - return this._textBox && this._textBox.props.addDocTab(doc, dataDoc, location) ? true : false; - } - render() { - this.TextDoc; this.TextDataDoc; - if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) { - let wid = FormattedTextBox.InputBoxOverlay.props.Document.width; // need to force overlay to render when underlying text box is resized (eg, w/ DocDecorations) - let hgtx = FormattedTextBox.InputBoxOverlay.props.Document.height; // need to force overlay to render when underlying text box is resized (eg, w/ DocDecorations) - let textRect = this._textTargetDiv.getBoundingClientRect(); - let s = this._textXf().Scale; - let location = this._textBottom ? textRect.bottom : textRect.top; - let hgt = (this._textBox && this._textBox.props.Document.autoHeight) || this._textBottom ? "auto" : this._textTargetDiv.clientHeight; - return
    -
    -
    -
    - { this._tooltip = tooltip; this.updateTooltip(); }} /> -
    -
    -
    - ; - } - else return (null); - } -} \ No newline at end of file diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 660b42290..545f99a41 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -34,14 +34,12 @@ import { DocumentDecorations } from './DocumentDecorations'; import KeyManager from './GlobalKeyHandler'; import { InkingControl } from './InkingControl'; import "./Main.scss"; -import { MainOverlayTextBox } from './MainOverlayTextBox'; import MainViewModal from './MainViewModal'; import { DocumentView } from './nodes/DocumentView'; -import { PresBox } from './nodes/PresBox'; -import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { FilterBox } from './search/FilterBox'; +import { OverlayView } from './OverlayView'; @observer export class MainView extends React.Component { @@ -687,7 +685,6 @@ export class MainView extends React.Component { {this.nodesMenu()} {this.miscButtons} -
    ); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index c4311fa52..bb1a12f88 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -46,12 +46,6 @@ border-radius: inherit; box-sizing: border-box; position: absolute; - overflow: hidden; - - .marqueeView { - overflow: hidden; - } - top: 0; left: 0; width: 100%; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 9fc2e44fb..7dc54ea79 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -6,6 +6,13 @@ width:100%; height:100%; } +.marqueeView { + overflow: hidden; +} + +.marqueeView:focus-within { + overflow: visible; +} .marquee { border-style: dashed; box-sizing: border-box; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 82193aefa..bf154d37d 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -442,8 +442,8 @@ export class MarqueeView extends React.Component render() { let p: [number, number] = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0]; - return
    -
    + return
    e.currentTarget.scrollLeft = 0} style={{ borderRadius: "inherit" }} onClick={this.onClick} onPointerDown={this.onPointerDown}> +
    e.currentTarget.scrollLeft = 0} > {this._visible ? this.marqueeDiv : null}
    {this.props.children} diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 45e516015..541c29faa 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -28,7 +28,7 @@ } .formattedTextBox-cont-hidden { - pointer-events: none; + // pointer-events: none; } .formattedTextBox-inner-rounded { @@ -40,9 +40,10 @@ left: 10%; } -.formattedTextBox-inner-rounded div, -.formattedTextBox-inner div { +.formattedTextBox-inner-rounded , +.formattedTextBox-inner { padding: 10px 10px; + height: 100%; } .menuicon { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 819accf20..13eb78f48 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -46,7 +46,6 @@ library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); export interface FormattedTextBoxProps { - isOverlay?: boolean; hideOnLeave?: boolean; height?: string; color?: string; @@ -95,9 +94,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @observable private _fontFamily = "Arial"; @observable private _fontAlign = ""; @observable private _entered = false; - @observable public static InputBoxOverlay?: FormattedTextBox = undefined; public static SelectOnLoad = ""; - public static InputBoxOverlayScroll: number = 0; public static IsFragment(html: string) { return html.indexOf("data-pm-slice") !== -1; } @@ -137,9 +134,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe constructor(props: FieldViewProps) { super(props); - if (this.props.isOverlay) { - DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined); - } FormattedTextBox.Instance = this; } @@ -300,8 +294,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe node = model.create({ src: url, docid: link[Id] }) } else { node = schema.nodes.dashDoc.create({ - width: this.props.Document[WidthSym](), height: this.props.Document[HeightSym](), - title: "dashDoc", docid: target[Id] + width: target[WidthSym](), height: target[HeightSym](), + title: "dashDoc", docid: target[Id], + float: "none" }); } let pos = this._editorView!.posAtCoords({ left: de.x, top: de.y }); @@ -390,7 +385,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe (schema as any).Document = this.props.Document; return { schema, - plugins: this.props.isOverlay ? [ + plugins: [ inputRules(inpRules), this.tooltipTextMenuPlugin(), history(), @@ -403,26 +398,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } }), formattedTextBoxCommentPlugin - ] : [ - history(), - keymap(this._keymap), - keymap(baseKeymap), - ] + ] }; } componentDidMount() { - - if (!this.props.isOverlay) { - this._proxyReactionDisposer = reaction(() => this.props.isSelected(), - () => { - if (this.props.isSelected()) { - FormattedTextBox.InputBoxOverlay = this; - FormattedTextBox.InputBoxOverlayScroll = this._ref.current!.scrollTop; - } - }, { fireImmediately: true }); - } - this.pullFromGoogleDoc(this.checkState); this.dataDoc[GoogleRef] && this.dataDoc.unchanged && runInAction(() => DocumentDecorations.Instance.isAnimatingFetch = true); @@ -551,7 +531,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let editor = this._editorView; let ret = findLinkFrag(editor.state.doc.content, editor); - if (ret.frag.size > 2 && ((!this.props.isOverlay && !this.props.isSelected()) || (this.props.isSelected() && this.props.isOverlay))) { + if (ret.frag.size > 2) { let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start if (ret.frag.firstChild) { selection = TextSelection.between(editor.state.doc.resolve(ret.start + 2), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected @@ -754,7 +734,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe clipboardTextSerializer: this.clipboardTextSerializer, handlePaste: this.handlePaste, }); - (this._editorView as any).isOverlay = this.props.isOverlay; if (startup) { Doc.GetProto(doc).documentText = undefined; this._editorView.dispatch(this._editorView.state.tr.insertText(startup)); @@ -766,7 +745,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe FormattedTextBox.SelectOnLoad = ""; this.props.select(false); } - else if (this.props.isOverlay) this._editorView!.focus(); + this._editorView!.focus(); // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet. this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: timenow() })]; } @@ -824,13 +803,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe document.removeEventListener("keypress", this.recordKeyHandler); document.addEventListener("keypress", this.recordKeyHandler); this.tryUpdateHeight(); - if (!this.props.isOverlay) { - FormattedTextBox.InputBoxOverlay = this; - } else { - if (this._ref.current) { - this._ref.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; - } - } } onPointerWheel = (e: React.WheelEvent): void => { // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time @@ -901,7 +873,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } } - this._proseRef!.focus(); + let pos = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); + if (pos && pos.pos > 0) { + this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new TextSelection(this._editorView!.state.doc.resolve(pos.pos)))); + } + this._editorView!.focus(); if (this._linkClicked) { this._linkClicked = ""; e.preventDefault(); @@ -959,7 +935,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe tryUpdateHeight() { const ChromeHeight = this.props.ChromeHeight; let sh = this._ref.current ? this._ref.current.scrollHeight : 0; - if (!this.props.isOverlay && !this.props.Document.isAnimating && this.props.Document.autoHeight && sh !== 0) { + if (!this.props.Document.isAnimating && this.props.Document.autoHeight && sh !== 0) { let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0); let dh = NumCast(this.props.Document.height, 0); this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0)); @@ -968,7 +944,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } render() { - let style = this.props.isOverlay ? "scroll" : "hidden"; + let style = "hidden"; let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : ""; let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.props.Document.isBackground ? "none" : "all"; -- cgit v1.2.3-70-g09d2 From f9916faa215297d434aab2357b98d2c4b1fdcb92 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 5 Oct 2019 13:02:43 -0400 Subject: started cleaning up videos. restored link follwing to timecodes. changed to currentTimecode from curPage --- src/client/documents/Documents.ts | 11 +++-- src/client/util/DictationManager.ts | 1 - src/client/util/DocumentManager.ts | 7 ++- src/client/views/InkingCanvas.tsx | 6 +-- .../views/collections/CollectionBaseView.tsx | 4 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionVideoView.tsx | 6 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/linking/LinkFollowBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 6 +-- src/client/views/nodes/VideoBox.tsx | 57 ++++++++++++---------- src/new_fields/InkField.ts | 2 +- 13 files changed, 58 insertions(+), 50 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 71b9038d4..98f56af01 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -74,6 +74,7 @@ export interface DocumentOptions { backgroundLayout?: string; chromeStatus?: string; curPage?: number; + currentTimecode?: number; documentText?: string; borderRounding?: string; schemaColumns?: List; @@ -120,7 +121,7 @@ export namespace Docs { }], [DocumentType.IMG, { layout: { view: ImageBox, collectionView: [CollectionView, data, anno] as CollectionViewType }, - options: { curPage: 0 } + options: {} }], [DocumentType.WEB, { layout: { view: WebBox, collectionView: [CollectionView, data, anno] as CollectionViewType }, @@ -136,7 +137,7 @@ export namespace Docs { }], [DocumentType.VID, { layout: { view: VideoBox, collectionView: [CollectionVideoView, data, anno] as CollectionViewType }, - options: { curPage: 0 }, + options: { currentTimecode: 0 }, }], [DocumentType.AUDIO, { layout: { view: AudioBox }, @@ -662,15 +663,17 @@ export namespace DocUtils { UndoManager.RunInBatch(() => { linkDocProto.type = DocumentType.LINK; - linkDocProto.targetContext = target.ctx; - linkDocProto.sourceContext = source.ctx; linkDocProto.title = title === "" ? source.doc.title + " to " + target.doc.title : title; linkDocProto.linkDescription = description; linkDocProto.anchor1 = source.doc; + linkDocProto.anchor1Context = source.ctx; + linkDocProto.anchor1Timecode = source.doc.currentTimecode; linkDocProto.anchor1Groups = new List([]); linkDocProto.anchor2 = target.doc; + linkDocProto.anchor2Context = target.ctx; linkDocProto.anchor2Groups = new List([]); + linkDocProto.anchor2Timecode = target.doc.currentTimecode; LinkManager.Instance.addLink(linkDocProto); diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index cebb56bbe..3b2307073 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -336,7 +336,6 @@ export namespace DictationManager { let newBox = Docs.Create.TextDocument({ width: 400, height: 200, title: "My Outline" }); newBox.autoHeight = true; let proto = newBox.proto!; - proto.page = -1; let prompt = "Press alt + r to start dictating here..."; let head = 3; let anchor = head + prompt.length; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 6fe97edbb..83a69465f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, trace } from 'mobx'; import { Doc, DocListCastAsync } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; import { Cast, NumCast, StrCast } from '../../new_fields/Types'; @@ -196,10 +196,13 @@ export class DocumentManager { const second = secondDocWithoutView ? [secondDocWithoutView] : secondDocs; const linkDoc = first.length ? first[0] : second.length ? second[0] : undefined; const linkFollowDocs = first.length ? [await first[0].anchor2 as Doc, await first[0].anchor1 as Doc] : second.length ? [await second[0].anchor1 as Doc, await second[0].anchor2 as Doc] : undefined; - const linkFollowDocContexts = first.length ? [await first[0].targetContext as Doc, await first[0].sourceContext as Doc] : second.length ? [await second[0].sourceContext as Doc, await second[0].targetContext as Doc] : [undefined, undefined]; + const linkFollowDocContexts = first.length ? [await first[0].anchor2Context as Doc, await first[0].anchor1Context as Doc] : second.length ? [await second[0].anchor1Context as Doc, await second[0].anchor2Context as Doc] : [undefined, undefined]; + const linkFollowTimecodes = first.length ? [NumCast(first[0].anchor2Timecode), NumCast(first[0].anchor1Timecode)] : second.length ? [NumCast(second[0].anchor1Timecode), NumCast(second[0].anchor2Timecode)] : [undefined, undefined]; if (linkFollowDocs && linkDoc) { const maxLocation = StrCast(linkFollowDocs[0].maximizeLocation, "inTab"); const targetContext = !Doc.AreProtosEqual(linkFollowDocContexts[reverse ? 1 : 0], currentContext) ? linkFollowDocContexts[reverse ? 1 : 0] : undefined; + const target = linkFollowDocs[reverse ? 1 : 0]; + target.currentTimecode !== undefined && (target.currentTimecode = linkFollowTimecodes[reverse ? 1 : 0]); DocumentManager.Instance.jumpToDocument(linkFollowDocs[reverse ? 1 : 0], zoom, (doc: Doc) => focus(doc, maxLocation), targetContext, linkDoc[Id]); } } diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 1cfa8d644..9ab320eab 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -87,7 +87,7 @@ export class InkingCanvas extends React.Component { color: InkingControl.Instance.selectedColor, width: InkingControl.Instance.selectedWidth, tool: InkingControl.Instance.selectedTool, - page: NumCast(this.props.Document.curPage, -1) + displayTimecode: NumCast(this.props.Document.currentTimecode, -1) }); this.inkData = data; } @@ -150,9 +150,9 @@ export class InkingCanvas extends React.Component { @computed get drawnPaths() { - let curPage = NumCast(this.props.Document.curPage, -1); + let curTimecode = NumCast(this.props.Document.currentTimecode, -1); let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { - if (strokeData.page === -1 || (Math.abs(Math.round(strokeData.page) - Math.round(curPage)) < 3)) { + if (strokeData.displayTimecode === -1 || (Math.abs(Math.round(strokeData.displayTimecode) - Math.round(curTimecode)) < 3)) { paths.push( { @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { - var curPage = NumCast(this.props.Document.curPage, -1); - Doc.GetProto(doc).page = curPage; + var curTime = NumCast(this.props.Document.currentTimecode, -1); + curTime !== -1 && (doc.displayTimecode = curTime); if (this.props.fieldExt) { // bcz: fieldExt !== undefined means this is an overlay layer Doc.GetProto(doc).annotationOn = this.props.Document; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 52a41fc84..1ba35a52b 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -51,7 +51,7 @@ const columnTypes: Map = new Map([ ["title", ColumnType.String], ["x", ColumnType.Number], ["y", ColumnType.Number], ["width", ColumnType.Number], ["height", ColumnType.Number], ["nativeWidth", ColumnType.Number], ["nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean], - ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["zIndex", ColumnType.Number] + ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number] ]); @observer diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 5185d9d0e..3d898b7de 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -21,7 +21,7 @@ export class CollectionVideoView extends React.Component { } private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale); - let curTime = NumCast(this.props.Document.curPage); + let curTime = NumCast(this.props.Document.currentTimecode); return ([
    {"" + Math.round(curTime)} {" " + Math.round((curTime - Math.trunc(curTime)) * 100)} @@ -85,7 +85,7 @@ export class CollectionVideoView extends React.Component { onPointerMove = (e: PointerEvent) => { this._isclick += Math.abs(e.movementX) + Math.abs(e.movementY); if (this._videoBox) { - this._videoBox.Seek(Math.max(0, NumCast(this.props.Document.curPage, 0) + Math.sign(e.movementX) * 0.0333)); + this._videoBox.Seek(Math.max(0, NumCast(this.props.Document.currentTimecode, 0) + Math.sign(e.movementX) * 0.0333)); } e.stopImmediatePropagation(); } @@ -94,7 +94,7 @@ export class CollectionVideoView extends React.Component { document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); InkingControl.Instance.switchTool(InkTool.None); - this._isclick < 10 && (this.props.Document.curPage = 0); + this._isclick < 10 && (this.props.Document.currentTimecode = 0); } setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7b29f2c2a..bfd3e6481 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -105,7 +105,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { SelectionManager.DeselectAll(); docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).map(dv => dv && SelectionManager.SelectDoc(dv, true)); } - public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.page, -1) - NumCast(this.Document.curPage, -1)) < 1.5 || NumCast(doc.page, -1) === -1); } + public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } public getActiveDocuments = () => { return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index bf154d37d..eaf65b88c 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -285,7 +285,7 @@ export class MarqueeView extends React.Component this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; - d.page = -1; + d.displayTimecode = undefined; return d; }); } diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx index 2bff3ded4..b18aa5d63 100644 --- a/src/client/views/linking/LinkFollowBox.tsx +++ b/src/client/views/linking/LinkFollowBox.tsx @@ -128,7 +128,7 @@ export class LinkFollowBox extends React.Component { runInAction(async () => { this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: dest })); this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target })); - let tcontext = LinkFollowBox.linkDoc && (await Cast(LinkFollowBox.linkDoc.targetContext, Doc)) as Doc; + let tcontext = LinkFollowBox.linkDoc && (await Cast(LinkFollowBox.linkDoc.anchor2Context, Doc)) as Doc; runInAction(() => tcontext && this._docs.splice(0, 0, { col: tcontext, target: dest })); }); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 88cd2cdc4..1f3887608 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -65,9 +65,9 @@ export class PDFBox extends DocComponent(PdfDocumen public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); } public prevAnnotation() { this._pdfViewer && this._pdfViewer.prevAnnotation(); } public nextAnnotation() { this._pdfViewer && this._pdfViewer.nextAnnotation(); } - public backPage() { this._pdfViewer!.gotoPage(NumCast(this.props.Document.curPage) - 1); } + public backPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); } public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); }; - public forwardPage() { this._pdfViewer!.gotoPage(NumCast(this.props.Document.curPage) + 1); } + public forwardPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); } @undoBatch @action @@ -128,7 +128,7 @@ export class PDFBox extends DocComponent(PdfDocumen
    e.stopPropagation()}>
    - this.gotoPage(Number(e.currentTarget.value))} style={{ left: 20, top: 5, height: "30px", width: "30px", position: "absolute", pointerEvents: "all" }} onClick={action(() => this._pageControls = !this._pageControls)} /> diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 573197117..e83aa8bea 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -3,7 +3,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction, import { observer } from "mobx-react"; import * as rp from 'request-promise'; import { InkTool } from "../../../new_fields/InkField"; -import { makeInterface } from "../../../new_fields/Schema"; +import { makeInterface, createSchema } from "../../../new_fields/Schema"; import { Cast, FieldValue, NumCast, BoolCast } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; import { RouteStore } from "../../../server/RouteStore"; @@ -16,16 +16,19 @@ import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { documentSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; -import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; import { library } from "@fortawesome/fontawesome-svg-core"; import { faVideo } from "@fortawesome/free-solid-svg-icons"; import { Doc } from "../../../new_fields/Doc"; import { ScriptField } from "../../../new_fields/ScriptField"; +import { positionSchema } from "./CollectionFreeFormDocumentView"; var path = require('path'); -type VideoDocument = makeInterface<[typeof documentSchema, typeof pageSchema]>; -const VideoDocument = makeInterface(documentSchema, pageSchema); +export const timeSchema = createSchema({ + currentTimecode: "number", +}); +type VideoDocument = makeInterface<[typeof documentSchema, typeof positionSchema, typeof timeSchema]>; +const VideoDocument = makeInterface(documentSchema, positionSchema, timeSchema); library.add(faVideo); @@ -97,11 +100,11 @@ export class VideoBox extends DocComponent(VideoD } @action public Snapshot() { - let width = NumCast(this.props.Document.width); - let height = NumCast(this.props.Document.height); + let width = this.Document.width || 0; + let height = this.Document.height || 0; var canvas = document.createElement('canvas'); canvas.width = 640; - canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth); + canvas.height = 640 * (this.Document.nativeHeight || 0) / (this.Document.nativeWidth || 1); var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions if (ctx) { ctx.rect(0, 0, canvas.width, canvas.height); @@ -112,24 +115,25 @@ export class VideoBox extends DocComponent(VideoD if (!this._videoRef) { // can't find a way to take snapshots of videos let b = Docs.Create.ButtonDocument({ - x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), - width: 150, height: 50, title: NumCast(this.props.Document.curPage).toString() + x: (this.Document.x || 0) + width, y: (this.Document.y || 0), + width: 150, height: 50, title: (this.Document.currentTimecode || 0).toString() }); - b.onClick = ScriptField.MakeScript(`this.curPage = ${NumCast(this.props.Document.curPage)}`); + b.onClick = ScriptField.MakeScript(`this.currentTimecode = ${(this.Document.currentTimecode || 0)}`); } else { //convert to desired file format var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' // if you want to preview the captured image, - let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, ""); - VideoBox.convertDataUri(dataUrl, filename).then(returnedFilename => { + let filename = path.basename(encodeURIComponent("snapshot" + this.Document.title + "_" + (this.Document.currentTimecode || 0).toString())); + VideoBox.convertDataUri(dataUrl, filename.replace(/\..*$/, "")).then(returnedFilename => { if (returnedFilename) { let url = this.choosePath(Utils.prepend(returnedFilename)); let imageSummary = Docs.Create.ImageDocument(url, { - x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), - width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-" + x: (this.Document.x || 0) + width, y: (this.Document.y || 0), + width: 150, height: height / width * 150, title: "--snapshot" + (this.Document.currentTimecode || 0) + " image-" }); + imageSummary.isButton = true; this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.addDocument && this.props.ContainingCollectionView.props.addDocument(imageSummary, false); - DocUtils.MakeLink({doc:imageSummary}, {doc: this.props.Document}, "snapshot from " + this.props.Document.title, "video frame snapshot"); + DocUtils.MakeLink({ doc: imageSummary }, { doc: this.props.Document }, "snapshot from " + this.Document.title, "video frame snapshot"); } }); } @@ -137,8 +141,8 @@ export class VideoBox extends DocComponent(VideoD @action updateTimecode = () => { - this.player && (this.props.Document.curPage = this.player.currentTime); - this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime()); + this.player && (this.Document.currentTimecode = this.player.currentTime); + this._youtubePlayer && (this.Document.currentTimecode = this._youtubePlayer.getCurrentTime()); } componentDidMount() { @@ -146,12 +150,12 @@ export class VideoBox extends DocComponent(VideoD if (this.youtubeVideoId) { let youtubeaspect = 400 / 315; - var nativeWidth = FieldValue(this.Document.nativeWidth, 0); - var nativeHeight = FieldValue(this.Document.nativeHeight, 0); + var nativeWidth = (this.Document.nativeWidth || 0); + var nativeHeight = (this.Document.nativeHeight || 0); if (!nativeWidth || !nativeHeight) { if (!this.Document.nativeWidth) this.Document.nativeWidth = 600; this.Document.nativeHeight = this.Document.nativeWidth / youtubeaspect; - this.Document.height = FieldValue(this.Document.width, 0) / youtubeaspect; + this.Document.height = (this.Document.width || 0) / youtubeaspect; } } } @@ -168,10 +172,9 @@ export class VideoBox extends DocComponent(VideoD if (vref) { this._videoRef!.ontimeupdate = this.updateTimecode; vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); - if (this._reactionDisposer) this._reactionDisposer(); - this._reactionDisposer = reaction(() => this.props.Document.curPage, () => - !this.Playing && (vref.currentTime = this.Document.curPage || 0) - , { fireImmediately: true }); + this._reactionDisposer && this._reactionDisposer(); + this._reactionDisposer = reaction(() => this.Document.currentTimecode || 0, + time => !this.Playing && (vref.currentTime = time), { fireImmediately: true }); } } @@ -242,7 +245,7 @@ export class VideoBox extends DocComponent(VideoD let onYoutubePlayerReady = (event: any) => { this._reactionDisposer && this._reactionDisposer(); this._youtubeReactionDisposer && this._youtubeReactionDisposer(); - this._reactionDisposer = reaction(() => this.props.Document.curPage, () => !this.Playing && this.Seek(this.Document.curPage || 0)); + this._reactionDisposer = reaction(() => this.Document.currentTimecode, () => !this.Playing && this.Seek(this.Document.currentTimecode || 0)); this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => { let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting; iframe.style.pointerEvents = interactive ? "all" : "none"; @@ -263,9 +266,9 @@ export class VideoBox extends DocComponent(VideoD this._youtubeIframeId = VideoBox._youtubeIframeCounter++; this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true; let style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : ""); - let start = untracked(() => Math.round(NumCast(this.props.Document.curPage))); + let start = untracked(() => Math.round(this.Document.currentTimecode || 0)); return ; } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 8f64c1c2e..e381d0218 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -16,7 +16,7 @@ export interface StrokeData { color: string; width: string; tool: InkTool; - page: number; + displayTimecode: number; } export type InkData = Map; -- cgit v1.2.3-70-g09d2