From a299d1766aa7f4bf3e6bbc3032a39b6b5ae28b4b Mon Sep 17 00:00:00 2001 From: Geireann <60007097+geireann@users.noreply.github.com> Date: Tue, 15 Feb 2022 16:50:51 -0500 Subject: make link anchor --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 311d52afa..a47395771 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -726,6 +726,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } + // TODO: nda -- Look at how link anchors are added makeLinkAnchor(anchorDoc?: Doc, location?: string, targetHref?: string, title?: string) { const state = this._editorView?.state; if (state) { -- cgit v1.2.3-70-g09d2 From a2df645d2ffe83be24c20997c26eaf7257e847c0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 2 May 2022 18:09:22 -0400 Subject: fixed scaling ink label in lightbox,etc views. changed ink strokes so that clicking on label of closed stroke is lower preceden than clicking on line. fixed fontsize UI for setting ink label sizes. can no longer slide ink pts that are cusps along curve. --- src/client/views/InkStrokeProperties.ts | 61 +++++++++++----------- src/client/views/InkingStroke.tsx | 44 +++++++++++----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 3 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 3 +- src/client/views/nodes/button/FontIconBox.tsx | 2 +- .../views/nodes/formattedText/RichTextMenu.tsx | 19 ++++--- src/client/views/pdf/PDFViewer.tsx | 3 +- 9 files changed, 84 insertions(+), 57 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index e4486fc78..922f309d7 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -230,42 +230,41 @@ export class InkStrokeProperties { this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const order = controlIndex % 4; const closed = InkingStroke.IsClosed(ink); - if (origInk && this._currentPoint > 0 && this._currentPoint < ink.length - 1) { + const brokenIndices = Cast(inkView.props.Document.brokenInkIndices, listSpec("number"), []); + if (origInk && this._currentPoint > 0 && this._currentPoint < ink.length - 1 && brokenIndices.findIndex(value => value === controlIndex) === -1) { const cpt_before = ink[controlIndex]; const cpt = { X: cpt_before.X + deltaX, Y: cpt_before.Y + deltaY }; - if (true) { - const newink = origInk.slice(); - const start = this._currentPoint === 0 ? 0 : this._currentPoint - 4; - const splicedPoints = origInk.slice(start, start + (this._currentPoint === 0 || this._currentPoint === ink.length - 1 ? 4 : 8)); - const { nearestT, nearestSeg } = InkStrokeProperties.nearestPtToStroke(splicedPoints, cpt); - const samplesLeft: Point[] = []; - const samplesRight: Point[] = []; - var startDir = { x: 0, y: 0 }; - var endDir = { x: 0, y: 0 }; - for (var i = 0; i < nearestSeg / 4 + 1; i++) { - const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); - if (i === 0) startDir = bez.derivative(0); - if (i === nearestSeg / 4) endDir = bez.derivative(nearestT); - for (var t = 0; t < (i === nearestSeg / 4 ? nearestT + .05 : 1); t += 0.05) { - const pt = bez.compute(i !== nearestSeg / 4 ? t : Math.min(nearestT, t)); - samplesLeft.push(new Point(pt.x, pt.y)); - } + const newink = origInk.slice(); + const start = this._currentPoint === 0 ? 0 : this._currentPoint - 4; + const splicedPoints = origInk.slice(start, start + (this._currentPoint === 0 || this._currentPoint === ink.length - 1 ? 4 : 8)); + const { nearestT, nearestSeg } = InkStrokeProperties.nearestPtToStroke(splicedPoints, cpt); + const samplesLeft: Point[] = []; + const samplesRight: Point[] = []; + var startDir = { x: 0, y: 0 }; + var endDir = { x: 0, y: 0 }; + for (var i = 0; i < nearestSeg / 4 + 1; i++) { + const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); + if (i === 0) startDir = bez.derivative(0); + if (i === nearestSeg / 4) endDir = bez.derivative(nearestT); + for (var t = 0; t < (i === nearestSeg / 4 ? nearestT + .05 : 1); t += 0.05) { + const pt = bez.compute(i !== nearestSeg / 4 ? t : Math.min(nearestT, t)); + samplesLeft.push(new Point(pt.x, pt.y)); } - var { finalCtrls } = FitOneCurve(samplesLeft, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); - for (var i = nearestSeg / 4; i < splicedPoints.length / 4; i++) { - const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); - if (i === nearestSeg / 4) startDir = bez.derivative(nearestT); - if (i === splicedPoints.length / 4 - 1) endDir = bez.derivative(1); - for (var t = i === nearestSeg / 4 ? nearestT : 0; t < (i === nearestSeg / 4 ? 1 + .05 + 1e-7 : 1 + 1e-7); t += 0.05) { - const pt = bez.compute(Math.min(1, t)); - samplesRight.push(new Point(pt.x, pt.y)); - } + } + var { finalCtrls } = FitOneCurve(samplesLeft, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); + for (var i = nearestSeg / 4; i < splicedPoints.length / 4; i++) { + const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); + if (i === nearestSeg / 4) startDir = bez.derivative(nearestT); + if (i === splicedPoints.length / 4 - 1) endDir = bez.derivative(1); + for (var t = i === nearestSeg / 4 ? nearestT : 0; t < (i === nearestSeg / 4 ? 1 + .05 + 1e-7 : 1 + 1e-7); t += 0.05) { + const pt = bez.compute(Math.min(1, t)); + samplesRight.push(new Point(pt.x, pt.y)); } - const { finalCtrls: rightCtrls, error: errorRight } = FitOneCurve(samplesRight, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); - finalCtrls = finalCtrls.concat(rightCtrls); - newink.splice(this._currentPoint - 4, 8, ...finalCtrls); - return newink; } + const { finalCtrls: rightCtrls, error: errorRight } = FitOneCurve(samplesRight, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); + finalCtrls = finalCtrls.concat(rightCtrls); + newink.splice(this._currentPoint - 4, 8, ...finalCtrls); + return newink; } return ink.map((pt, i) => { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 06671961d..1871ab5a4 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -328,12 +328,25 @@ export class InkingStroke extends ViewBoxBaseComponent() { StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== "transparent" ? StrCast(this.layoutDoc.color, "transparent") : "transparent") : ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "yellow", "magenta", "cyan", "orange"][highlightIndex]; // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = (downHdlr?: (e: React.PointerEvent) => void) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15), StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), - StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker, + StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker, markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, false, downHdlr); + const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", "")); + const lineHeightGuess = (+getComputedStyle(document.body).lineHeight.replace("px", "")) / (+getComputedStyle(document.body).fontSize.replace("px", "")); + const interactions = { + onPointerLeave: action(() => this._nearestScrPt = undefined), + onPointerMove: this.props.isSelected() ? this.onPointerMove : undefined, + onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), + onContextMenu: () => { + const cm = ContextMenu.Instance; + !Doc.UserDoc().noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); + cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); + cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); + } + }; return
() { mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset", cursor: this.props.isSelected() ? "default" : undefined }} - onPointerLeave={action(e => this._nearestScrPt = undefined)} - onPointerMove={this.props.isSelected() ? this.onPointerMove : undefined} - onClick={e => this._handledClick && e.stopPropagation()} - onContextMenu={() => { - const cm = ContextMenu.Instance; - !Doc.UserDoc().noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); - cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); - cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); - }} + {...(!closed ? interactions : {})} > - {clickableLine(this.onPointerDown)} {inkLine} + {clickableLine(this.onPointerDown)} {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) :
() { yPadding={10} xPadding={10} fieldKey={"text"} - fontSize={12} + fontSize={fsize} dontRegisterView={true} noSidebar={true} dontScale={true} @@ -374,6 +382,16 @@ export class InkingStroke extends ViewBoxBaseComponent() { />
} + {!closed ? null : + {clickableLine(this.onPointerDown, true)} + }
; } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3f16d3c49..edadd59c0 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -38,7 +38,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this._savedAnnotations; render() { TraceMobx(); @@ -408,7 +409,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.props.PanelWidth() / 5; infoHeight = () => this.props.PanelHeight() / 5; anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; - + savedAnnotations = () => this._savedAnnotations; render() { const renderAnnotations = (docFilters?: () => string[]) => (null); // bcz: commmented this out. Otherwise, any documents that are rendered with an InfoWindow of a marker @@ -618,7 +618,7 @@ export class MapBox extends ViewBoxAnnotatableComponent} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index e57cb1abe..c8b72990f 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -800,6 +800,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent; } + savedAnnotations = () => this._savedAnnotations; render() { const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding); const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad; @@ -847,7 +848,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent} diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index ca13590de..d3ff2586b 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -656,7 +656,7 @@ ScriptingGlobals.add(function setFontHighlight(color?: string, checkResult?: boo ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: boolean) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; if (checkResult) { - return (editorView ? RichTextMenu.Instance.fontSize : StrCast(Doc.UserDoc().fontSize, "10px")).replace("px", ""); + return RichTextMenu.Instance.fontSize.replace("px", ""); } if (typeof size === "number") size = size.toString(); if (size && Number(size).toString() === size) size += "px"; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 4814d6e9a..c5f76cc8d 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -9,7 +9,7 @@ import { wrapInList } from "prosemirror-schema-list"; import { EditorState, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { Doc } from "../../../../fields/Doc"; -import { Cast, StrCast } from "../../../../fields/Types"; +import { Cast, NumCast, StrCast } from "../../../../fields/Types"; import { DocServer } from "../../../DocServer"; import { LinkManager } from "../../../util/LinkManager"; import { SelectionManager } from "../../../util/SelectionManager"; @@ -118,7 +118,7 @@ export class RichTextMenu extends AntimodeMenu { this.activeListType = this.getActiveListStyle(); this._activeAlignment = this.getActiveAlignment(); this._activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; - this._activeFontSize = !activeSizes.length ? "13px" : activeSizes[0]; + this._activeFontSize = !activeSizes.length ? StrCast(this.TextView.Document.fontSize, StrCast(Doc.UserDoc().fontSize, "10px")) : activeSizes[0]; this._activeFontColor = !activeColors.length ? "black" : activeColors.length > 0 ? String(activeColors[0]) : "..."; this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length > 0 ? String(activeHighlights[0]) : "..."; @@ -310,10 +310,17 @@ export class RichTextMenu extends AntimodeMenu { setFontSize = (fontSize: string) => { if (this.view) { - const fmark = this.view.state.schema.marks.pFontSize.create({ fontSize }); - this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); - this.view.focus(); - this.updateMenu(this.view, undefined, this.props); + if (this.view.state.selection.from === 1 && this.view.state.selection.empty && + (!this.view.state.doc.nodeAt(1) || !this.view.state.doc.nodeAt(1)?.marks.some(m => m.type.name === fontSize))) { + this.TextView.dataDoc.fontSize = fontSize; + this.view.focus(); + this.updateMenu(this.view, undefined, this.props); + } else { + const fmark = this.view.state.schema.marks.pFontSize.create({ fontSize }); + this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); + this.view.focus(); + this.updateMenu(this.view, undefined, this.props); + } } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index b55b2cf44..d3876906e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -562,6 +562,7 @@ export class PDFViewer extends React.Component { ; } contentZoom = () => this._zoomed; + savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); return
@@ -586,7 +587,7 @@ export class PDFViewer extends React.Component { addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)} docView={this.props.docViewPath().lastElement()} finishMarquee={this.finishMarquee} - savedAnnotations={this._savedAnnotations} + savedAnnotations={this.savedAnnotations} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />}
-- cgit v1.2.3-70-g09d2 From 57c1b8235b26a1b6a315922b4dc2926e1e597674 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 13 May 2022 18:17:10 -0400 Subject: removed layerProvider functionality. --- src/client/documents/Documents.ts | 3 +- src/client/views/DocComponent.tsx | 4 -- src/client/views/GestureOverlay.tsx | 1 - src/client/views/InkingStroke.tsx | 2 +- src/client/views/LightboxView.tsx | 1 - src/client/views/MainView.tsx | 6 --- src/client/views/OverlayView.tsx | 1 - src/client/views/Palette.tsx | 1 - src/client/views/PropertiesView.tsx | 2 - src/client/views/StyleProvider.tsx | 52 +++------------------- src/client/views/TemplateMenu.tsx | 1 - src/client/views/collections/CollectionMenu.tsx | 1 - .../collections/CollectionStackedTimeline.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 2 - .../views/collections/CollectionTreeView.tsx | 1 - src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 19 +------- src/client/views/collections/TreeView.tsx | 2 - .../collectionFreeForm/CollectionFreeFormView.tsx | 24 +++++----- .../collections/collectionFreeForm/MarqueeView.tsx | 10 ++--- .../collectionLinear/CollectionLinearView.tsx | 1 - .../CollectionMulticolumnView.tsx | 1 - .../CollectionMultirowView.tsx | 1 - .../collectionSchema/CollectionSchemaView.tsx | 1 - .../collections/collectionSchema/SchemaTable.tsx | 1 - src/client/views/linking/LinkPopup.tsx | 3 +- src/client/views/nodes/AudioBox.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 - src/client/views/nodes/DocumentView.tsx | 5 +-- src/client/views/nodes/FilterBox.tsx | 1 - src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 1 - src/client/views/nodes/LinkAnchorBox.tsx | 1 - src/client/views/nodes/LinkDocPreview.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 6 +-- .../views/nodes/formattedText/DashDocView.tsx | 1 - .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 2 +- src/client/views/nodes/trails/PresElementBox.tsx | 1 - src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/search/SearchBox.tsx | 2 +- src/fields/Doc.ts | 2 +- src/mobile/AudioUpload.tsx | 1 - src/mobile/MobileInterface.tsx | 1 - src/server/server_Initialization.ts | 2 +- 46 files changed, 41 insertions(+), 143 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d9c2e0d8b..797a129c4 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -122,7 +122,6 @@ export class DocumentOptions { _scrollTop?: number; // scroll location for pdfs _noAutoscroll?: boolean;// whether collections autoscroll when this item is dragged _chromeHidden?: boolean; // whether the editing chrome for a document is hidden - _layerTags?: List; // layer tags a document has (used for tab filtering "layers" in document tab) _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view) _forceActive?: boolean; // flag to handle pointer events when not selected (or otherwise active) _stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere @@ -426,7 +425,7 @@ export namespace Docs { childDontRegisterViews: true, _isLinkButton: true, _height: 150, description: "", showCaption: "description", backgroundColor: "lightblue", // lightblue is default color for linking dot and link documents text comment area links: "@links(self)", - _removeDropProperties: new List(["_layerTags", "isLinkButton"]), + _removeDropProperties: new List(["isLinkButton"]), } }], [DocumentType.LINKDB, { diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 79aaf2158..9c176a4fd 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -44,7 +44,6 @@ interface ViewBoxBaseProps { ContainingCollectionDoc: Opt; DocumentView?: () => DocumentView; fieldKey: string; - layerProvider?: (doc: Doc, assign?: boolean) => boolean; isSelected: (outsideReaction?: boolean) => boolean; isContentActive: () => boolean | undefined; renderDepth: number; @@ -85,7 +84,6 @@ export interface ViewBoxAnnotatableProps { DataDoc?: Doc; fieldKey: string; filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) - layerProvider?: (doc: Doc, assign?: boolean) => boolean; isContentActive: () => boolean | undefined; select: (isCtrlPressed: boolean) => void; whenChildContentsActiveChanged: (isActive: boolean) => void; @@ -209,13 +207,11 @@ export function ViewBoxAnnotatableComponent

() if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); doc.context = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; - this.props.layerProvider?.(doc, true); Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc); }); } else { added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document - this.props.layerProvider?.(doc, true); //DocUtils.LeavePushpin(doc); doc._stayInCollection = undefined; doc.context = this.props.Document; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 50dca0a99..482b62479 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -881,7 +881,6 @@ export class GestureOverlay extends Touchable { isContentActive={returnFalse} renderDepth={0} styleProvider={returnEmptyString} - layerProvider={undefined} docViewPath={returnEmptyDoclist} focus={DocUtils.DefaultFocus} whenChildContentsActiveChanged={emptyFunction} diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 3d9c048e5..d0f01c363 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -332,7 +332,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15), StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker, - markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, + markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? "none" : "visiblepainted"), 0.0, false, downHdlr); const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", "")); // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 59ed0dc92..9882693ee 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -246,7 +246,6 @@ export class LightboxView extends React.Component { docFilters={this.docFilters} removeDocument={undefined} styleProvider={DefaultStyleProvider} - layerProvider={returnTrue} ScreenToLocalTransform={this.lightboxScreenToLocal} PanelWidth={this.lightboxWidth} PanelHeight={this.lightboxHeight} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index db51c54f8..2e1d10955 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -281,7 +281,6 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} - layerProvider={undefined} styleProvider={undefined} rootSelected={returnTrue} isContentActive={returnTrue} @@ -361,7 +360,6 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} - layerProvider={undefined} styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === Doc.UserDoc().myFilesystem ? DashboardStyleProvider : DefaultStyleProvider} rootSelected={returnTrue} removeDocument={returnFalse} @@ -402,7 +400,6 @@ export class MainView extends React.Component { docViewPath={returnEmptyDoclist} focus={DocUtils.DefaultFocus} styleProvider={DefaultStyleProvider} - layerProvider={undefined} isContentActive={returnTrue} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} @@ -516,7 +513,6 @@ export class MainView extends React.Component { dropAction={"alias"} setHeight={returnFalse} styleProvider={DefaultStyleProvider} - layerProvider={undefined} rootSelected={returnTrue} bringToFront={emptyFunction} select={emptyFunction} @@ -591,7 +587,6 @@ export class MainView extends React.Component { ContainingCollectionDoc={undefined} Document={DocumentLinksButton.invisibleWebDoc} dropAction={"move"} - layerProvider={undefined} styleProvider={undefined} isSelected={returnFalse} select={returnFalse} @@ -673,7 +668,6 @@ export class MainView extends React.Component { rootSelected={returnFalse} renderDepth={0} setHeight={returnFalse} - layerProvider={undefined} styleProvider={undefined} addDocTab={returnFalse} pinToPres={returnFalse} diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 0f51cf9b2..ebad2981d 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -195,7 +195,6 @@ export class OverlayView extends React.Component { whenChildContentsActiveChanged={emptyFunction} focus={DocUtils.DefaultFocus} styleProvider={DefaultStyleProvider} - layerProvider={undefined} docViewPath={returnEmptyDoclist} addDocTab={returnFalse} pinToPres={emptyFunction} diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx index 529697f71..954529bc9 100644 --- a/src/client/views/Palette.tsx +++ b/src/client/views/Palette.tsx @@ -54,7 +54,6 @@ export default class Palette extends React.Component { focus={emptyFunction} docViewPath={returnEmptyDoclist} styleProvider={returnEmptyString} - layerProvider={undefined} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 21c688421..bba2ac211 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -303,7 +303,6 @@ export class PropertiesView extends React.Component { fitContentsToDoc={returnTrue} rootSelected={returnFalse} styleProvider={DefaultStyleProvider} - layerProvider={undefined} docViewPath={returnEmptyDoclist} freezeDimensions={true} dontCenter={"y"} @@ -1010,7 +1009,6 @@ export class PropertiesView extends React.Component { createNewFilterDoc={this.createNewFilterDoc} updateFilterDoc={this.updateFilterDoc} docViewPath={returnEmptyDoclist} - layerProvider={undefined} dontCenter="y" /> diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 5056dedaf..334415b38 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -26,10 +26,6 @@ import React = require("react"); import { InkingStroke } from './InkingStroke'; import { TreeSort } from './collections/TreeView'; -export enum StyleLayers { - Background = "background" -} - export enum StyleProp { TreeViewIcon = "treeViewIcon", TreeViewSortings = "treeViewSortings",// options for how to sort tree view items @@ -56,14 +52,9 @@ export enum StyleProp { function darkScheme() { return CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark; } -function toggleBackground(doc: Doc) { +function toggleLockedPosition(doc: Doc) { UndoManager.RunInBatch(() => runInAction(() => { - const layers = StrListCast(doc._layerTags); - if (!layers.includes(StyleLayers.Background)) { - if (!layers.length) doc._layerTags = new List([StyleLayers.Background]); - else layers.push(StyleLayers.Background); - } - else layers.splice(layers.indexOf(StyleLayers.Background), 1); + doc._lockedPosition = !doc._lockedPosition; }), "toggleBackground"); } @@ -86,7 +77,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic"; - const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background); + const isBackground = () => doc && BoolCast(doc._lockedPosition); const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor); const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity); const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle); @@ -177,7 +168,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt 0 && ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ? -

toggleBackground(doc)}> +
toggleLockedPosition(doc)}>
: (null); @@ -251,30 +240,3 @@ export function DashboardStyleProvider(doc: Opt, props: Opt { - if (doc.z) return true; - if (assign) { - const activeLayer = StrCast(thisDoc?.activeLayer); - if (activeLayer) { - const layers = Cast(doc._layerTags, listSpec("string"), []); - if (layers.length && !layers.includes(activeLayer)) layers.push(activeLayer); - else if (!layers.length) doc._layerTags = new List([activeLayer]); - if (activeLayer === "red" || activeLayer === "green" || activeLayer === "blue") doc._backgroundColor = activeLayer; - } - return true; - } else { - if (Doc.AreProtosEqual(doc, thisDoc)) return true; - const layers = StrListCast(doc._layerTags); - if (!layers.length && !thisDoc?.activeLayer) return true; - if (layers.includes(StrCast(thisDoc?.activeLayer))) return true; - return false; - } - }; -} \ No newline at end of file diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index b3a24e031..636f7042f 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -131,7 +131,6 @@ export class TemplateMenu extends React.Component { ContainingCollectionDoc={undefined} ContainingCollectionView={undefined} styleProvider={DefaultStyleProvider} - layerProvider={undefined} setHeight={returnFalse} docViewPath={returnEmptyDoclist} docFilters={returnEmptyFilter} diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 364a2440e..b3fbd4ca4 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -108,7 +108,6 @@ export class CollectionMenu extends AntimodeMenu{ dropAction={"alias"} setHeight={returnFalse} styleProvider={DefaultStyleProvider} - layerProvider={undefined} rootSelected={returnTrue} bringToFront={emptyFunction} select={emptyFunction} diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index de307416f..683b6d51d 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -392,7 +392,7 @@ export class CollectionStackedTimeline extends CollectionSubView + style={{ pointerEvents: this.rootDoc._lockedPosition ? "none" : undefined }}> {this.showIsTagged()} {this.renderSubView(this.collectionViewType, props)}
); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 8dfc7edc7..73e5a9178 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -26,7 +26,7 @@ import { Colors, Shadows } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView"; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; -import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } from '../StyleProvider'; +import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { CollectionDockingView } from './CollectionDockingView'; import { CollectionDockingViewMenu } from './CollectionDockingViewMenu'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @@ -94,20 +94,6 @@ export class TabDocView extends React.Component { if (tab.element[0].children[1].children.length === 1) { - const toggle = document.createElement("div"); - toggle.style.width = "10px"; - toggle.style.height = "calc(100% - 2px)"; - toggle.style.left = "-2px"; - toggle.style.bottom = "1px"; - toggle.style.borderTopRightRadius = "7px"; - toggle.style.position = "relative"; - toggle.style.display = "inline-block"; - toggle.style.background = "transparent"; - toggle.onclick = (e: MouseEvent) => { - if (tab.contentItem === tab.header.parent.getActiveContentItem()) { - tab.DashDoc.activeLayer = tab.DashDoc.activeLayer ? undefined : StyleLayers.Background; - } - }; iconWrap.className = "lm_iconWrap"; iconWrap.id = "lm_iconWrap"; closeWrap.className = "lm_iconWrap"; @@ -357,7 +343,6 @@ export class TabDocView extends React.Component { disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform); hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap); - @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); } @computed get docView() { return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) : <> this._view = r)} @@ -369,7 +354,6 @@ export class TabDocView extends React.Component { isContentActive={returnTrue} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} - layerProvider={this.layerProvider} styleProvider={DefaultStyleProvider} docFilters={CollectionDockingView.Instance.childDocFilters} docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters} @@ -520,7 +504,6 @@ export class TabMinimapView extends React.Component { whenChildContentsActiveChanged={emptyFunction} focus={DocUtils.DefaultFocus} styleProvider={TabMinimapView.miniStyleProvider} - layerProvider={undefined} addDocTab={this.props.addDocTab} pinToPres={TabDocView.PinDoc} docFilters={CollectionDockingView.Instance.childDocFilters} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 164021358..d608f800c 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -663,7 +663,6 @@ export class TreeView extends React.Component { hideDecorationTitle={this.props.treeView.outlineMode} hideResizeHandles={this.props.treeView.outlineMode} styleProvider={this.titleStyleProvider} - layerProvider={returnTrue} docViewPath={returnEmptyDoclist} treeViewDoc={this.props.treeView.props.Document} addDocument={undefined} @@ -760,7 +759,6 @@ export class TreeView extends React.Component { renderDepth={this.props.renderDepth + 1} treeViewDoc={this.props.treeView?.props.Document} rootSelected={returnTrue} - layerProvider={returnTrue} docViewPath={this.props.treeView.props.docViewPath} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4f79d19ad..322944d92 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -44,7 +44,7 @@ import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { PresBox } from "../../nodes/trails/PresBox"; import { VideoBox } from "../../nodes/VideoBox"; import { CreateImage } from "../../nodes/WebBoxRenderer"; -import { StyleLayers, StyleProp } from "../../StyleProvider"; +import { StyleProp } from "../../StyleProvider"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; import { CollectionViewType } from "../CollectionView"; @@ -122,8 +122,6 @@ export class CollectionFreeFormView extends CollectionSubView ele.bounds && !ele.bounds.z).map(ele => ele.ele); } - @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); } - @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); } @computed get fitToContentVals() { return { bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 }, @@ -222,8 +220,8 @@ export class CollectionFreeFormView extends CollectionSubView s.backgroundColor); // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document - set?.filter(s => !StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); - set?.filter(s => StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); + set?.map(s => styleProp = StrCast(s.backgroundColor)); } } //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray"; return styleProp; @@ -1017,7 +1014,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (sendToBack || StrListCast(doc._layerTags).includes(StyleLayers.Background)) { + if (sendToBack) { doc.zIndex = 0; } else if (doc.isInkMask) { doc.zIndex = 5000; @@ -1155,7 +1152,7 @@ export class CollectionFreeFormView extends CollectionSubView { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); - const pointerEvents = this.props.isContentActive() === false ? "none" : this.backgroundActive || this.props.childPointerEvents ? "all" : + const pointerEvents = this.props.isContentActive() === false ? "none" : this.props.childPointerEvents ? "all" : (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : this.props.pointerEvents?.(); return pointerEvents; } @@ -1195,7 +1192,6 @@ export class CollectionFreeFormView extends CollectionSubView intersectRect(docDims(doc), rect); const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; - let snappableDocs = activeDocs.filter(doc => !StrListCast(doc._layerTags).includes(StyleLayers.Background) && doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to + let snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect))); // if not, see if there are background docs to snap to !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z !== undefined && isDocInView(doc, otherBounds))); // if not, then why not snap to floating docs @@ -1739,7 +1735,7 @@ export class CollectionFreeFormView extends CollectionSubView } - {this.props.Document._isGroup && SnappingManager.GetIsDragging() && (this.ChildDrag || this.props.layerProvider?.(this.props.Document) === false) ? + {this.props.Document._isGroup && SnappingManager.GetIsDragging() && this.ChildDrag ?
, options: DocumentOptions, id?: string) => Doc>, layers: string[], makeGroup: Opt) => { + getCollection = action((selected: Doc[], creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, makeGroup: Opt) => { const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => { Doc.GetProto(doc).data = new List(selected); Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform"; @@ -357,7 +356,6 @@ export class MarqueeView extends React.Component(layers); newCollection._width = this.Bounds.width; newCollection._height = this.Bounds.height; newCollection._isGroup = makeGroup; @@ -437,7 +435,7 @@ export class MarqueeView extends React.Component { - const newCollection = this.getCollection([], undefined, [StyleLayers.Background], undefined); + const newCollection = this.getCollection([], undefined, undefined); this.props.addDocument?.(newCollection); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); @@ -617,7 +615,7 @@ export class MarqueeView extends React.Component this.props.layerProvider?.(doc) !== false && !doc.z).map(selectFunc); + this.props.activeDocuments().filter(doc => !doc.z && !doc._lockedPosition).map(selectFunc); if (!selection.length && selectBackgrounds) this.props.activeDocuments().filter(doc => doc.z === undefined).map(selectFunc); if (!selection.length) this.props.activeDocuments().filter(doc => doc.z !== undefined).map(selectFunc); return selection; diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index c615bfb8e..bec582dcd 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -155,7 +155,6 @@ export class CollectionLinearView extends CollectionSubView() { renderDepth={this.props.renderDepth + 1} focus={emptyFunction} styleProvider={this.props.styleProvider} - layerProvider={this.props.layerProvider} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 6929a1cd8..92f9b2f49 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -219,7 +219,6 @@ export class CollectionMulticolumnView extends CollectionSubView() { Document={layout} DataDoc={layout.resolvedDataDoc as Doc} styleProvider={this.props.styleProvider} - layerProvider={this.props.layerProvider} docViewPath={this.props.docViewPath} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 7e2b83230..4c4054b09 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -218,7 +218,6 @@ export class CollectionMultirowView extends CollectionSubView() { Document={layout} DataDoc={layout.resolvedDataDoc as Doc} styleProvider={this.props.styleProvider} - layerProvider={this.props.layerProvider} docViewPath={this.props.docViewPath} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index a93762ea4..b731479a5 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -417,7 +417,6 @@ export class CollectionSchemaView extends CollectionSubView() { docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} - layerProvider={undefined} docViewPath={returnEmptyDoclist} ContainingCollectionDoc={this.props.CollectionView?.props.Document} ContainingCollectionView={this.props.CollectionView} diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx index 605481ddf..bea5b3be6 100644 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx @@ -573,7 +573,6 @@ export class SchemaTable extends React.Component { Document={this._showDoc} DataDoc={this._showDataDoc} styleProvider={DefaultStyleProvider} - layerProvider={undefined} docViewPath={returnEmptyDoclist} freezeDimensions={true} focus={DocUtils.DefaultFocus} diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index c8be9069c..4b33ef8ae 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -67,7 +67,7 @@ export class LinkPopup extends React.Component { */} - { pinToPres={emptyFunction} rootSelected={returnTrue} styleProvider={DefaultStyleProvider} - layerProvider={undefined} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} PanelWidth={this.getPWidth} diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index e28e5b453..d97cb6f84 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -654,7 +654,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent {!this.path ? this.recordingControls : this.playbackControls}
; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index edadd59c0..5a0ab9110 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -21,7 +21,6 @@ import React = require("react"); export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined; - layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined; renderCutoffProvider: (doc: Doc) => boolean; zIndex?: number; highlight?: boolean; @@ -159,7 +158,6 @@ export class CollectionFreeFormDocumentView extends DocComponent number; docViewPath: () => DocumentView[]; dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt - layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean); styleProvider: Opt; focus: DocFocusFunc; fitWidth?: (doc: Doc) => boolean; @@ -474,7 +473,7 @@ export class DocumentViewInternal extends DocComponent() { treeViewHideHeaderFields={false} dontRegisterView={true} styleProvider={this.FilterStyleProvider} - layerProvider={this.props.layerProvider} docViewPath={this.props.docViewPath} scriptContext={this.props.scriptContext} moveDocument={returnFalse} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index e7c43e5cd..3b04aa807 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -379,7 +379,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { docRangeFilters: returnEmptyFilter, searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, - layerProvider: undefined, docViewPath: returnEmptyDoclist, ContainingCollectionView: undefined, ContainingCollectionDoc: undefined, diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 437d29f39..7fd289a97 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -89,7 +89,6 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { openLinkTargetOnRight = (e: React.MouseEvent) => { const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null)); alias._isLinkButton = undefined; - alias._layerTags = undefined; alias.layoutKey = "layout"; this.props.addDocTab(alias, "add:right"); } diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 375434933..ba515fb89 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -179,7 +179,6 @@ export class LinkDocPreview extends React.Component { moveDocument={returnFalse} rootSelected={returnFalse} styleProvider={this.props.docProps?.styleProvider} - layerProvider={this.props.docProps?.layerProvider} docViewPath={returnEmptyDoclist} ScreenToLocalTransform={Transform.Identity} isDocumentActive={returnFalse} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 3b4c94562..c350e3139 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -809,7 +809,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { e.stopPropagation(); e.preventDefault(); }}> diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 20e01be05..445df8ddd 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -74,7 +74,7 @@ export class WebBox extends ViewBoxAnnotatableComponent a.textInlineAnnotations); } @computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; } - @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url } + @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url; } constructor(props: any) { super(props); @@ -134,7 +134,7 @@ export class WebBox extends ViewBoxAnnotatableComponent setTimeout(action(() => { this.lockout = false; this.layoutDoc.thumb = new ImageField(returnedfilename); - this.layoutDoc.thumbScrollTop = scrollTop + this.layoutDoc.thumbScrollTop = scrollTop; }), 500)); }) .catch(function (error: any) { @@ -717,7 +717,7 @@ export class WebBox extends ViewBoxAnnotatableComponent !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; annotationPointerEvents = () => this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"; render() { - const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents?.() as any; + const pointerEvents = this.layoutDoc._lockedPosition ? "none" : this.props.pointerEvents?.() as any; const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const scale = previewScale * (this.props.scaling?.() || 1); const renderAnnotations = (docFilters?: () => string[]) => diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 364be461f..1d8e3a2cf 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -182,7 +182,6 @@ export class DashDocViewInternal extends React.Component { removeDocument={this.removeDoc} isDocumentActive={returnFalse} isContentActive={this._textBox.props.isContentActive} - layerProvider={this._textBox.props.layerProvider} styleProvider={this._textBox.props.styleProvider} docViewPath={this._textBox.props.docViewPath} ScreenToLocalTransform={this.getDocTransform} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 29117794e..f2a222cee 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1630,7 +1630,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const active = this.props.isContentActive(); const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; - const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false); + const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition); if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide); const minimal = this.props.ignoreAutoHeight; const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 820d7ef96..64f5a296f 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -700,7 +700,7 @@ export class PresBox extends ViewBoxBaseComponent() { removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) && + isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && !this.layoutDoc._lockedPosition) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) /** diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f4dc9b615..ef918d991 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -80,7 +80,6 @@ export class PresElementBox extends ViewBoxBaseComponent() { Document={this.targetDoc} DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]} styleProvider={this.styleProvider} - layerProvider={this.props.layerProvider} docViewPath={returnEmptyDoclist} rootSelected={returnTrue} addDocument={returnFalse} diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index fb2e33e2a..5bdce273d 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -26,7 +26,7 @@ export {DocListCast(this.props.anno.textInlineAnnotations).map(a => )} - + ; } } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 2905e96d9..152b7bbcb 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -127,7 +127,7 @@ export class SearchBox extends ViewBoxBaseComponent() { static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) { let newarray: Doc[] = []; var depth = 0; - let visited: Doc[] = []; + const visited: Doc[] = []; while (docs.length > 0) { newarray = []; docs.filter(d => d && !visited.includes(d)).forEach(d => { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 9de8d0831..194b3ba27 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1026,7 +1026,7 @@ export namespace Doc { if (status === DocBrushStatus.unbrushed) { const lastBrushed = Array.from(brushManager.BrushedDoc.keys()).lastElement(); if (lastBrushed) { - for (var link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) { + for (const link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) { const a1 = Cast(link.anchor1, Doc, null); const a2 = Cast(link.anchor2, Doc, null); if (Doc.AreProtosEqual(a1, doc) || Doc.AreProtosEqual(a2, doc) || diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx index 88221732e..418464f0e 100644 --- a/src/mobile/AudioUpload.tsx +++ b/src/mobile/AudioUpload.tsx @@ -96,7 +96,6 @@ export class AudioUpload extends React.Component { isDocumentActive={returnTrue} isContentActive={emptyFunction} focus={emptyFunction} - layerProvider={undefined} styleProvider={() => "rgba(0,0,0,0)"} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index cfcc48608..78ec706d7 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -214,7 +214,6 @@ export class MobileInterface extends React.Component { isContentActive={emptyFunction} focus={DocUtils.DefaultFocus} styleProvider={this.whitebackground} - layerProvider={undefined} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index bdea57cb2..fd000a83c 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -195,7 +195,7 @@ function proxyServe(req: any, requrl: string, response: any) { console.log("EROR?: ", e); } } else req.pipe(request(requrl)).pipe(response); - } + }; retrieveHTTPBody = () => { req.headers.cookie = ""; req.pipe(request(requrl)) -- cgit v1.2.3-70-g09d2 From 1bff8efd7386d0edd19105d682c0d22fc410bb30 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 16 May 2022 13:32:37 -0400 Subject: made text box body take up entire docview when suppressHeight is set (and set suppressSetHeight in muliticolumn view) - this fixes issues with topBar. made tree view rightbuttons clickable again. fixed drag offset when dragging docs that are fitting their container width when the container is wider than the actual document width. --- src/client/views/collections/TreeView.scss | 16 ++++++++++------ .../collectionMulticolumn/CollectionMulticolumnView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 4 +++- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index b91737a1d..f587dbbf6 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -21,7 +21,7 @@ } .treeView-bulletIcons { - // width: $TREE_BULLET_WIDTH; + // width: $TREE_BULLET_WIDTH; width: 100%; height: 100%; @@ -39,16 +39,17 @@ &:hover { .treeView-expandIcon { - display: unset; + display: unset; } } } + .treeView-bulletIcons:hover img { left: 14px; position: absolute; transform-origin: center left; transform: scale(6); - pointer-events:none; + pointer-events: none; } .bullet { @@ -56,7 +57,7 @@ width: $TREE_BULLET_WIDTH; color: $medium-gray; margin-top: 3px; - // transform: scale(1.3, 1.3); // bcz: why was this here? It makes displaying images in the treeView for documents that have icons harder. + // transform: scale(1.3, 1.3); // bcz: why was this here? It makes displaying images in the treeView for documents that have icons harder. border: #80808030 1px solid; border-radius: 4px; } @@ -70,11 +71,12 @@ border-radius: 4px; font-size: 10px; } + .treeView-container-active { cursor: default; } -.treeView-container-outline-active -.treeView-container-active { + +.treeView-container-outline-active .treeView-container-active { z-index: 100; position: relative; pointer-events: all; @@ -139,6 +141,7 @@ align-items: center; margin-left: 0.25rem; opacity: 0.75; + pointer-events: all; cursor: pointer; >svg { @@ -173,6 +176,7 @@ } .treeView-rightButtons { + >svg, .styleProvider-treeView-icon { display: inherit; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 3582718a3..c18b4cec7 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -259,6 +259,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} + suppressSetHeight={true} ScreenToLocalTransform={dxf} isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive} focus={this.props.focus} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e76bcdc42..628a12945 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -2,7 +2,7 @@ import { IconProp } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, DocListCastAsync, Field, Opt, StrListCast, WidthSym } from "../../../fields/Doc"; +import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, StrListCast, WidthSym } from "../../../fields/Doc"; import { Document } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; @@ -425,6 +425,8 @@ export class DocumentViewInternal extends DocComponent Date: Fri, 20 May 2022 12:51:51 -0400 Subject: removed enumerables field stuff which was hacky and never used. cleaned up some of currentUserUtils initialiazation. fixed treeView sorting for 'none" which fixes problem with slide template. --- src/client/documents/Documents.ts | 24 -- src/client/util/CurrentUserUtils.ts | 242 +++++---------------- .../views/collections/CollectionStackingView.tsx | 1 - src/client/views/collections/TreeView.tsx | 2 +- src/client/views/nodes/ComparisonBox.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 14 -- 6 files changed, 57 insertions(+), 228 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2dd8de089..4be9674f7 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1406,30 +1406,6 @@ export namespace DocUtils { return undefined; } - export async function addFieldEnumerations(doc: Opt, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) { - let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey); - if (!(optionsCollection instanceof Doc)) { - optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set`, system: true }, enumeratedFieldKey); - Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); - } - const options = optionsCollection as Doc; - const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc); - const docFind = `options.data?.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`; - targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(docFind + `._backgroundColor || "white"`, undefined, { options })); - targetDoc && (targetDoc.color = ComputedField.MakeFunction(docFind + `.color || "black"`, undefined, { options })); - targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(docFind + `.borderRounding`, undefined, { options })); - enumerations.map(enumeration => { - const found = DocListCast(options.data).find(d => d.title === enumeration.title); - if (found) { - found._backgroundColor = enumeration._backgroundColor || found._backgroundColor; - found._color = enumeration.color || found._color; - } else { - Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, { ...enumeration, system: true })); - } - }); - return optionsCollection; - } - // /** // * // * @param dms Degree Minute Second format exif gps data diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 8fed6e940..e0580d3c4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -75,201 +75,68 @@ export class CurrentUserUtils { @observable public static searchPanelWidth: number = 0; // sets up the default User Templates - slideView, headerView - static setupUserTemplateButtons(doc: Doc) { - // Prototype for mobile button (not sure if 'Advanced Item Prototypes' is ideal location) - if (doc["template-mobile-button"] === undefined) { - const queryTemplate = this.mobileButton({ - title: "NEW MOBILE BUTTON", - onClick: undefined, - }, - [this.createToolButton({ - ignoreClick: true, - icon: "mobile", - btnType: ButtonType.ToolButton, - backgroundColor: "transparent" - }), - this.mobileTextContainer({}, - [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]); - doc["template-mobile-button"] = CurrentUserUtils.createToolButton({ - onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile", btnType: ButtonType.ToolButton, - }); - } - - if (doc["template-button-slides"] === undefined) { - const slideTemplate = Docs.Create.MultirowDocument( - [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), - Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) - ], - { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } - ); - slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); - doc["template-button-slides"] = CurrentUserUtils.createToolButton({ - onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card", - btnType: ButtonType.ToolButton - }); - } - - if (doc["template-button-link"] === undefined) { // set _backgroundColor to transparent to prevent link dot from obscuring document it's attached to. - const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _autoHeight: true, system: true }, "header")); // text needs to be a space to allow templateText to be created - linkTemplate.system = true; - Doc.GetProto(linkTemplate).layout = - "
" + - " " + - " " + - "
"; - (linkTemplate.proto as Doc).isTemplateDoc = makeTemplate(linkTemplate.proto as Doc, true, "linkView"); - - const rtf2 = { - doc: { - type: "doc", content: [ - { - type: "paragraph", - content: [{ - type: "dashField", - attrs: { - fieldKey: "src", - hideKey: false - } - }] - }, - { type: "paragraph" }, - { - type: "paragraph", - content: [{ - type: "dashField", - attrs: { - fieldKey: "dst", - hideKey: false - } - }] - }] + static setupExperimentalTemplateButtons(doc: Doc) { + if (doc["template-experimental-buttons"] === undefined) { + const requiredTypeNameFields = [ + { + type: "slide", icon: "address-card", template: Docs.Create.MultirowDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), + Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) + ], + { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } + ) }, - selection: { type: "text", anchor: 1, head: 1 }, - storedMarks: [] - }; - linkTemplate.header = new RichTextField(JSON.stringify(rtf2), ""); - - doc["template-button-link"] = CurrentUserUtils.createToolButton({ - onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true, - btnType: ButtonType.ToolButton + { + type: "mobile", icon: "mobile", template: this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, + [this.createToolButton({ ignoreClick: true, icon: "mobile", btnType: ButtonType.ToolButton, backgroundColor: "transparent" }), + this.mobileTextContainer({}, + [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) + ] + ) + }, + ]; + const requiredTypes = requiredTypeNameFields.map(({ type, icon, template }) => { + if (doc[`template-button-${type}`] === undefined) { + template.isTemplateDoc = makeTemplate(template); + doc[`template-button-${type}`] = CurrentUserUtils.createToolButton({ + onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), + dragFactory: new PrefetchProxy(template) as any as Doc, + title: type, + icon, + btnType: ButtonType.ToolButton, + }); + } + return doc[`template-button-${type}`] as Doc; }); - } - // if (doc["template-button-switch"] === undefined) { - // const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create; - - // const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40, system: true }); - // const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1, system: true }); - // const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, system: true }); - // const labelTemplate = { - // doc: { - // type: "doc", content: [{ - // type: "paragraph", - // content: [{ type: "dashField", attrs: { fieldKey: "PARAMS", hideKey: true } }] - // }] - // }, - // selection: { type: "text", anchor: 1, head: 1 }, - // storedMarks: [] - // }; - // Doc.GetProto(name).text = new RichTextField(JSON.stringify(labelTemplate), "PARAMS"); - // Doc.GetProto(yes).backgroundColor = ComputedField.MakeFunction("self[this.PARAMS] ? 'green':'red'"); - // // Doc.GetProto(no).backgroundColor = ComputedField.MakeFunction("!self[this.PARAMS] ? 'red':'white'"); - // // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true"); - // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]"); - // // Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false"); - // const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, system: true }); - // box.isTemplateDoc = makeTemplate(box, true, "switch"); - - // doc["template-button-switch"] = CurrentUserUtils.createToolButton({ - // onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - // dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true, - // btnType: ButtonType.ToolButton - // }); - // } - - const requiredTypes = [ - doc["template-button-slides"] as Doc, - doc["template-mobile-button"] as Doc, - doc["template-button-link"] as Doc, - //doc["template-button-switch"] as Doc] - ]; - if (doc["template-buttons"] === undefined) { - doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { - title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", _chromeHidden: true, + doc["template-experimental-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { + title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true, hidden: ComputedField.MakeFunction("IsNoviceMode()") as any, _stayInCollection: true, _hideContextMenu: true, _forceActive: true, _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true })); - } else { - const curButnTypes = Cast(doc["template-buttons"], Doc, null); - DocListCastAsync(curButnTypes.data).then(async curBtns => { - curBtns && await Promise.all(curBtns); - requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype)); - }); } - return doc["template-buttons"] as Doc; + return doc["template-experimental-buttons"] as Doc; } // setup the different note type skins static setupNoteTemplates(doc: Doc) { - if (doc["template-note-Note"] === undefined) { - const noteView = Docs.Create.TextDocument("", { - title: "text", isTemplateDoc: true, backgroundColor: "yellow", system: true, icon: "sticky-note", - _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize), - }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Note"); - doc["template-note-Note"] = new PrefetchProxy(noteView); - } - if (doc["template-note-Idea"] === undefined) { - const noteView = Docs.Create.TextDocument("", { - title: "text", backgroundColor: "pink", system: true, icon: "lightbulb", - _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize), - }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea"); - doc["template-note-Idea"] = new PrefetchProxy(noteView); - } - if (doc["template-note-Topic"] === undefined) { - const noteView = Docs.Create.TextDocument("", { - title: "text", backgroundColor: "lightblue", system: true, icon: "book-open", - _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize), - }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic"); - doc["template-note-Topic"] = new PrefetchProxy(noteView); - } - // if (doc["template-note-Todo"] === undefined) { - // const noteView = Docs.Create.TextDocument("", { - // title: "text", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption", - // layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus"), system: true, - // _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize), - // }); - // noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo"); - // doc["template-note-Todo"] = new PrefetchProxy(noteView); - // } - // const taskStatusValues = [ - // { title: "todo", _backgroundColor: "blue", color: "white", system: true }, - // { title: "in progress", _backgroundColor: "yellow", color: "black", system: true }, - // { title: "completed", _backgroundColor: "green", color: "white", system: true } - // ]; - // if (doc.fieldTypes === undefined) { - // doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations", system: true }); - // DocUtils.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues); - // } - if (doc["template-notes"] === undefined) { - doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc], // doc["template-note-Todo"] as any as Doc], - { title: "Note Layouts", _height: 75, system: true })); - } else { - const curNoteTypes = Cast(doc["template-notes"], Doc, null); - const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc];//, doc["template-note-Todo"] as any as Doc]; - DocListCastAsync(curNoteTypes.data).then(async curNotes => { - curNotes && await Promise.all(curNotes); - requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype)); - }); + const requiredTypeNameFields = [ + { type: "Note", backgroundColor: "yellow", icon: "sticky-note" }, + { type: "Idea", backgroundColor: "pink", icon: "lightbulb" }, + { type: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; + const requiredTypes = requiredTypeNameFields.map(({ type, backgroundColor, icon }) => + doc[`template-note-${type}`] as Doc ?? + (() => { + const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor, system: true, icon }); + noteView.isTemplateDoc = makeTemplate(noteView, true, type); + return doc[`template-note-${type}`] = new PrefetchProxy(noteView); + })()); + + doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument(requiredTypes, { title: "Note Layouts", _height: 75, system: true })); } return doc["template-notes"] as Doc; @@ -277,11 +144,12 @@ export class CurrentUserUtils { // creates Note templates, and initial "user" templates static setupDocTemplates(doc: Doc) { - const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc); - const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); - const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc); if (doc.templateDocs === undefined) { - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], { + doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([ + CurrentUserUtils.setupNoteTemplates(doc), + CurrentUserUtils.setupExperimentalTemplateButtons(doc), + CurrentUserUtils.setupClickEditorTemplates(doc) + ], { title: "template layouts", _xMargin: 0, system: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) })); @@ -717,7 +585,7 @@ export class CurrentUserUtils { static async setupToolsBtnPanel(doc: Doc) { // setup a masonry view of all he creators const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc); - const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); + const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc); doc["tabs-button-tools"] = undefined; @@ -1260,7 +1128,7 @@ export class CurrentUserUtils { doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode; doc.title = Doc.CurrentUserEmail; doc._raiseWhenDragged = true; - doc._showLabel = false; + doc._showLabel = true; doc._showMenuLabel = true; doc.textAlign = StrCast(doc.textAlign, "left"); doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)"); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4338dedcc..4630b3bf2 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -482,7 +482,6 @@ export class CollectionStackingView extends CollectionSubView { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion)); + const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None)); const rowWidth = () => panelWidth() - treeBulletWidth(); const treeViewRefs = new Map(); return docs.filter(child => child instanceof Doc).map((child, i) => { diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 49cd39f43..5ea6d567a 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -76,7 +76,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { return
e.stopPropagation()} // prevent triggering slider movement in registerSliding - onClick={e => this.clearDoc(e, `compareBox-${which}`)}> + onClick={e => this.clearDoc(e, which)}>
; }; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 34908e54b..1a8352b72 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -58,7 +58,6 @@ export class DashFieldViewInternal extends React.Component(); - @observable _showEnumerables: boolean = false; @observable _dashDoc: Doc | undefined; constructor(props: IDashFieldViewInternal) { @@ -110,7 +109,6 @@ export class DashFieldViewInternal extends React.Component this.fieldSpanKeyDown(e, r)); r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false)); r?.addEventListener("pointerdown", action((e) => { - this._showEnumerables = true; e.stopPropagation(); })); }} > @@ -124,7 +122,6 @@ export class DashFieldViewInternal extends React.Component { if (e.key === "Enter") { // handle the enter key by "submitting" the current text to Dash's database. - e.ctrlKey && DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: span.textContent! }]); this.updateText(span.textContent!, true); e.preventDefault();// prevent default to avoid a newline from being generated and wiping out this field view } @@ -142,7 +139,6 @@ export class DashFieldViewInternal extends React.Component { - this._showEnumerables = false; if (nodeText) { const newText = nodeText.startsWith(":=") || nodeText.startsWith("=:=") ? ":=-computed-" : nodeText; @@ -154,7 +150,6 @@ export class DashFieldViewInternal extends React.Component (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title))); if (modText) { // elementfieldSpan.innerHTML = this._dashDoc![this._fieldKey as string] = modText; - DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, []); Doc.SetInPlace(this._dashDoc!, this._fieldKey, modText, true); } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key else if (nodeText.startsWith(":=")) { @@ -178,13 +173,6 @@ export class DashFieldViewInternal extends React.Component { - e.stopPropagation(); - const collview = await DocUtils.addFieldEnumerations(this._textBoxDoc, this._fieldKey, [{ title: this._fieldKey }]); - collview instanceof Doc && this.props.tbox.props.addDocTab(collview, "add:right"); - } - // clicking on the label creates a pivot view collection of all documents // in the same collection. The pivot field is the fieldKey of this label @@ -220,8 +208,6 @@ export class DashFieldViewInternal extends React.Component} - ; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 0cddc2350124f7ae870e362a4774de6f4d9a0545 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 23 May 2022 10:12:19 -0400 Subject: more code cleanup in currentuserutils. some fixes to dragFactory-count titles. --- src/Utils.ts | 1 + src/client/documents/Documents.ts | 9 +- src/client/util/CurrentUserUtils.ts | 156 ++++++--------------- src/client/util/DragManager.ts | 6 +- src/client/views/MainView.tsx | 3 +- src/client/views/collections/CollectionMenu.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 13 +- 7 files changed, 66 insertions(+), 124 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/Utils.ts b/src/Utils.ts index c3c13a555..dbae0aa8c 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -8,6 +8,7 @@ import Color = require('color'); export namespace Utils { export let DRAG_THRESHOLD = 4; + export let SNAP_THRESHOLD = 10; export function readUploadedFileAsText(inputFile: File) { const temporaryFileReader = new FileReader(); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4be9674f7..6fa467368 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -156,6 +156,7 @@ export class DocumentOptions { "_carousel-caption-yMargin"?: number; "icon-nativeWidth"?: number; "icon-nativeHeight"?: number; + "dragFactory-count"?: number; // number of items created from a drag button (used for setting title with incrementing index) x?: number; y?: number; z?: number; // whether document is in overlay (1) or not (0 or undefined) @@ -672,8 +673,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(url), ...options }); } - export function PresDocument(initial: List = new List(), options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.PRES), initial, options); + export function PresDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.PRES), new List(), options); } export function ScriptingDocument(script: Opt, options: DocumentOptions = {}, fieldKey?: string) { @@ -693,8 +694,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.WEBCAM), "", options); } - export function ScreenshotDocument(title: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), "", { ...options, title }); + export function ScreenshotDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), "", options); } export function ComparisonDocument(options: DocumentOptions = { title: "Comparison Box" }) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b9789ab7f..85769d915 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -24,7 +24,7 @@ import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; import { OverlayView } from "../views/OverlayView"; import { DocumentManager } from "./DocumentManager"; -import { DragManager } from "./DragManager"; +import { DragManager, dropActionType } from "./DragManager"; import { makeTemplate, MakeTemplate } from "./DropConverter"; import { HistoryUtil } from "./History"; import { LinkManager } from "./LinkManager"; @@ -55,7 +55,6 @@ interface Button { } export let resolvedPorts: { server: number, socket: number }; -const headerViewVersion = "0.1"; export class CurrentUserUtils { private static curr_id: string; //TODO tfs: these should be temporary... @@ -87,7 +86,7 @@ export class CurrentUserUtils { }, { type: "mobile", icon: "mobile", template: this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, - [this.createToolButton({ ignoreClick: true, icon: "mobile", btnType: ButtonType.ToolButton, backgroundColor: "transparent" }), + [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), this.mobileTextContainer({}, [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) ] @@ -102,7 +101,6 @@ export class CurrentUserUtils { dragFactory: new PrefetchProxy(template) as any as Doc, title: type, icon, - btnType: ButtonType.ToolButton, }); } return doc[`template-button-${type}`] as Doc; @@ -179,6 +177,9 @@ export class CurrentUserUtils { "icon-nativeWidth": 360 / 4, "icon-nativeHeight": 270 / 4, _width: 360 / 4, _height: 270 / 4, _showTitle: "title", system: true, onClick: deiconifyScript(), ...extra }); + const fontBox = () => Docs.Create.FontIconDocument({ + _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, system: true, onClick: deiconifyScript() + }); if (!templateIconsDoc) { const newIconsList = [ makeIconTemplate(undefined, "title", () => labelBox({ _backgroundColor: "dimgray" })), @@ -189,7 +190,7 @@ export class CurrentUserUtils { makeIconTemplate(DocumentType.IMG, "data", () => imageBox("", { _height: undefined, })), makeIconTemplate(DocumentType.COL, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), makeIconTemplate(DocumentType.VID, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})), - makeIconTemplate(DocumentType.BUTTON, "data", () => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, system: true, onClick: deiconifyScript() })), + makeIconTemplate(DocumentType.BUTTON, "data", () => fontBox()), // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {})) ].filter(d => d).map(d => d!); @@ -201,30 +202,23 @@ export class CurrentUserUtils { title: string, toolTip: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, backgroundColor?: string, dragFactory?: Doc, noviceMode?: boolean, clickFactory?: Doc }[] { + const standardOps = () => ({ _fitWidth: true, system: true, "dragFactory-count": 0, cloneFieldFilter: new List(["system"]) }); if (doc.emptyPresentation === undefined) { - doc.emptyPresentation = Docs.Create.PresDocument(new List(), - { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0", system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyPresentation as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyPresentation = Docs.Create.PresDocument({ ...standardOps(), title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); } if (doc.emptyCollection === undefined) { - doc.emptyCollection = Docs.Create.FreeformDocument([], - { _nativeWidth: undefined, _nativeHeight: undefined, _fitWidth: true, _width: 150, _height: 100, title: "freeform", system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyCollection as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyCollection = Docs.Create.FreeformDocument([], { ...standardOps(), title: "freeform", _width: 150, _height: 100 }); } if (doc.emptyPane === undefined) { - doc.emptyPane = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _backgroundGridShow: true, _nativeHeight: undefined, _width: 500, _height: 800, title: "Untitled Tab", system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyPane as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyPane = Docs.Create.FreeformDocument([], { ...standardOps(), title: "Untitled Tab", _backgroundGridShow: true, _width: 500, _height: 800 }); } if (doc.emptySlide === undefined) { - const textDoc = Docs.Create.TreeDocument([], { - title: "Slide", _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, - allowOverlayDrop: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, - backgroundColor: "white", system: true, cloneFieldFilter: new List(["system"]) + doc.emptySlide = Docs.Create.TreeDocument([], { + ...standardOps(), title: ComputedField.MakeFunction('self.text?.Text') as any, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, "dragFactory-count": undefined, + allowOverlayDrop: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" }); - Doc.GetProto(textDoc).title = ComputedField.MakeFunction('self.text?.Text'); - doc.emptySlide = textDoc; } - if ((doc.emptyHeader as Doc)?.version !== headerViewVersion) { + if (doc.emptyHeader === undefined) { const json = { doc: { type: "doc", @@ -245,9 +239,8 @@ export class CurrentUserUtils { storedMarks: [] }; const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { - title: "text", version: headerViewVersion, _height: 70, _headerPointerEvents: "all", - _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, _fitWidth: true, - cloneFieldFilter: new List(["system"]) + ...standardOps(), title: "text", _height: 70, + _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, }, "header"); const headerBtnHgt = 10; headerTemplate[DataSym].layout = @@ -263,43 +256,34 @@ export class CurrentUserUtils { // ""; (headerTemplate.proto as Doc).isTemplateDoc = makeTemplate(headerTemplate.proto as Doc, true, "headerView"); doc.emptyHeader = headerTemplate; - ((doc.emptyHeader as Doc).proto as Doc)["dragFactory-count"] = 0; } if (doc.emptyComparison === undefined) { - doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "comparison box", _width: 300, _height: 300, system: true, cloneFieldFilter: new List(["system"]) }); + doc.emptyComparison = Docs.Create.ComparisonDocument({ ...standardOps(), title: "Comparer", _width: 300, _height: 300 }); } if (doc.emptyScript === undefined) { - doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250, title: "script", system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyScript as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { ...standardOps(), title: "script", _width: 200, _height: 250, }); } if (doc.emptyScreenshot === undefined) { - doc.emptyScreenshot = Docs.Create.ScreenshotDocument("empty screenshot", { _fitWidth: true, title: "empty screenshot", _width: 400, _height: 200, system: true, cloneFieldFilter: new List(["system"]) }); + doc.emptyScreenshot = Docs.Create.ScreenshotDocument({ ...standardOps(), title: "empty screenshot", _width: 400, _height: 200 }); } if (doc.emptyWall === undefined) { - doc.emptyWall = Docs.Create.ScreenshotDocument("", { _fitWidth: true, _width: 400, _height: 200, title: "screen snapshot", system: true, cloneFieldFilter: new List(["system"]) }); + doc.emptyWall = Docs.Create.ScreenshotDocument({ ...standardOps(), title: "screen snapshot", _width: 400, _height: 200, }); (doc.emptyWall as Doc).videoWall = true; } if (doc.emptyAudio === undefined) { - doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, _height: 100, title: "audio recording", system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyAudio as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { ...standardOps(), title: "audio recording", _width: 200, _height: 100, }); } if (doc.emptyNote === undefined) { - doc.emptyNote = Docs.Create.TextDocument("", { _width: 200, title: "text note", _autoHeight: true, system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyNote as Doc).proto as Doc)["dragFactory-count"] = 0; - } - if (doc.emptyImage === undefined) { - doc.emptyImage = Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth: 250, title: "an image of a cat", system: true }); + doc.emptyNote = Docs.Create.TextDocument("", { ...standardOps(), title: "text note", _width: 200, _autoHeight: true }); } if (doc.emptyButton === undefined) { - doc.emptyButton = Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title: "Button", system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyButton as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyButton = Docs.Create.ButtonDocument({ ...standardOps(), title: "Button", _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }); } if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("http://www.bing.com/", { title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, system: true, cloneFieldFilter: new List(["system"]) }); + doc.emptyWebpage = Docs.Create.WebDocument("http://www.bing.com/", { ...standardOps(), title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, }); } if (doc.emptyMap === undefined) { - doc.emptyMap = Docs.Create.MapDocument([], { title: "map", _showSidebar: true, _width: 800, _height: 600, system: true, cloneFieldFilter: new List(["system"]) }); - ((doc.emptyMap as Doc).proto as Doc)["dragFactory-count"] = 0; + doc.emptyMap = Docs.Create.MapDocument([], { ...standardOps(), title: "map", _showSidebar: true, _width: 800, _height: 600, }); } if (doc.activeMobileMenu === undefined) { this.setupActiveMobileMenu(doc); @@ -309,7 +293,6 @@ export class CurrentUserUtils { { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, }, { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true }, { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc }, - { toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyImage as Doc }, { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true }, { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc }, { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc }, @@ -719,30 +702,21 @@ export class CurrentUserUtils { })) as any as Doc static createToolButton = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ - ...opts, btnType: ButtonType.ToolButton, _forceActive: true, _dropAction: "alias", _removeDropProperties: new List(["_dropAction", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true + btnType: ButtonType.ToolButton, _forceActive: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["_dropAction", "_hideContextMenu", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true, ...opts, })) as any as Doc /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window static setupDockedButtons(doc: Doc) { if (doc.dockedBtns === undefined) { - if (doc["dockedBtn-undo"] === undefined) { - doc["dockedBtn-undo"] = CurrentUserUtils.createToolButton({ - title: "undo", icon: "undo-alt", _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, _hideContextMenu: true, system: true, - onClick: ScriptField.MakeScript("undo()"), btnType: ButtonType.ToolButton, _dropAction: "alias", - _removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to undo" - }); - } - if (doc["dockedBtn-redo"] === undefined) { - doc["dockedBtn-redo"] = CurrentUserUtils.createToolButton({ - title: "redo", icon: "redo-alt", _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, _hideContextMenu: true, system: true, - onClick: ScriptField.MakeScript("redo()"), btnType: ButtonType.ToolButton, _dropAction: "alias", - _removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to redo", - }); - } + const dockBtn = (opts: DocumentOptions) => CurrentUserUtils.createToolButton({ _width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...opts }); + const btnDescs = [ + { title: "undo", opts: () => ({ icon: "undo-alt", onClick: ScriptField.MakeScript("undo()"), toolTip: "Click to undo" }) }, + { title: "redo", opts: () => ({ icon: "redo-alt", onClick: ScriptField.MakeScript("redo()"), toolTip: "Click to redo" }) } + ]; doc.dockedBtns = CurrentUserUtils.linearButtonList({ title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true - }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]); + }, btnDescs.map(desc => doc[`dockedBtn-${desc.title}`] as Doc ?? (doc[`dockedBtn-${desc.title}`] = dockBtn({ title: desc.title, ...desc.opts() })))); } } @@ -996,7 +970,7 @@ export class CurrentUserUtils { static async updateUserDocument(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { if (!doc.globalGroupDatabase) doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument(); - const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data); + await DocListCastAsync((doc.globalGroupDatabase as Doc).data); reaction(() => DateCast((doc.globalGroupDatabase as Doc)["data-lastModified"]), async () => { const groups = await DocListCastAsync((doc.globalGroupDatabase as Doc).data); @@ -1025,9 +999,6 @@ export class CurrentUserUtils { doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, false); doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null); doc.noviceMode = BoolCast(doc.noviceMode, true); - doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // - doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // - Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); doc.savedFilters = new List(); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; @@ -1049,15 +1020,6 @@ export class CurrentUserUtils { doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); - // uncomment this to setup a default note style that uses the custom header layout - // PromiseValue(doc.emptyHeader).then(factory => { - // if (Cast(doc.defaultTextLayout, Doc, null)?.version !== headerViewVersion) { - // const deleg = Doc.delegateDragFactory(factory as Doc); - // deleg.title = "header"; - // doc.defaultTextLayout = new PrefetchProxy(deleg); - // Doc.AddDocToList(Cast(doc["template-notes"], Doc, null), "data", deleg); - // } - // }); setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); doc.fieldInfos = await Docs.setupFieldInfos(); if (doc.activeDashboard instanceof Doc) { @@ -1264,26 +1226,16 @@ ScriptingGlobals.add(function openDragFactory(dragFactory: Doc) { view && SelectionManager.SelectView(view, false); } }); -ScriptingGlobals.add(function MySharedDocs() { return Doc.SharingDoc(); }, - "document containing all shared Docs"); -ScriptingGlobals.add(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, - "is Dash in novice mode"); -ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, - "creates a snapshot copy of a dashboard"); -ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(Doc.UserDoc()); }, - "creates a new dashboard when called"); -ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, - "creates a new presentation when called"); -ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, - "creates a new folder in myFiles when called"); -ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, - "returns all the links to the document or its annotations", "(doc: any)"); -ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, - "imports files from device directly into the import sidebar"); -ScriptingGlobals.add(function shareDashboard(dashboard: Doc) { - SharingManager.Instance.open(undefined, dashboard); -}, - "opens sharing dialog for Dashboard"); +ScriptingGlobals.add(function MySharedDocs() { return Doc.SharingDoc(); }, "document containing all shared Docs"); +ScriptingGlobals.add(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, "is Dash in novice mode"); +ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); +ScriptingGlobals.add(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, "creates a snapshot copy of a dashboard"); +ScriptingGlobals.add(function createNewDashboard() { return CurrentUserUtils.createNewDashboard(Doc.UserDoc()); }, "creates a new dashboard when called"); +ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called"); +ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called"); +ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); +ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); +ScriptingGlobals.add(function shareDashboard(dashboard: Doc) { SharingManager.Instance.open(undefined, dashboard); }, "opens sharing dialog for Dashboard"); ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { const dashboards = await DocListCastAsync(CurrentUserUtils.MyDashboards.data); if (dashboards && dashboards.length > 1) { @@ -1292,21 +1244,10 @@ ScriptingGlobals.add(async function removeDashboard(dashboard: Doc) { } }, "Remove Dashboard from Dashboards"); -ScriptingGlobals.add(async function addToDashboards(dashboard: Doc) { +ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { const dashboardAlias = Doc.MakeAlias(dashboard); - - const allDocs = await DocListCastAsync(dashboard[DataSym]["data-all"]); - - // moves the data-all field from the datadoc to the layoutdoc, necessary for off screen docs tab to function properly - // dashboard["data-all"] = new List(allDocs); - // dashboardAlias["data-all"] = new List((allDocs || []).map(doc => Doc.MakeAlias(doc))); - - // const dockingConfig = JSON.parse(StrCast(dashboardAlias.dockingConfig)); - // dashboardAlias.dockingConfig = JSON.stringify(dockingConfig); - dashboardAlias.data = new List(DocListCast(dashboard.data).map(tabFolder => Doc.MakeAlias(tabFolder))); DocListCast(dashboardAlias.data).forEach(doc => doc.dashboard = dashboardAlias); - //new List(); DocListCast(dashboardAlias.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any; Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboardAlias); @@ -1344,9 +1285,6 @@ ScriptingGlobals.add(function makeTopLevelFolder() { TreeView._editTitleOnLoad = { id: folder[Id], parent: undefined }; return Doc.AddDocToList(Doc.UserDoc().myFilesystem as Doc, "data", folder); }); -ScriptingGlobals.add(function toggleComicMode() { - Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; -}); ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { if (readOnly) return; const sel = SelectionManager.Views()[0]; @@ -1359,8 +1297,7 @@ ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { CollectionFreeFormDocumentView.updateKeyframe(col.childDocs, currentFrame || 0); sel.rootDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1); sel.rootDoc.lastFrame = Math.max(NumCast(sel.rootDoc._currentFrame), NumCast(sel.rootDoc.lastFrame)); -} -); +}); ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { if (readOnly) return; const sel = SelectionManager.Views()[0]; @@ -1372,5 +1309,4 @@ ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { } CollectionFreeFormDocumentView.gotoKeyframe(col.childDocs.slice()); sel.rootDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1); -} -); \ No newline at end of file +}); \ No newline at end of file diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 5a00e0c04..9f8c49081 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -7,7 +7,7 @@ import { listSpec } from "../../fields/Schema"; import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { ScriptField } from "../../fields/ScriptField"; import { Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; -import { emptyFunction } from "../../Utils"; +import { emptyFunction, Utils } from "../../Utils"; import { Docs, DocUtils } from "../documents/Documents"; import * as globalCssVariables from "../views/global/globalCssVariables.scss"; import { DocumentView } from "../views/nodes/DocumentView"; @@ -277,7 +277,7 @@ export namespace DragManager { SnappingManager.setSnapLines(horizLines, vertLines); } export function snapDragAspect(dragPt: number[], snapAspect: number) { - let closest = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10); + let closest = Utils.SNAP_THRESHOLD; let near = dragPt; const intersect = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, dragx: number, dragy: number) => { if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) return undefined; // Check if none of the lines are of length 0 @@ -312,7 +312,7 @@ export namespace DragManager { } // snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { - const snapThreshold = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10); + const snapThreshold = Utils.SNAP_THRESHOLD; const snapVal = (pts: number[], drag: number, snapLines: number[]) => { if (snapLines.length) { const offs = [pts[0], (pts[0] - pts[1]) / 2, -pts[1]]; // offsets from drag pt diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 45dd84e31..6a2df3b51 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -244,8 +244,7 @@ export class MainView extends React.Component { title: "TRAILS", childDontRegisterViews: true, _height: 100, _forceActive: true, boxShadow: "0 0", _lockedPosition: true, treeViewOpen: true, system: true })); } - const pres = Docs.Create.PresDocument(new List(), - { title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); + const pres = Docs.Create.PresDocument({ title: "Untitled Trail", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0" }); CollectionDockingView.AddSplit(pres, "right"); this.userDoc.activePresentation = pres; Doc.AddDocToList(this.userDoc.myTrails as Doc, "data", pres); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index b3fbd4ca4..c322d9e16 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -467,7 +467,7 @@ export class CollectionViewBaseChrome extends React.Component { - const doc = Docs.Create.ScreenshotDocument("screen recording", { _fitWidth: true, _width: 400, _height: 200, mediaState: "pendingRecording" }); + const doc = Docs.Create.ScreenshotDocument({ title: "screen recording", _fitWidth: true, _width: 400, _height: 200, mediaState: "pendingRecording" }); //Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc); CollectionDockingView.AddSplit(doc, "right"); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index d0c8c5826..164bcb9b0 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -17,7 +17,7 @@ import { InkTool } from '../../../../fields/InkField'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from "../../../../fields/RichTextField"; import { RichTextUtils } from '../../../../fields/RichTextUtils'; -import { Cast, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; +import { Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; @@ -62,6 +62,7 @@ import { schema } from "./schema_rts"; import { SummaryView } from "./SummaryView"; import applyDevTools = require("prosemirror-dev-tools"); import React = require("react"); +import { ComputedField } from '../../../../fields/ScriptField'; const translateGoogleApi = require("translate-google-api"); export interface FormattedTextBoxProps { @@ -371,9 +372,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp while (node.firstChild && node.firstChild.type.name !== "text") node = node.firstChild; const str = node.textContent; const prefix = str.startsWith("@") ? "" : "-"; - this.dataDoc.title = prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? "..." : ""); - if (str.startsWith("@") && str.length > 1) { - Doc.AddDocToList(Doc.UserDoc(), "myPublishedDocs", this.rootDoc); + + const cfield = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc.title)); + if (!(cfield instanceof ComputedField)) { + this.dataDoc.title = prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? "..." : ""); + if (str.startsWith("@") && str.length > 1) { + Doc.AddDocToList(Doc.UserDoc(), "myPublishedDocs", this.rootDoc); + } } } } -- cgit v1.2.3-70-g09d2 From 3fe0e0e02a6c9bd717b3df9b000c13d1131f6eb4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 23 May 2022 12:28:31 -0400 Subject: cleaning up singleLine text box api and TreeView types --- src/client/util/CurrentUserUtils.ts | 7 +-- src/client/views/MainView.tsx | 5 +- .../views/collections/CollectionTreeView.tsx | 29 ++++++---- src/client/views/collections/TreeView.tsx | 35 ++++++------ .../collectionFreeForm/CollectionFreeFormView.tsx | 34 ++++++++++-- .../collections/collectionFreeForm/MarqueeView.tsx | 13 +++-- src/client/views/nodes/DocumentView.tsx | 2 + src/client/views/nodes/FieldView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 7 +-- .../formattedText/ProsemirrorExampleTransfer.ts | 62 ++++++---------------- 10 files changed, 101 insertions(+), 96 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 85769d915..1ebb5365a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -16,6 +16,7 @@ import { Docs, DocumentOptions, DocUtils } from "../documents/Documents"; import { DocumentType } from "../documents/DocumentTypes"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { CollectionFreeFormView } from "../views/collections/collectionFreeForm"; +import { TreeViewType } from "../views/collections/CollectionTreeView"; import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; import { TreeView } from "../views/collections/TreeView"; import { Colors } from "../views/global/globalEnums"; @@ -215,7 +216,7 @@ export class CurrentUserUtils { if (doc.emptySlide === undefined) { doc.emptySlide = Docs.Create.TreeDocument([], { ...standardOps(), title: ComputedField.MakeFunction('self.text?.Text') as any, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, "dragFactory-count": undefined, - allowOverlayDrop: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" + allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white" }); } if (doc.emptyHeader === undefined) { @@ -563,7 +564,7 @@ export class CurrentUserUtils { title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: "fileSystem", isFolder: true, system: true, + _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files." })); const toggleDarkTheme = ScriptField.MakeScript(`this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`); @@ -616,7 +617,7 @@ export class CurrentUserUtils { title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, treeViewHideTitle: true, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true, + isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." })); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 6a2df3b51..09a57843c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -8,11 +8,9 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; import { ScriptField } from '../../fields/ScriptField'; import { PromiseValue, StrCast } from '../../fields/Types'; -import { TraceMobx } from '../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; @@ -34,6 +32,7 @@ import { CollectionDockingView } from './collections/CollectionDockingView'; import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; import { CollectionLinearView } from './collections/collectionLinear'; import { CollectionMenu } from './collections/CollectionMenu'; +import { TreeViewType } from './collections/CollectionTreeView'; import { CollectionViewType } from './collections/CollectionView'; import "./collections/TreeView.scss"; import { ComponentDecorations } from './ComponentDecorations'; @@ -263,7 +262,7 @@ export class MainView extends React.Component { title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, - isFolder: true, treeViewType: "fileSystem", childHideLinkButton: true, + isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "proto", system: true, explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." })); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5e89016db..99ffb9bb0 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -27,6 +27,7 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import { TreeView } from "./TreeView"; import React = require("react"); +import { FieldViewProps } from "../nodes/FieldView"; const _global = (window /* browser */ || global /* node */) as any; export type collectionTreeViewProps = { @@ -39,6 +40,12 @@ export type collectionTreeViewProps = { onChildClick?: () => ScriptField; }; +export enum TreeViewType { + outline = "outline", + fileSystem = "fileSystem", + default = "default" +} + @observer export class CollectionTreeView extends CollectionSubView>() { private _treedropDisposer?: DragManager.DragDropDisposer; @@ -54,8 +61,8 @@ export class CollectionTreeView extends CollectionSubView StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeViewType === "outline") this.makeTextCollection(this.treeChildren); + if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; })} />; } + onKey = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { + if (this.outlineMode && e.key === "Enter") { + e.stopPropagation(); + this.makeTextCollection(this.treeChildren); + return true; + } + } get documentTitle() { return this._titleRef = r} - onKeyDown={e => { - if (this.outlineMode) { - e.stopPropagation(); - e.key === "Enter" && this.makeTextCollection(this.treeChildren); - } - }}> + ref={r => this._titleRef = r}> {this.outlineMode ? this.documentTitle : this.editableTitle} ; } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 65f8fe248..70ad23f41 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -26,11 +26,12 @@ import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFun import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { StyleProp } from '../StyleProvider'; -import { CollectionTreeView } from './CollectionTreeView'; +import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView, CollectionViewType } from './CollectionView'; import "./TreeView.scss"; import React = require("react"); import { KeyValueBox } from '../nodes/KeyValueBox'; +import { FieldViewProps } from '../nodes/FieldView'; export interface TreeViewProps { treeView: CollectionTreeView; @@ -241,7 +242,7 @@ export class TreeView extends React.Component { layout: CollectionView.LayoutString("data"), title: "-title-", treeViewExpandedViewLock: true, treeViewExpandedView: "data", - _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: "outline", + _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewType: TreeViewType.outline, x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _width: 1000, _height: 10 }); Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text'); @@ -604,24 +605,29 @@ export class TreeView extends React.Component { if (property.startsWith(StyleProp.Decorations)) return (null); return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView } - onKeyDown = (e: React.KeyboardEvent) => { + onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { switch (e.key) { case "Tab": - e.stopPropagation(); - e.preventDefault(); + e.stopPropagation?.(); + e.preventDefault?.(); setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150); - return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab"); + UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab"); + return true; case "Backspace": - e.stopPropagation(); - e.preventDefault(); - return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc); + if (!(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc)) { + e.stopPropagation?.(); + e.preventDefault?.(); + return true; + } + break; case "Enter": - e.stopPropagation(); - e.preventDefault(); + e.stopPropagation?.(); + e.preventDefault?.(); return UndoManager.RunInBatch(this.makeTextCollection, "bullet"); } } + return false; } titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth() - 2 * treeBulletWidth())); @@ -758,6 +764,7 @@ export class TreeView extends React.Component { hideResizeHandles={this.props.treeView.outlineMode} focus={this.refocus} ContentScaling={returnOne} + onKey={this.onKeyDown} hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} ScreenToLocalTransform={this.docTransform} @@ -800,7 +807,7 @@ export class TreeView extends React.Component { @computed get renderBorder() { const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); const sortings = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string, label: string } }; - return
+ return
{!this.treeViewOpen ? (null) : this.renderContent}
; } @@ -821,9 +828,7 @@ export class TreeView extends React.Component { return this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? "<" + this.doc.title + ">" : // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles
this.props.isContentActive(true) && SelectionManager.DeselectAll()} // bcz: this breaks entering a text filter in a filterBox since it deselects the filter's target document - onKeyDown={this.onKeyDown}> + onDrop={this.onTreeDrop}>
  • {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader ? // should test for prop 'treeViewRenderDocWithBulletAsHeader" this.renderEmbeddedDocument(false, returnFalse) : diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index df09569ef..3b32cf57d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,18 +1,18 @@ import { Bezier } from "bezier-js"; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { DateField } from "../../../../fields/DateField"; -import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc"; +import { DataSym, Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; import { RichTextField } from "../../../../fields/RichTextField"; -import { ImageField } from "../../../../fields/URLField"; import { createSchema, listSpec } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; +import { ImageField } from "../../../../fields/URLField"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils"; @@ -26,6 +26,7 @@ import { DragManager, dropActionType } from "../../../util/DragManager"; import { HistoryUtil } from "../../../util/History"; import { InteractionUtils } from "../../../util/InteractionUtils"; import { LinkManager } from "../../../util/LinkManager"; +import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; import { SearchUtil } from "../../../util/SearchUtil"; import { SelectionManager } from "../../../util/SelectionManager"; import { ColorScheme } from "../../../util/SettingsManager"; @@ -47,13 +48,14 @@ import { CreateImage } from "../../nodes/WebBoxRenderer"; import { StyleProp } from "../../StyleProvider"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; +import { TreeViewType } from "../CollectionTreeView"; import { CollectionViewType } from "../CollectionView"; import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; +import { FieldView, FieldViewProps } from "../../nodes/FieldView"; export const panZoomSchema = createSchema({ _panX: "number", @@ -957,7 +959,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return; + if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -1160,6 +1162,27 @@ export class CollectionFreeFormView extends CollectionSubView this.props.isSelected() || this.props.isContentActive(); + @undoBatch + @action + onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { + const docView = fieldProps.DocumentView?.(); + if (docView && docView.rootDoc._singleLine && ["Tab", "Enter"].includes(e.key)) { + e.stopPropagation?.(); + const below = !e.altKey && e.key !== "Tab"; + const layoutKey = StrCast(docView.LayoutFieldKey); + const newDoc = Doc.MakeCopy(docView.rootDoc, true); + const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; + newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; + if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10; + else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10; + if (layoutKey !== "layout" && docView.rootDoc[layoutKey] instanceof Doc) { + newDoc[layoutKey] = docView.rootDoc[layoutKey]; + } + Doc.GetProto(newDoc).text = undefined; + FormattedTextBox.SelectOnLoad = newDoc[Id]; + return this.addDocument?.(newDoc); + } + } pointerEvents = () => { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); const pointerEvents = this.props.isContentActive() === false ? "none" : @@ -1185,6 +1208,7 @@ export class CollectionFreeFormView extends CollectionSubView Transform; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f5ad47ca7..f7312e59c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -50,6 +50,7 @@ import { ScriptingBox } from "./ScriptingBox"; import { PresBox } from './trails/PresBox'; import React = require("react"); import { DocServer } from "../../DocServer"; +import { FieldViewProps } from "./FieldView"; const { Howl } = require('howler'); interface Window { @@ -178,6 +179,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; onBrowseClick?: () => (ScriptField | undefined); + onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined); } // these props are only available in DocumentViewIntenral diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 94937430e..79c1f1c40 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -5,7 +5,7 @@ import { DateField } from "../../../fields/DateField"; import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { WebField } from "../../../fields/URLField"; -import { DocumentViewSharedProps } from "./DocumentView"; +import { DocumentView, DocumentViewSharedProps } from "./DocumentView"; import { ScriptField } from "../../../fields/ScriptField"; // @@ -25,6 +25,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { scaling?: () => number; setHeight?: (height: number) => void; onBrowseClick?: () => (ScriptField | undefined); + onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined); // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) pointerEvents?: () => Opt; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 164bcb9b0..0e29461a6 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -17,6 +17,7 @@ import { InkTool } from '../../../../fields/InkField'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from "../../../../fields/RichTextField"; import { RichTextUtils } from '../../../../fields/RichTextUtils'; +import { ComputedField } from '../../../../fields/ScriptField'; import { Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; @@ -62,7 +63,6 @@ import { schema } from "./schema_rts"; import { SummaryView } from "./SummaryView"; import applyDevTools = require("prosemirror-dev-tools"); import React = require("react"); -import { ComputedField } from '../../../../fields/ScriptField'; const translateGoogleApi = require("translate-google-api"); export interface FormattedTextBoxProps { @@ -1471,11 +1471,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, "titler"); } } + onKeyDown = (e: React.KeyboardEvent) => { - // single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container) - if (this.rootDoc._singleLine && ((e.key === "Backspace" && !this.dataDoc[this.fieldKey]?.Text) || ["Tab", "Enter"].includes(e.key))) { - return; - } if (e.altKey) { e.preventDefault(); return; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index c76eda859..0dd0a8411 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -1,20 +1,15 @@ -import { chainCommands, exitCode, joinDown, joinUp, lift, deleteSelection, joinBackward, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn, newlineInCode } from "prosemirror-commands"; -import { liftTarget } from "prosemirror-transform"; +import { chainCommands, deleteSelection, exitCode, joinBackward, joinDown, joinUp, lift, newlineInCode, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn } from "prosemirror-commands"; import { redo, undo } from "prosemirror-history"; import { Schema } from "prosemirror-model"; -import { liftListItem, sinkListItem } from "./prosemirrorPatches.js"; -import { splitListItem, wrapInList, } from "prosemirror-schema-list"; -import { EditorState, Transaction, TextSelection } from "prosemirror-state"; -import { SelectionManager } from "../../../util/SelectionManager"; -import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types"; -import { Doc, DataSym, DocListCast, AclAugment, AclSelfEdit } from "../../../../fields/Doc"; -import { FormattedTextBox } from "./FormattedTextBox"; -import { Id } from "../../../../fields/FieldSymbols"; -import { Docs } from "../../../documents/Documents"; -import { Utils } from "../../../../Utils"; -import { listSpec } from "../../../../fields/Schema"; -import { List } from "../../../../fields/List"; +import { splitListItem, wrapInList } from "prosemirror-schema-list"; +import { EditorState, TextSelection, Transaction } from "prosemirror-state"; +import { liftTarget } from "prosemirror-transform"; +import { AclAugment, AclSelfEdit, Doc } from "../../../../fields/Doc"; import { GetEffectiveAcl } from "../../../../fields/util"; +import { Utils } from "../../../../Utils"; +import { Docs } from "../../../documents/Documents"; +import { SelectionManager } from "../../../util/SelectionManager"; +import { liftListItem, sinkListItem } from "./prosemirrorPatches.js"; const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false; @@ -48,29 +43,6 @@ export function buildKeymap>(schema: S, props: any, mapKey keys[key] = cmd; } - /// bcz; Argh!! replace with an onEnter func that conditionally handles Enter - const addTextBox = (below: boolean, force?: boolean) => { - if (props.Document.treeViewType === "outline") return true; // bcz: Arghh .. need to determine if this is an treeViewOutlineBox in which case Enter's are ignored.. - const layoutDoc = props.Document; - const originalDoc = layoutDoc.rootDocument || layoutDoc; - if (force || props.Document._singleLine) { - const layoutKey = StrCast(originalDoc.layoutKey); - const newDoc = Doc.MakeCopy(originalDoc, true); - const dataField = originalDoc[Doc.LayoutFieldKey(newDoc)]; - newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (below) newDoc.y = NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10; - else newDoc.x = NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10; - if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) { - newDoc[layoutKey] = originalDoc[layoutKey]; - } - Doc.GetProto(newDoc).text = undefined; - FormattedTextBox.SelectOnLoad = newDoc[Id]; - props.addDocument(newDoc); - return true; - } - return false; - }; - const canEdit = (state: any) => { switch (GetEffectiveAcl(props.Document)) { case AclAugment: return false; @@ -109,11 +81,7 @@ export function buildKeymap>(schema: S, props: any, mapKey bind("Ctrl-i", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state as any, dispatch as any)); bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { - /// bcz; Argh!! replace layotuTEmpalteString with a onTab prop conditionally handles Tab); - if (props.Document._singleLine) { - if (!props.LayoutTemplateString) return addTextBox(false, true); - return true; - } + if (props.onKey?.({ key: "Tab" }, props)) return true; if (!canEdit(state)) return true; const ref = state.selection; const range = ref.$from.blockRange(ref.$to); @@ -138,8 +106,7 @@ export function buildKeymap>(schema: S, props: any, mapKey }); bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { - /// bcz; Argh!! replace with a onShiftTab prop conditionally handles Tab); - if (props.Document._singleLine) return true; + if (props.onKey?.({ key: "Tab", shiftKey: true })) return true; // single line docs don't process tabs so that their containers can decide what to do. This should be a prop if (!canEdit(state)) return true; const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); @@ -188,13 +155,14 @@ export function buildKeymap>(schema: S, props: any, mapKey }; //Command to create a text document to the right of the selected textbox - bind("Alt-Enter", () => addTextBox(false, true)); + bind("Alt-Enter", () => true); //Command to create a text document to the bottom of the selected textbox - bind("Ctrl-Enter", () => addTextBox(true, true)); + bind("Ctrl-Enter", () => true); // backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward); bind("Backspace", (state: EditorState, dispatch: (tx: Transaction>) => void) => { + if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; if (!deleteSelection(state, (tx: Transaction) => { @@ -216,8 +184,8 @@ export function buildKeymap>(schema: S, props: any, mapKey //newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock //command to break line bind("Enter", (state: EditorState, dispatch: (tx: Transaction>) => void) => { - if (addTextBox(true, false)) return true; + if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; const trange = state.selection.$from.blockRange(state.selection.$to); -- cgit v1.2.3-70-g09d2 From 414b56260c55f5ea7cac43dad83b41688fb924b5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 23 May 2022 20:34:07 -0400 Subject: added headerBar for closed tabs and other docs. extended multirow/col to support hiding chile doc decorations and for making child content/document active work better. changed background style to work better for sub collections. --- src/client/util/CurrentUserUtils.ts | 3 + src/client/views/DocumentDecorations.tsx | 7 +- src/client/views/MainView.tsx | 115 +++++++++++++++------ src/client/views/StyleProvider.tsx | 6 +- src/client/views/collections/CollectionMenu.tsx | 17 ++- src/client/views/collections/CollectionView.tsx | 6 +- src/client/views/collections/TabDocView.tsx | 2 + .../CollectionMulticolumnView.tsx | 11 +- .../CollectionMultirowView.tsx | 11 +- src/client/views/nodes/DocumentView.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 1 - 11 files changed, 125 insertions(+), 60 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 1ebb5365a..1e42b9073 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -70,6 +70,7 @@ export class CurrentUserUtils { @observable public static GuestDashboard: Doc | undefined; @observable public static GuestMobile: Doc | undefined; @observable public static propertiesWidth: number = 0; + @observable public static headerBarHeight: number = 0; @observable public static searchPanelWidth: number = 0; // sets up the default User Templates - slideView, headerView @@ -1003,6 +1004,7 @@ export class CurrentUserUtils { doc.savedFilters = new List(); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; + doc.myHeaderBarDoc = doc.myHeaderBarDoc ?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true }); this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates this.setupImportSidebar(doc); // sets up the import sidebar @@ -1210,6 +1212,7 @@ export class CurrentUserUtils { public static get DockedBtns() { return Cast(Doc.UserDoc().dockedBtns, Doc, null); } public static get MySearchPanelDoc() { return Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null); } public static get ActiveDashboard() { return Cast(Doc.UserDoc().activeDashboard, Doc, null); } + public static get MyHeaderBarDoc() { return Cast(Doc.UserDoc().myHeaderBarDoc, Doc, null); } public static get ActivePresentation() { return Cast(Doc.UserDoc().activePresentation, Doc, null); } public static get MyRecentlyClosed() { return Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc, null); } public static get MyDashboards() { return Cast(Doc.UserDoc().myDashboards, Doc, null); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ae3a91c4d..29e088143 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -511,11 +511,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P {`${this.selectionTitle}`}
  • ; - let inMainMenuPanel = false; - for (let node = seldoc.ContentDiv; node && !inMainMenuPanel; node = node?.parentNode as any) { - if (node.className === "mainView-mainContent") inMainMenuPanel = true; - } - const leftBounds = inMainMenuPanel ? 0 : this.props.boundsLeft; + + const leftBounds = this.props.boundsLeft; const topBounds = LightboxView.LightboxDoc ? 0 : this.props.boundsTop; bounds.x = Math.max(leftBounds, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2; bounds.y = Math.max(topBounds, bounds.y - this._resizeBorderWidth / 2 - this._titleHeight) + this._resizeBorderWidth / 2 + this._titleHeight; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 09a57843c..69e394790 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -33,7 +33,7 @@ import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOpti import { CollectionLinearView } from './collections/collectionLinear'; import { CollectionMenu } from './collections/CollectionMenu'; import { TreeViewType } from './collections/CollectionTreeView'; -import { CollectionViewType } from './collections/CollectionView'; +import { CollectionView, CollectionViewType } from './collections/CollectionView'; import "./collections/TreeView.scss"; import { ComponentDecorations } from './ComponentDecorations'; import { ContextMenu } from './ContextMenu'; @@ -81,14 +81,19 @@ export class MainView extends React.Component { @computed private get dashboardTabHeight() { return 27; } // 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js @computed private get topOfDashUI() { return Number(DASHBOARD_SELECTOR_HEIGHT.replace("px", "")); } - @computed private get topOfMainDoc() { return this.topOfDashUI + this.topMenuHeight(); } + @computed private get topOfHeaderBarDoc() { return this.topOfDashUI + this.topMenuHeight(); } + @computed private get topOfSidebarDoc() { return this.topOfDashUI + this.topMenuHeight(); } + @computed private get topOfMainDoc() { return this.topOfDashUI + this.topMenuHeight() + this.headerBarDocHeight(); } @computed private get topOfMainDocContent() { return this.topOfMainDoc + this.dashboardTabHeight; } @computed private get leftScreenOffsetOfMainDocView() { return this.leftMenuWidth() - 2; } @computed private get userDoc() { return Doc.UserDoc(); } @computed private get colorScheme() { return StrCast(CurrentUserUtils.ActiveDashboard?.colorScheme); } @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; } + @computed private get headerBarDoc() { return this.userDoc ? CurrentUserUtils.MyHeaderBarDoc : CurrentUserUtils.MyHeaderBarDoc; } @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } + headerBarDocWidth = () => this._dashUIWidth; + headerBarDocHeight = () => CurrentUserUtils.headerBarHeight ?? 0; topMenuHeight = () => 35; topMenuWidth = returnZero; // value is ignored ... leftMenuWidth = () => Number(LEFT_MENU_WIDTH.replace("px", "")); @@ -98,7 +103,7 @@ export class MainView extends React.Component { propertiesWidth = () => Math.max(0, Math.min(this._dashUIWidth - 50, CurrentUserUtils.propertiesWidth || 0)); propertiesHeight = () => this._dashUIHeight; mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth(); - mainDocViewHeight = () => this._dashUIHeight; + mainDocViewHeight = () => this._dashUIHeight - this.headerBarDocHeight(); componentDidMount() { document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!)); @@ -177,8 +182,8 @@ export class MainView extends React.Component { fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper as any, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, far.faCircle as any, - fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer as any, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp, - fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl, + fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleDoubleDown, fa.faAngleDoubleLeft, fa.faAngleDoubleUp, faBuffer as any, fa.faExpand, fa.faUndo, + fa.faSlidersH, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl, fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo, fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical, fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll, @@ -276,33 +281,67 @@ export class MainView extends React.Component { return () => this._exploreMode ? ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)", { documentView: "any", clientX: "number", clientY: "number" })! : undefined; } - + headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1); + + headerContentActive = () => SnappingManager.GetIsDragging() ? false : true; + @computed get headerBarDocView() { + console.log(this.headerBarDoc) + return
    +
    ; + } @computed get mainDocView() { - return ; + return <> + {this.headerBarDocView} + ; } @computed get dockingContent() { @@ -331,7 +370,7 @@ export class MainView extends React.Component { this.closeFlyout); } - sidebarScreenToLocal = () => new Transform(0, -this.topOfMainDoc, 1); + sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); addDocTabFunc = (doc: Doc, location: string): boolean => { const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); @@ -461,6 +500,16 @@ export class MainView extends React.Component { ; } + @computed get headerBar() { + return !this.userDoc ? (null) : +
    + {this.headerBarDocView} +
    ; + } + @computed get mainDashboardArea() { return !this.userDoc ? (null) :
    { @@ -620,7 +669,7 @@ export class MainView extends React.Component { - + {LinkDescriptionPopup.descriptionPopup ? : null} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 7ac40fc8e..c44443264 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -158,12 +158,12 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 ? + Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : - Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ? + Doc.UserDoc().activeCollectionBackground, "string") ?? (darkScheme() ? Colors.BLACK : "linear-gradient(#065fff, #85c1f9)")) - )); + ); break; //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index c322d9e16..96029a8e4 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -84,11 +84,11 @@ export class CollectionMenu extends AntimodeMenu{ } @action - toggleProperties = () => { - if (CurrentUserUtils.propertiesWidth > 0) { - CurrentUserUtils.propertiesWidth = 0; + toggleTopBar = () => { + if (CurrentUserUtils.headerBarHeight > 0) { + CurrentUserUtils.headerBarHeight = 0; } else { - CurrentUserUtils.propertiesWidth = 250; + CurrentUserUtils.headerBarHeight = 60; } } @@ -137,14 +137,13 @@ export class CollectionMenu extends AntimodeMenu{ render() { - const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left"; - const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Properties Panel" : "Open Properties Panel"; + const propIcon = CurrentUserUtils.headerBarHeight > 0 ? "angle-double-up" : "angle-double-down"; + const propTitle = CurrentUserUtils.headerBarHeight > 0 ? "Close Header Bar" : "Open Header Bar"; - const prop = {propTitle}
    } key="properties" placement="bottom"> + const prop = {propTitle}
    } key="topar" placement="bottom">
    0 ? Colors.MEDIUM_BLUE : undefined }} - key="properties" - onPointerDown={this.toggleProperties}> + onPointerDown={this.toggleTopBar}>
    ; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 19485a0eb..4f92e305e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -6,7 +6,7 @@ import { Doc, DocListCast } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { ObjectField } from '../../../fields/ObjectField'; import { ScriptField } from '../../../fields/ScriptField'; -import { Cast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { returnEmptyString } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; @@ -237,6 +237,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.props.PanelWidth(); + childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles); + childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle); childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); } @@ -258,6 +260,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent { closeWrap.id = "lm_closeWrap"; closeWrap.onclick = (e: MouseEvent) => { tab.header.parent.contentItem.remove(); + Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc); Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true); }; const docIcon = ; @@ -179,6 +180,7 @@ export class TabDocView extends React.Component { tab.closeElement.off('click') //unbind the current click handler .click(function () { Object.values(tab._disposers).forEach((disposer: any) => disposer?.()); + Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", doc); Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true); SelectionManager.DeselectAll(); UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab"); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index b6b59a2d6..66cc3613d 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -241,7 +241,9 @@ export class CollectionMulticolumnView extends CollectionSubView() { } return this.props.addDocTab(doc, where); } - isContentActive = () => this.props.isSelected() || this.props.isContentActive(); + isContentActive = () => this.props.isSelected() ? true : undefined; + isChildContentActive = () => this.props.isContentActive?.() === false ? false : undefined; + isChildDocumentActive = () => (this.props.childDocumentsActive?.() && this.props.isDocumentActive?.()) || this.isContentActive() || this.props.isContentActive(); getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return this.props.isSelected() || this.props.isContentActive(); + isContentActive = () => this.props.isSelected() ? true : undefined; + isChildContentActive = () => this.props.isContentActive?.() === false ? false : undefined; + isChildDocumentActive = () => (this.props.childDocumentsActive?.() && this.props.isDocumentActive?.()) || this.isContentActive() || this.props.isContentActive(); getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { return {!this._retryThumb || !this.thumbShown() ? (null) : diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 0e29461a6..822bc996b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -635,7 +635,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }), icon: icon }); }); - !Doc.UserDoc().noviceMode && changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" }); const highlighting: ContextMenuProps[] = []; const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others"]; const expertHighlighting = [...noviceHighlighting, "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"]; -- cgit v1.2.3-70-g09d2 From a01cd55030f549b1c4c207d23731a00e689989c3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 25 May 2022 15:18:46 -0400 Subject: variety of small fixes for text / sharing. made typed text default to 35 height so that when shared it doesn't start big and jump to small. changed permissions to be private until an Acl is set - this prevents private docs from flicking on momentarily when shared since fields are not distributed atomically. added Shift/Alt/Ctrl Enter for freeform and stacking views to create neighboring docs. fixed first typed char of text to have a user_mark. made shared text doc header overlap to prevent scrolling. --- src/client/DocServer.ts | 60 ++++++++++------------ src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/MainView.tsx | 4 +- src/client/views/StyleProvider.tsx | 5 +- .../views/collections/CollectionStackingView.tsx | 22 ++++++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 16 +++--- .../formattedText/ProsemirrorExampleTransfer.ts | 14 +++-- src/fields/util.ts | 7 ++- 10 files changed, 77 insertions(+), 57 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index e498a7cca..dbc4783d8 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -364,40 +364,36 @@ export namespace DocServer { const proms: Promise[] = []; runInAction(() => { for (const field of fields) { - if (field !== undefined && field !== null && !_cache[field.id]) { + const cached = _cache[field.id]; + if (!cached) { // deserialize - const cached = _cache[field.id]; - if (!cached) { - const prom = SerializationHelper.Deserialize(field).then(deserialized => { - fieldMap[field.id] = deserialized; - - //overwrite or delete any promises (that we inserted as flags - // to indicate that the field was in the process of being fetched). Now everything - // should be an actual value within or entirely absent from the cache. - if (deserialized !== undefined) { - _cache[field.id] = deserialized; - } else { - delete _cache[field.id]; - } - return deserialized; - }); - // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) - // we set the value at the field's id to a promise that will resolve to the field. - // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). - // The mapping in the .then call ensures that when other callers await these promises, they'll - // get the resolved field - _cache[field.id] = prom; - - // adds to a list of promises that will be awaited asynchronously - proms.push(prom); - } else if (cached instanceof Promise) { - proms.push(cached as any); - } - } else if (_cache[field.id] instanceof Promise) { - proms.push(_cache[field.id] as any); - (_cache[field.id] as any).then((f: any) => fieldMap[field.id] = f); + const prom = SerializationHelper.Deserialize(field).then(deserialized => { + fieldMap[field.id] = deserialized; + + //overwrite or delete any promises (that we inserted as flags + // to indicate that the field was in the process of being fetched). Now everything + // should be an actual value within or entirely absent from the cache. + if (deserialized !== undefined) { + _cache[field.id] = deserialized; + } else { + delete _cache[field.id]; + } + return deserialized; + }); + // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) + // we set the value at the field's id to a promise that will resolve to the field. + // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). + // The mapping in the .then call ensures that when other callers await these promises, they'll + // get the resolved field + _cache[field.id] = prom; + + // adds to a list of promises that will be awaited asynchronously + proms.push(prom); + } else if (cached instanceof Promise) { + proms.push(cached as any); + cached.then((f: any) => fieldMap[field.id] = f); } else if (field) { - proms.push(_cache[field.id] as any); + proms.push(cached as any); fieldMap[field.id] = DocServer.GetCachedRefField(field.id) || field; } } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c3b6953b5..ed37c48dc 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -369,7 +369,7 @@ export namespace Docs { [DocumentType.RTF, { layout: { view: FormattedTextBox, dataField: "text" }, options: { - _height: 150, _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true, treeViewGrowsHorizontally: true, + _height: 35, _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true, treeViewGrowsHorizontally: true, links: "@links(self)" } }], diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e4dc175bd..436237d6c 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1184,7 +1184,7 @@ export class CurrentUserUtils { public static GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) { const tbox = Docs.Create.TextDocument("", { _xMargin: noMargins ? 0 : undefined, _yMargin: noMargins ? 0 : undefined, annotationOn, docMaxAutoHeight: maxHeight, backgroundColor: backgroundColor, - _width: width || 200, _height: height || 100, x: x, y: y, _fitWidth: true, _autoHeight: true, title + _width: width || 200, _height: 35, x: x, y: y, _fitWidth: true, _autoHeight: true, title }); const template = Doc.UserDoc().defaultTextLayout; if (template instanceof Doc) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 183efc944..ff2857739 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -120,8 +120,8 @@ export class MainView extends React.Component { } this._sidebarContent.proto = undefined; if (!MainView.Live) { - DocServer.setPlaygroundFields(["dataTransition", "treeViewOpen", "autoHeight", "showSidebar", "sidebarWidthPercent", "viewTransition", - "panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "text-scrollHeight", "text-height", "hideMinimap", + DocServer.setPlaygroundFields(["dataTransition", "treeViewOpen", "showSidebar", "sidebarWidthPercent", "viewTransition", + "panX", "panY", "nativeWidth", "nativeHeight", "text-scrollHeight", "text-height", "hideMinimap", "viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's } DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg))); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index c44443264..553f84a67 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -70,6 +70,7 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { + const remoteDocHeader = "author;creationDate;noMargin"; const docProps = testDocProps(props) ? props : undefined; const selected = property.includes(":selected"); const isCaption = property.includes(":caption"); @@ -111,7 +112,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + "color"], StrCast(doc?._color)); @@ -126,7 +127,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt (props?.PanelHeight() || 0) ? 5 : 10) : 0; case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || - doc?.type === DocumentType.RTF || doc?.type === DocumentType.LABEL) && showTitle() && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0; + (doc?.type === DocumentType.RTF && !showTitle()?.includes("noMargin")) || doc?.type === DocumentType.LABEL) && showTitle() && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0; case StyleProp.BackgroundColor: { if (MainView.Instance.LastButton === doc) return Colors.LIGHT_GRAY; let docColor: Opt = diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4630b3bf2..dddae4a34 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -28,6 +28,8 @@ import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; +import { FieldViewProps } from "../nodes/FieldView"; +import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; const _global = (window /* browser */ || global /* node */) as any; @@ -207,6 +209,25 @@ export class CollectionStackingView extends CollectionSubView { + const docView = fieldProps.DocumentView?.(); + if (docView && ["Enter"].includes(e.key) && e.ctrlKey) { + e.stopPropagation?.(); + const below = !e.altKey && e.key !== "Tab"; + const layoutKey = StrCast(docView.LayoutFieldKey); + const newDoc = Doc.MakeCopy(docView.rootDoc, true); + const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; + newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; + if (layoutKey !== "layout" && docView.rootDoc[layoutKey] instanceof Doc) { + newDoc[layoutKey] = docView.rootDoc[layoutKey]; + } + Doc.GetProto(newDoc).text = undefined; + FormattedTextBox.SelectOnLoad = newDoc[Id]; + return this.addDocument?.(newDoc); + } + } isContentActive = () => this.props.isSelected() || this.props.isContentActive(); getDisplayDoc(doc: Doc, width: () => number) { const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc; @@ -225,6 +246,7 @@ export class CollectionStackingView extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && docView.rootDoc._singleLine && ["Tab", "Enter"].includes(e.key)) { + if (docView && (e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== "Tab"; const layoutKey = StrCast(docView.LayoutFieldKey); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 822bc996b..d468822c0 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -245,8 +245,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const state = this._editorView.state.apply(tx); this._editorView.updateState(state); - const tsel = this._editorView.state.selection.$from; - //tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000))); const curText = state.doc.textBetween(0, state.doc.content.size, " \n"); const curTemp = this.layoutDoc.resolvedDataDoc ? Cast(this.layoutDoc[this.props.fieldKey], RichTextField) : undefined; // the actual text in the text box const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype @@ -348,7 +346,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } autoLink = () => { - if (this._editorView) { + if (this._editorView?.state.doc.textContent) { const newAutoLinks = new Set(); const oldAutoLinks = DocListCast(this.props.Document.links).filter(link => link.linkRelationship === LinkManager.AutoKeywords); const f = this._editorView.state.selection.from; @@ -962,7 +960,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, { fireImmediately: true } ); quickScroll = undefined; - setTimeout(this.tryUpdateScrollHeight, 10); + this.tryUpdateScrollHeight(); } pushToGoogleDoc = async () => { @@ -1193,19 +1191,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())); if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) { + const selLoadChar = FormattedTextBox.SelectOnLoadChar; FormattedTextBox.SelectOnLoad = ""; this.props.select(false); - if (FormattedTextBox.SelectOnLoadChar && this._editorView) { + if (selLoadChar && this._editorView) { const $from = this._editorView.state.selection.anchor ? this._editorView.state.doc.resolve(this._editorView.state.selection.anchor - 1) : undefined; const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }); const curMarks = this._editorView.state.storedMarks ?? $from?.marksAcross(this._editorView.state.selection.$head) ?? []; const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark]; const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks); this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size)))); - FormattedTextBox.SelectOnLoadChar = ""; - } else if (curText && !FormattedTextBox.DontSelectInitialText) { - selectAll(this._editorView!.state, this._editorView?.dispatch); + } else if (this._editorView && curText && !FormattedTextBox.DontSelectInitialText) { + selectAll(this._editorView.state, this._editorView?.dispatch) this.startUndoTypingBatch(); + } else if (this._editorView) { + this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }))); } FormattedTextBox.DontSelectInitialText = false; } diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 0dd0a8411..e979ae59e 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -80,8 +80,10 @@ export function buildKeymap>(schema: S, props: any, mapKey //Commands for lists bind("Ctrl-i", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state as any, dispatch as any)); + bind("Ctrl-Tab", () => props.onKey?.(event, props) ? true : true); + bind("Alt-Tab", () => props.onKey?.(event, props) ? true : true); bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { - if (props.onKey?.({ key: "Tab" }, props)) return true; + if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; const ref = state.selection; const range = ref.$from.blockRange(ref.$to); @@ -106,7 +108,7 @@ export function buildKeymap>(schema: S, props: any, mapKey }); bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { - if (props.onKey?.({ key: "Tab", shiftKey: true })) return true; // single line docs don't process tabs so that their containers can decide what to do. This should be a prop + if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); @@ -154,11 +156,9 @@ export function buildKeymap>(schema: S, props: any, mapKey return tx; }; - //Command to create a text document to the right of the selected textbox - bind("Alt-Enter", () => true); - //Command to create a text document to the bottom of the selected textbox - bind("Ctrl-Enter", () => true); + bind("Alt-Enter", () => props.onKey?.(event, props) ? true : true); + bind("Ctrl-Enter", () => props.onKey?.(event, props) ? true : true); // backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward); bind("Backspace", (state: EditorState, dispatch: (tx: Transaction>) => void) => { @@ -244,8 +244,6 @@ export function buildKeymap>(schema: S, props: any, mapKey return false; }); - // mac && bind("Ctrl-Enter", cmd); - // bind("Mod-Enter", cmd); bind("Shift-Enter", cmd); return keys; diff --git a/src/fields/util.ts b/src/fields/util.ts index c708affe3..ef5ac79b8 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -175,8 +175,11 @@ const getEffectiveAclCache = computedFn(function (target: any, user?: string) { * Calculates the effective access right to a document for the current user. */ export function GetEffectiveAcl(target: any, user?: string): symbol { - return !target ? AclPrivate : - target[UpdatingFromServer] ? AclAdmin : getEffectiveAclCache(target, user);// all changes received from the server must be processed as Admin. return this directly so that the acls aren't cached (UpdatingFromServer is not observable) + if (!target) return AclPrivate; + if (target[UpdatingFromServer]) return AclAdmin; + // authored documents are private until an ACL is set. this also fixes notes that flicker on and off when a remote types to create a private note into a shared collection. + if (!target[AclSym] && target.author && target.author !== Doc.CurrentUserEmail) return AclPrivate; + return getEffectiveAclCache(target, user);// all changes received from the server must be processed as Admin. return this directly so that the acls aren't cached (UpdatingFromServer is not observable) } function getPropAcl(target: any, prop: string | symbol | number) { -- cgit v1.2.3-70-g09d2 From 53cae5e2ab9267295a824ff721c119ada5e5dc20 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 31 May 2022 13:03:19 -0400 Subject: added a pop up menu for viewing dashField view collection. added a menu button for turning off autoLinking to text selection. added ability to add button to top contextMenu buttons without blowing away db. --- src/client/util/CurrentUserUtils.ts | 34 +++++++++ src/client/views/MainView.tsx | 2 + .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/button/FontIconBox.tsx | 8 +++ .../views/nodes/formattedText/DashFieldView.tsx | 81 +++++++++++++++++----- .../views/nodes/formattedText/FormattedTextBox.tsx | 12 ++-- .../formattedText/ProsemirrorExampleTransfer.ts | 2 + .../views/nodes/formattedText/RichTextMenu.tsx | 14 +++- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/nodes/formattedText/marks_rts.ts | 14 ++++ 10 files changed, 144 insertions(+), 27 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 083530ce7..c4e2afd08 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -745,6 +745,7 @@ export class CurrentUserUtils { { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", click: 'setAlignment("left", _readOnly_)' }, { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", click: 'setAlignment("center", _readOnly_)' }, { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", click: 'setAlignment("right", _readOnly_)' }, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", click: 'toggleNoAutoLinkAnchor(_readOnly_)' }, ]; return tools; } @@ -834,11 +835,44 @@ export class CurrentUserUtils { !params.subMenu ? btnFunc(params) : CurrentUserUtils.linearButtonList({ + title: params.title, linearViewSubMenu: true, flexGap: 0, ignoreClick: true, linearViewExpandable: true, icon: params.title, _height: 30, linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined, hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, }, params.subMenu.map(btnFunc)))); + } else { + const menuBtnList = DocListCast((doc.contextMenuBtns as Doc).data); + let prev = ""; + CurrentUserUtils.contextMenuTools(doc).forEach(params => { + const menuBtnDoc = menuBtnList.find(doc => doc.title === params.title); + if (!menuBtnDoc) { + const newMenuBtnDoc = !params.subMenu ? + btnFunc(params) : + CurrentUserUtils.linearButtonList({ + title: params.title, + linearViewSubMenu: true, flexGap: 0, ignoreClick: true, + linearViewExpandable: true, icon: params.title, _height: 30, + linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined, + hidden: params.hidden ? ComputedField.MakeFunction(params.hidden) as any : undefined, + }, params.subMenu.map(btnFunc)); + const after = menuBtnList.find(doc => doc.title === prev); + Doc.AddDocToList(doc.contextMenuBtns as Doc, "data", newMenuBtnDoc, after, false, !after); + } + const subMenuBtnList = menuBtnDoc?.data ? DocListCast(menuBtnDoc.data) : undefined; + if (menuBtnDoc && subMenuBtnList && params.subMenu && DocListCast(doc.data).length !== subMenuBtnList.length) { + let prevSub = ""; + params.subMenu.forEach(sub => { + if (!subMenuBtnList.find(doc => doc.title === sub.title)) { + const newSubMenuBtnDoc = btnFunc(sub); + const after = subMenuBtnList.find(doc => doc.title === prevSub); + Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub); + } + prevSub = params.title; + }) + } + prev = params.title; + }); } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ff2857739..55190001b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -50,6 +50,7 @@ import { AudioBox } from './nodes/AudioBox'; import { ButtonType } from './nodes/button/FontIconBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; +import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; @@ -686,6 +687,7 @@ export class MainView extends React.Component { + diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f4cb08f8f..259cc1ee5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1166,7 +1166,7 @@ export class CollectionFreeFormView extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && (e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) { + if (docView && (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== "Tab"; const layoutKey = StrCast(docView.LayoutFieldKey); diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index e6d8fe88d..625f5d14a 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -666,6 +666,14 @@ ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: b if (editorView) RichTextMenu.Instance.setFontSize(size); else Doc.UserDoc()._fontSize = size; }); +ScriptingGlobals.add(function toggleNoAutoLinkAnchor(checkResult?: boolean) { + const editorView = RichTextMenu.Instance?.TextView?.EditorView; + if (checkResult) { + return (editorView ? RichTextMenu.Instance.noAutoLink : Doc.UserDoc().noAutoLink) ? Colors.MEDIUM_BLUE : "transparent"; + } + if (editorView) RichTextMenu.Instance?.toggleNoAutoLinkAnchor(); + else Doc.UserDoc().noAutoLink = Doc.UserDoc().noAutoLink ? true : false; +}); ScriptingGlobals.add(function toggleBold(checkResult?: boolean) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 1a8352b72..6a3f9ed00 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -8,35 +8,41 @@ import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; import { ComputedField } from "../../../../fields/ScriptField"; import { Cast, StrCast } from "../../../../fields/Types"; import { DocServer } from "../../../DocServer"; -import { DocUtils } from "../../../documents/Documents"; import { CollectionViewType } from "../../collections/CollectionView"; import "./DashFieldView.scss"; import { FormattedTextBox } from "./FormattedTextBox"; import React = require("react"); +import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../../Utils"; +import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"; +import { Tooltip } from "@material-ui/core"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; export class DashFieldView { _fieldWrapper: HTMLDivElement; // container for label and value constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + const { boolVal, strVal } = DashFieldViewInternal.fieldContent(tbox.props.Document, tbox.rootDoc, node.attrs.fieldKey); + this._fieldWrapper = document.createElement("div"); this._fieldWrapper.style.width = node.attrs.width; this._fieldWrapper.style.height = node.attrs.height; this._fieldWrapper.style.fontWeight = "bold"; this._fieldWrapper.style.position = "relative"; this._fieldWrapper.style.display = "inline-block"; + this._fieldWrapper.textContent = node.attrs.fieldKey.startsWith("#") ? node.attrs.fieldKey : node.attrs.fieldKey + " " + strVal; this._fieldWrapper.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldWrapper.onkeydown = function (e: any) { e.stopPropagation(); }; this._fieldWrapper.onkeyup = function (e: any) { e.stopPropagation(); }; this._fieldWrapper.onmousedown = function (e: any) { e.stopPropagation(); }; - ReactDOM.render( ReactDOM.render(, this._fieldWrapper); + />, this._fieldWrapper)); (this as any).dom = this._fieldWrapper; } destroy() { ReactDOM.unmountComponentAtNode(this._fieldWrapper); } @@ -76,16 +82,17 @@ export class DashFieldViewInternal extends React.Component { r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r)); r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false)); - r?.addEventListener("pointerdown", action((e) => { - e.stopPropagation(); - })); + r?.addEventListener("pointerdown", action(e => e.stopPropagation())); }} > {strVal} ; @@ -161,7 +166,7 @@ export class DashFieldViewInternal extends React.Component 1 ? new List(splits) : newText; if (this._fieldKey.startsWith("_")) Doc.Layout(this._textBoxDoc)[this._fieldKey] = strVal; @@ -173,11 +178,7 @@ export class DashFieldViewInternal extends React.Component { - e.stopPropagation(); + createPivotForField = (e: React.MouseEvent) => { let container = this.props.tbox.props.ContainingCollectionView; while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) { container = container.props.ContainingCollectionView; @@ -196,6 +197,16 @@ export class DashFieldViewInternal extends React.Component { + setupMoveUpEvents(this, e, returnFalse, returnFalse, (e) => { + DashFieldViewMenu.createFieldView = this.createPivotForField; + DashFieldViewMenu.Instance.show(e.clientX, e.clientY + 16); + }); + } + render() { return
    ; } +} +@observer +export class DashFieldViewMenu extends AntimodeMenu { + static Instance: DashFieldViewMenu; + static createFieldView: (e: React.MouseEvent) => void = emptyFunction; + constructor(props: any) { + super(props); + DashFieldViewMenu.Instance = this; + } + @action + showFields = (e: React.MouseEvent) => { + DashFieldViewMenu.createFieldView(e); + DashFieldViewMenu.Instance.fadeOut(true); + } + + public show = (x: number, y: number) => { + this.jumpTo(x, y, true); + const hideMenu = () => { + this.fadeOut(true); + document.removeEventListener("pointerdown", hideMenu); + } + document.addEventListener("pointerdown", hideMenu) + } + render() { + const buttons = [ + {"Remove Link Anchor"}
    }> + + , + ]; + + return this.getElement(buttons); + } } \ No newline at end of file diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index d468822c0..ce82821b6 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -391,16 +391,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp flattened1.forEach((flat, i) => { const flattened = this.findInNode(this._editorView!, this._editorView!.state.doc, autoLinkTerm); this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex; - alink = alink ?? (DocListCast(this.Document.links).find(link => - Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) && - Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, - LinkManager.AutoKeywords)!); - newAutoLinks.add(alink); const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); const sel = flattened[i]; tr = tr.addMark(sel.from, sel.to, splitter); tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { - if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { + if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { + alink = alink ?? (DocListCast(this.Document.links).find(link => + Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) && + Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, + LinkManager.AutoKeywords)!); + newAutoLinks.add(alink); const allAnchors = [{ href: Doc.localServerPath(target), title: "a link", anchorId: this.props.Document[Id] }]; allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? [])); const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: "auto term", location: "add:right" }); diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index e979ae59e..fb49b0698 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -82,6 +82,8 @@ export function buildKeymap>(schema: S, props: any, mapKey bind("Ctrl-Tab", () => props.onKey?.(event, props) ? true : true); bind("Alt-Tab", () => props.onKey?.(event, props) ? true : true); + bind("Meta-Tab", () => props.onKey?.(event, props) ? true : true); + bind("Meta-Enter", () => props.onKey?.(event, props) ? true : true); bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { if (props.onKey?.(event, props)) return true; if (!canEdit(state)) return true; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index c5f76cc8d..3df1e45a5 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -35,6 +35,7 @@ export class RichTextMenu extends AntimodeMenu { public _brushMap: Map> = new Map(); @observable private collapsed: boolean = false; + @observable private _noLinkActive: boolean = false; @observable private _boldActive: boolean = false; @observable private _italicsActive: boolean = false; @observable private _underlineActive: boolean = false; @@ -79,6 +80,7 @@ export class RichTextMenu extends AntimodeMenu { this._reaction?.(); } + @computed get noAutoLink() { return this._noLinkActive; } @computed get bold() { return this._boldActive; } @computed get underline() { return this._underlineActive; } @computed get italics() { return this._italicsActive; } @@ -220,7 +222,7 @@ export class RichTextMenu extends AntimodeMenu { let activeMarks: MarkType[] = []; if (!this.view || !this.TextView.props.isSelected(true)) return activeMarks; - const markGroup = [schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript]; + const markGroup = [schema.marks.noAutoLinkAnchor, schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript]; if (this.view.state.storedMarks) return this.view.state.storedMarks.map(mark => mark.type); //current selection const { empty, ranges, $to } = this.view.state.selection as TextSelection; @@ -264,6 +266,7 @@ export class RichTextMenu extends AntimodeMenu { setActiveMarkButtons(activeMarks: MarkType[] | undefined) { if (!activeMarks) return; + this._noLinkActive = false; this._boldActive = false; this._italicsActive = false; this._underlineActive = false; @@ -273,6 +276,7 @@ export class RichTextMenu extends AntimodeMenu { activeMarks.forEach(mark => { switch (mark.name) { + case "noAutoLinkAnchor": this._noLinkActive = true; break; case "strong": this._boldActive = true; break; case "em": this._italicsActive = true; break; case "underline": this._underlineActive = true; break; @@ -283,6 +287,14 @@ export class RichTextMenu extends AntimodeMenu { }); } + toggleNoAutoLinkAnchor = () => { + if (this.view) { + const mark = this.view.state.schema.mark(this.view.state.schema.marks.noAutoLinkAnchor); + this.setMark(mark, this.view.state, this.view.dispatch, false); + this.TextView.autoLink(); + this.view.focus(); + } + } toggleBold = () => { if (this.view) { const mark = this.view.state.schema.mark(this.view.state.schema.marks.strong); diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 427e05edb..8851d52e4 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -348,7 +348,7 @@ export class RichTextRules { this.Document[DataSym].tags = `${tags + "#" + tag + ':'}`; } const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" + tag }); - return state.tr.deleteRange(start, end).insert(start, fieldView); + return state.tr.deleteRange(start, end).insert(start, fieldView).insertText(" "); }), diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index 1f6ce014f..2fde5c7ba 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -48,6 +48,20 @@ export const marks: { [index: string]: MarkSpec } = { return ["a", { class: anchorids, "data-targethrefs": targethrefs, "data-linkdoc": node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0]; } }, + noAutoLinkAnchor: { + attrs: {}, + inclusive: false, + parseDOM: [{ + tag: "div", getAttrs(dom: any) { + return { + noAutoLink: dom.getAttribute("data-noAutoLink"), + }; + } + }], + toDOM(node: any) { + return ["span", { "data-noAutoLink": "true" }, 0]; + } + }, // :: MarkSpec A linkAnchor. The anchor can have multiple links, where each linkAnchor specifies an href to the URL of the source selection Marker text, // and a title for use in menus and hover. `title` // defaults to the empty string. Rendered and parsed as an `` -- cgit v1.2.3-70-g09d2 From a801dd089a1d2420bca4e8aa9b6eb893d314ad24 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Jun 2022 12:03:51 -0400 Subject: fixed highlighting of ink to not show bounding box. stopped shift Tab from blocking bulleting. moved presEffects to slide. --- src/client/views/InkingStroke.tsx | 4 +- .../collections/CollectionStackedTimeline.tsx | 3 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 12 ++++-- .../views/nodes/formattedText/RichTextMenu.tsx | 6 +-- src/client/views/nodes/trails/PresBox.tsx | 50 +++++++++++----------- 6 files changed, 42 insertions(+), 35 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index f97b713dd..aa5a815ac 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -323,13 +323,13 @@ export class InkingStroke extends ViewBoxBaseComponent() { StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker, markerScale, StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false); - const highlightIndex = BoolCast(this.props.Document.isLinkButton) && Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString + const highlightIndex = /*BoolCast(this.props.Document.isLinkButton) && */ Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString const highlightColor = !highlightIndex ? StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== "transparent" ? StrCast(this.layoutDoc.color, "transparent") : "transparent") : ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "yellow", "magenta", "cyan", "orange"][highlightIndex]; // Invisible polygonal line that enables the ink to be selected by the user. const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, - inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15), + inkStrokeWidth, fillColor && closed && highlightIndex ? highlightIndex / 2 : inkStrokeWidth + (fillColor ? closed ? 0 : (highlightIndex + 2) : 0), StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker, markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? "none" : "visiblepainted"), 0.0, diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 683b6d51d..02b2248fb 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -434,6 +434,9 @@ export class CollectionStackedTimeline extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) { + if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== "Tab"; const layoutKey = StrCast(docView.LayoutFieldKey); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6b0b92889..040ac7ae5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -14,7 +14,7 @@ import { BoolCast, Cast, ImageCast, NumCast, ScriptCast, StrCast } from "../../. import { AudioField } from "../../../fields/URLField"; import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { emptyFunction, hasDescendantTarget, lightOrDark, OmitKeys, returnEmptyString, returnTrue, returnVal, simulateMouseClick, Utils } from "../../../Utils"; +import { emptyFunction, hasDescendantTarget, lightOrDark, OmitKeys, returnEmptyString, returnTrue, returnFalse, returnVal, simulateMouseClick, Utils } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -961,6 +961,7 @@ export class DocumentViewInternal extends DocComponent
    { toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight()); focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options); getBounds = () => { - if (!this.docView || !this.docView.ContentDiv || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { + if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; } const xf = (this.docView?.props.ScreenToLocalTransform().scale(this.nativeScaling)).inverse(); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 3df1e45a5..9bc2e5628 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -1,15 +1,15 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; -import { action, IReactionDisposer, observable, reaction, runInAction, computed } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { lift, wrapIn } from "prosemirror-commands"; -import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos } from "prosemirror-model"; +import { Mark, MarkType, Node as ProsNode, ResolvedPos } from "prosemirror-model"; import { wrapInList } from "prosemirror-schema-list"; import { EditorState, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { Doc } from "../../../../fields/Doc"; -import { Cast, NumCast, StrCast } from "../../../../fields/Types"; +import { Cast, StrCast } from "../../../../fields/Types"; import { DocServer } from "../../../DocServer"; import { LinkManager } from "../../../util/LinkManager"; import { SelectionManager } from "../../../util/SelectionManager"; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 64f5a296f..9641b403f 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -47,17 +47,17 @@ export class PresBox extends ViewBoxBaseComponent() { * @param renderDoc * @param layoutDoc */ - static renderEffectsDoc(renderDoc: any, layoutDoc: Doc) { + static renderEffectsDoc(renderDoc: any, layoutDoc: Doc, presDoc: Doc) { const effectProps = { - left: layoutDoc.presEffectDirection === PresEffect.Left, - right: layoutDoc.presEffectDirection === PresEffect.Right, - top: layoutDoc.presEffectDirection === PresEffect.Top, - bottom: layoutDoc.presEffectDirection === PresEffect.Bottom, + left: presDoc.presEffectDirection === PresEffect.Left, + right: presDoc.presEffectDirection === PresEffect.Right, + top: presDoc.presEffectDirection === PresEffect.Top, + bottom: presDoc.presEffectDirection === PresEffect.Bottom, opposite: true, - delay: layoutDoc.presTransition, + delay: presDoc.presTransition, // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, }; - switch (layoutDoc.presEffect) { + switch (presDoc.presEffect) { case PresEffect.Zoom: return ({renderDoc}); case PresEffect.Fade: return ({renderDoc}); case PresEffect.Flip: return ({renderDoc}); @@ -71,7 +71,7 @@ export class PresBox extends ViewBoxBaseComponent() { } public static EffectsProvider(layoutDoc: Doc, renderDoc: any) { return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? - PresBox.renderEffectsDoc(renderDoc, layoutDoc) + PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc; } @@ -1089,7 +1089,7 @@ export class PresBox extends ViewBoxBaseComponent() { updateEffectDirection = (effect: any, all?: boolean) => { const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); array.forEach((doc) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const tagDoc = doc;// Cast(doc.presentationTargetDoc, Doc, null); switch (effect) { case PresEffect.Left: tagDoc.presEffectDirection = PresEffect.Left; @@ -1115,7 +1115,7 @@ export class PresBox extends ViewBoxBaseComponent() { updateEffect = (effect: any, all?: boolean) => { const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); array.forEach((doc) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const tagDoc = doc;//Cast(doc.presentationTargetDoc, Doc, null); switch (effect) { case PresEffect.Bounce: tagDoc.presEffect = PresEffect.Bounce; @@ -1152,7 +1152,7 @@ export class PresBox extends ViewBoxBaseComponent() { const zoom = activeItem.presZoom ? NumCast(activeItem.presZoom) * 100 : 75; let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2; if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); - const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None'; + const effect = this.activeItem.presEffect ? this.activeItem.presEffect : 'None'; activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom'; return (
    e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}> @@ -1274,12 +1274,12 @@ export class PresBox extends ViewBoxBaseComponent() { {effect}
    e.stopPropagation()}> -
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None
    -
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In
    -
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip
    -
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate
    -
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce
    -
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll
    +
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None
    +
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In
    +
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip
    +
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate
    +
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce
    +
    e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll
    @@ -1289,11 +1289,11 @@ export class PresBox extends ViewBoxBaseComponent() {
    -
    {"Enter from left"}
    }>
    this.updateEffectDirection(PresEffect.Left)}>
    -
    {"Enter from right"}
    }>
    this.updateEffectDirection(PresEffect.Right)}>
    -
    {"Enter from top"}
    }>
    this.updateEffectDirection(PresEffect.Top)}>
    -
    {"Enter from bottom"}
    }>
    this.updateEffectDirection(PresEffect.Bottom)}>
    -
    {"Enter from center"}
    }>
    this.updateEffectDirection(PresEffect.Center)}>
    +
    {"Enter from left"}
    }>
    this.updateEffectDirection(PresEffect.Left)}>
    +
    {"Enter from right"}
    }>
    this.updateEffectDirection(PresEffect.Right)}>
    +
    {"Enter from top"}
    }>
    this.updateEffectDirection(PresEffect.Top)}>
    +
    {"Enter from bottom"}
    }>
    this.updateEffectDirection(PresEffect.Bottom)}>
    +
    {"Enter from center"}
    }>
    this.updateEffectDirection(PresEffect.Center)}>
    }
    @@ -1308,7 +1308,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get effectDirection(): string { let effect = ''; - switch (this.targetDoc.presEffectDirection) { + switch (this.activeItem.presEffectDirection) { case 'left': effect = "Enter from left"; break; case 'right': effect = "Enter from right"; break; case 'top': effect = "Enter from top"; break; @@ -1324,8 +1324,8 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; this.updateMovement(activeItem.presMovement, true); - this.updateEffect(targetDoc.presEffect, true); - this.updateEffectDirection(targetDoc.presEffectDirection, true); + this.updateEffect(activeItem.presEffect, true); + this.updateEffectDirection(activeItem.presEffectDirection, true); array.forEach((doc) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); -- cgit v1.2.3-70-g09d2 From ba7824a91da113cc813c58b678719092c96d79a2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 3 Jun 2022 16:02:24 -0400 Subject: fixed opening closed tabs from Files sidebar to re-use best Alias before making a new alias. --- src/.DS_Store | Bin 8196 -> 8196 bytes src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/DocumentManager.ts | 28 ++++++++++----------- src/client/views/LightboxView.tsx | 5 ++-- src/client/views/collections/TabDocView.tsx | 15 ++++++++++- src/client/views/collections/TreeView.tsx | 4 +-- src/client/views/nodes/DocumentIcon.tsx | 4 +-- src/client/views/nodes/DocumentView.tsx | 4 --- src/client/views/nodes/button/FontIconBox.tsx | 11 ++++---- .../views/nodes/formattedText/DashFieldView.tsx | 6 ++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 14 ++--------- src/client/views/pdf/PDFViewer.tsx | 2 +- 13 files changed, 48 insertions(+), 49 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/.DS_Store b/src/.DS_Store index b0987293b..4bf9cdac7 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2ed6c3cbe..85ad58726 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -869,7 +869,7 @@ export class CurrentUserUtils { Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub); } prevSub = params.title; - }) + }); } prev = params.title; }); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index aeddc3249..a82f99d5a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -16,7 +16,7 @@ import { SelectionManager } from './SelectionManager'; export class DocumentManager { //global holds all of the nodes (regardless of which collection they're in) - @observable public DocumentViews: DocumentView[] = []; + @observable public DocumentViews = new Set(); @observable public LinkAnchorBoxViews: DocumentView[] = []; @observable public RecordingEvent = 0; @observable public LinkedDocumentViews: { a: DocumentView, b: DocumentView, l: Doc }[] = []; @@ -46,7 +46,7 @@ export class DocumentManager { // this.LinkedDocumentViews.forEach(view => console.log(" LV = " + view.a.props.Document.title + "/" + view.a.props.LayoutTemplateString + " --> " + // view.b.props.Document.title + "/" + view.b.props.LayoutTemplateString)); } else { - this.DocumentViews.push(view); + this.DocumentViews.add(view); } } public RemoveView = action((view: DocumentView) => { @@ -61,8 +61,7 @@ export class DocumentManager { const index = this.LinkAnchorBoxViews.indexOf(view); this.LinkAnchorBoxViews.splice(index, 1); } else { - const index = this.DocumentViews.indexOf(view); - index !== -1 && this.DocumentViews.splice(index, 1); + this.DocumentViews.delete(view); } SelectionManager.DeselectView(view); }); @@ -70,13 +69,13 @@ export class DocumentManager { //gets all views public getDocumentViewsById(id: string) { const toReturn: DocumentView[] = []; - DocumentManager.Instance.DocumentViews.map(view => { + Array.from(DocumentManager.Instance.DocumentViews).map(view => { if (view.rootDoc[Id] === id) { toReturn.push(view); } }); if (toReturn.length === 0) { - DocumentManager.Instance.DocumentViews.map(view => { + Array.from(DocumentManager.Instance.DocumentViews).map(view => { const doc = view.rootDoc.proto; if (doc && doc[Id] && doc[Id] === id) { toReturn.push(view); @@ -96,14 +95,14 @@ export class DocumentManager { const passes = preferredCollection ? [preferredCollection, undefined] : [undefined]; for (const pass of passes) { - DocumentManager.Instance.DocumentViews.map(view => { + Array.from(DocumentManager.Instance.DocumentViews).map(view => { if (view.rootDoc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) { toReturn = view; return; } }); if (!toReturn) { - DocumentManager.Instance.DocumentViews.map(view => { + Array.from(DocumentManager.Instance.DocumentViews).map(view => { const doc = view.rootDoc.proto; if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) { toReturn = view; @@ -122,9 +121,8 @@ export class DocumentManager { } public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { - const docViews = DocumentManager.Instance.DocumentViews; const views: DocumentView[] = []; - docViews.map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view)); + Array.from(DocumentManager.Instance.DocumentViews).map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view)); return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); } public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { @@ -133,8 +131,8 @@ export class DocumentManager { } public getDocumentViews(toFind: Doc): DocumentView[] { const toReturn: DocumentView[] = []; - const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); - const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath)); + const docViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); + const lightViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => LightboxView.IsLightboxDocView(view.docViewPath)); // heuristic to return the "best" documents first: // choose a document in the lightbox first @@ -290,7 +288,7 @@ export class DocumentManager { } } } -export function DocFocusOrOpen(doc: any, collectionDoc?: Doc) { +export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) { const cv = collectionDoc && DocumentManager.Instance.getDocumentView(collectionDoc); const dv = DocumentManager.Instance.getDocumentView(doc, (cv?.ComponentView as CollectionFreeFormView)?.props.CollectionView); if (dv && Doc.AreProtosEqual(dv.props.Document, doc)) { @@ -300,7 +298,9 @@ export function DocFocusOrOpen(doc: any, collectionDoc?: Doc) { else { const context = doc.context !== Doc.UserDoc().myFilesystem && Cast(doc.context, Doc, null); const showDoc = context || doc; - CollectionDockingView.AddSplit(showDoc === Doc.GetProto(showDoc) ? Doc.MakeAlias(showDoc) : showDoc, "right") && context && + const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc; + + CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), "right") && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc)); } } diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index ddfc8b249..3d2769f66 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -275,9 +275,8 @@ export class LightboxView extends React.Component {
    { e.stopPropagation(); - // CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, ""); - LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace"); - console.log("lightbox to tab triggered") + CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, ""); + //LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace"); SelectionManager.DeselectAll(); LightboxView.SetLightboxDoc(undefined); }}> diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 8d84e9a56..d64cb2fd7 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -66,6 +66,8 @@ export class TabDocView extends React.Component { get stack() { return (this.props as any).glContainer.parent.parent; } get tab() { return (this.props as any).glContainer.tab; } get view() { return this._view; } + _lastTab: any; + _lastView: DocumentView | undefined; @action init = (tab: any, doc: Opt) => { @@ -266,6 +268,7 @@ export class TabDocView extends React.Component { componentWillUnmount() { this._tabReaction?.(); + this._view && DocumentManager.Instance.RemoveView(this._view); this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab); this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged); @@ -353,7 +356,11 @@ export class TabDocView extends React.Component { @computed get docView() { return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) : - <> this._view = r)} + <> { + this._lastView && DocumentManager.Instance.RemoveView(this._lastView); + this._view = r; + this._lastView = this._view; + })} renderDepth={0} Document={this._document} DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined} @@ -409,6 +416,12 @@ export class TabDocView extends React.Component { height: "100%", width: "100%" }} ref={ref => { if (this._mainCont = ref) { + if (this._lastTab) { + console.log("DUP tab") + this._view && DocumentManager.Instance.RemoveView(this._view); + CollectionDockingView.Instance.tabMap.delete(this._lastTab); + } + this._lastTab = this.tab; (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document); DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document))); new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 661db7997..9de44fb00 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -183,7 +183,7 @@ export class TreeView extends React.Component { this.treeViewOpen = !this.treeViewOpen; } else { // choose an appropriate alias or make one. --- choose the first alias that (1) user owns, (2) has no context field ... otherwise make a new alias - const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); + const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail); this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), "lightbox"); } @@ -609,7 +609,7 @@ export class TreeView extends React.Component { // TODO: currently doc focus works, but can't seem to edit title // onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick)); onChildClick = () => { - return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.()) + return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.()); } onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick); diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index a9c998757..56de2d1fc 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -52,7 +52,7 @@ export class DocumentIconContainer extends React.Component { }; }, getVars() { - const docs = DocumentManager.Instance.DocumentViews; + const docs = Array.from(DocumentManager.Instance.DocumentViews); const capturedVariables: { [name: string]: Field } = {}; usedDocuments.forEach(index => capturedVariables[`d${index}`] = docs[index].props.Document); return { capturedVariables }; @@ -60,6 +60,6 @@ export class DocumentIconContainer extends React.Component { }; } render() { - return DocumentManager.Instance.DocumentViews.map((dv, i) => ); + return Array.from(DocumentManager.Instance.DocumentViews).map((dv, i) => ); } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 14ededaf8..6e4d6a52e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -242,7 +242,6 @@ export class DocumentViewInternal extends DocComponent() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const script = ScriptCast(this.rootDoc.script); - if (!script) { return null }; + if (!script) { return null; } let noviceList: string[] = []; let text: string | undefined; @@ -459,7 +459,7 @@ export class FontIconBox extends DocComponent() { const buttonText = StrCast(this.rootDoc.buttonText); // TODO:glr Add label of button type - let button = this.defaultButton; + let button: JSX.Element | null = this.defaultButton; switch (this.type) { case ButtonType.TextButton: @@ -527,9 +527,10 @@ export class FontIconBox extends DocComponent() { } return !this.layoutDoc.toolTip || this.type === ButtonType.DropdownList || this.type === ButtonType.ColorButton || this.type === ButtonType.NumberButton || this.type === ButtonType.EditableText ? button : - {StrCast(this.layoutDoc.toolTip)}
    }> - {button} - ; + button !== null ? + {StrCast(this.layoutDoc.toolTip)}
    }> + {button} + : null } } diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 6a3f9ed00..bb3791f1e 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -86,7 +86,7 @@ export class DashFieldViewInternal extends React.Component { const hideMenu = () => { this.fadeOut(true); document.removeEventListener("pointerdown", hideMenu); - } - document.addEventListener("pointerdown", hideMenu) + }; + document.addEventListener("pointerdown", hideMenu); } render() { const buttons = [ diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ce82821b6..434fccf8d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1202,7 +1202,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks); this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size)))); } else if (this._editorView && curText && !FormattedTextBox.DontSelectInitialText) { - selectAll(this._editorView.state, this._editorView?.dispatch) + selectAll(this._editorView.state, this._editorView?.dispatch); this.startUndoTypingBatch(); } else if (this._editorView) { this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }))); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index f4e792acd..0af7715fe 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -2435,9 +2435,7 @@ export class PresBox extends ViewBoxBaseComponent() { indexNum += (index[i] * (10 ** (-i))); } this._treeViewMap.set(indexNum, treeViewDoc); - console.log(String(index), treeViewDoc) this.props.Document.presentationLinearizedDocuments = new List(this.sort(this._treeViewMap)); // this is a flat array of Docs - console.log(this.props.Document.presentationLinearizedDocuments) return this.childDocs; } @@ -2447,21 +2445,13 @@ export class PresBox extends ViewBoxBaseComponent() { indexNum += (index[i] * (10 ** (-i))); } console.log(String(index), treeViewDoc) - this._treeViewMap.delete(indexNum) + this._treeViewMap.delete(indexNum); this.props.Document.presentationLinearizedDocuments = new List(this.sort(this._treeViewMap)); return this.childDocs; } // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1]) - sort = (treeViewMap: Map): Doc[] => { - // TODO - const sortedMap = [...treeViewMap.entries()].sort(); - var sortedDocs = []; - for (var kv of sortedMap) { - sortedDocs.push(kv[1]); - } - return sortedDocs; - } + sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort().map(kv => kv[1]); render() { // calling this method for keyEvents diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 6db36f36a..d5fd425ad 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -154,7 +154,7 @@ export class PDFViewer extends React.Component { if (doc !== this.props.rootDoc && mainCont) { const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1); const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight, NumCast(this.props.Document.scrollHeight)); - if (scrollTo !== undefined && scrollTo != this.props.layoutDoc._scrollTop) { + if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) { focusSpeed = 500; if (!this._pdfViewer) this._initialScroll = scrollTo; -- cgit v1.2.3-70-g09d2 From a2ea001c425fb425e4d0cce7c59e77736da86d3d Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 4 Jun 2022 20:45:29 -0400 Subject: fixed searching to highlight in text notes and to unhighlight when search string changes. fixed links to update when text boxes scroll (hackily) --- .../CollectionFreeFormLinkView.tsx | 15 ++++++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 43 ++++++++++++++-------- src/client/views/search/SearchBox.tsx | 3 ++ 3 files changed, 43 insertions(+), 18 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index f5a5492e3..fe849ee48 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { Doc, Field } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { List } from "../../../../fields/List"; -import { NumCast } from "../../../../fields/Types"; +import { Cast, NumCast } from "../../../../fields/Types"; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; import { LinkManager } from "../../../util/LinkManager"; import { SelectionManager } from "../../../util/SelectionManager"; @@ -30,7 +30,14 @@ export class CollectionFreeFormLinkView extends React.Component (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25))); componentDidMount() { - this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform()], + this._anchorDisposer = reaction(() => [ + this.props.A.props.ScreenToLocalTransform(), + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop, + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?._highlights, + this.props.B.props.ScreenToLocalTransform(), + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop, + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?._highlights, + ], action(() => { this._start = Date.now(); this._timeout && clearTimeout(this._timeout); @@ -75,6 +82,8 @@ export class CollectionFreeFormLinkView extends React.Component= 0 && mpx <= 1) linkDoc.anchor1_x = mpx * 100; if (mpy >= 0 && mpy <= 1) linkDoc.anchor1_y = mpy * 100; + if (getComputedStyle(targetAhyperlink).fontSize === "0px") linkDoc.opacity = 0; + else linkDoc.opacity = 1; } if (!targetBhyperlink) { if (linkDoc.linkAutoMove) { @@ -253,7 +262,7 @@ export class CollectionFreeFormLinkView extends React.Component + return !this.props.LinkDocs[0].opacity || !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<> diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 434fccf8d..6004ac271 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -83,7 +83,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp public static blankState = () => EditorState.create(FormattedTextBox.Instance.config); public static Instance: FormattedTextBox; public static LiveTextUndo: UndoManager.Batch | undefined; - static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"]; + static _globalHighlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"]; static _highlightStyleSheet: any = addStyleSheet(); static _bulletStyleSheet: any = addStyleSheet(); static _userStyleSheet: any = addStyleSheet(); @@ -412,6 +412,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } return tr; } + @action + search = (searchString: string, bwd?: boolean, clear: boolean = false) => { + if (clear) this.unhighlightSearchTerms(); + else this.highlightSearchTerms([searchString], bwd!); + return true; + } highlightSearchTerms = (terms: string[], backward: boolean) => { if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) { const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight); @@ -548,35 +554,40 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } updateHighlights = () => { + const highlights = FormattedTextBox._globalHighlights; clearStyleSheetRules(FormattedTextBox._userStyleSheet); - if (FormattedTextBox._highlights.indexOf("Audio Tags") === -1) { + if (highlights.indexOf("Audio Tags") === -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "audiotag", { display: "none" }, ""); } - if (FormattedTextBox._highlights.indexOf("Text from Others") !== -1) { + if (highlights.indexOf("Text from Others") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-remote", { background: "yellow" }); } - if (FormattedTextBox._highlights.indexOf("My Text") !== -1) { + if (highlights.indexOf("My Text") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { background: "moccasin" }); } - if (FormattedTextBox._highlights.indexOf("Todo Items") !== -1) { + if (highlights.indexOf("Todo Items") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UT-" + "todo", { outline: "black solid 1px" }); } - if (FormattedTextBox._highlights.indexOf("Important Items") !== -1) { + if (highlights.indexOf("Important Items") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UT-" + "important", { "font-size": "larger" }); } - if (FormattedTextBox._highlights.indexOf("Disagree Items") !== -1) { + if (highlights.indexOf("Bold Text") !== -1) { + addStyleSheetRule(FormattedTextBox._userStyleSheet, ".formattedTextBox-inner-selected .ProseMirror strong > span", { "font-size": "large" }, ""); + addStyleSheetRule(FormattedTextBox._userStyleSheet, ".formattedTextBox-inner-selected .ProseMirror :not(strong > span)", { "font-size": "0px" }, ""); + } + if (highlights.indexOf("Disagree Items") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UT-" + "disagree", { "text-decoration": "line-through" }); } - if (FormattedTextBox._highlights.indexOf("Ignore Items") !== -1) { + if (highlights.indexOf("Ignore Items") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UT-" + "ignore", { "font-size": "1" }); } - if (FormattedTextBox._highlights.indexOf("By Recent Minute") !== -1) { + if (highlights.indexOf("By Recent Minute") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { opacity: "0.1" }); const min = Math.round(Date.now() / 1000 / 60); numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-min-" + (min - i), { opacity: ((10 - i - 1) / 10).toString() })); setTimeout(this.updateHighlights); } - if (FormattedTextBox._highlights.indexOf("By Recent Hour") !== -1) { + if (highlights.indexOf("By Recent Hour") !== -1) { addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { opacity: "0.1" }); const hr = Math.round(Date.now() / 1000 / 60 / 60); numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-hr-" + (hr - i), { opacity: ((10 - i - 1) / 10).toString() })); @@ -634,17 +645,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); }); const highlighting: ContextMenuProps[] = []; - const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others"]; + const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others", "Bold Text"]; const expertHighlighting = [...noviceHighlighting, "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"]; (Doc.UserDoc().noviceMode ? noviceHighlighting : expertHighlighting).forEach(option => highlighting.push({ - description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { + description: (FormattedTextBox._globalHighlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { e.stopPropagation(); - if (FormattedTextBox._highlights.indexOf(option) === -1) { - FormattedTextBox._highlights.push(option); + if (FormattedTextBox._globalHighlights.indexOf(option) === -1) { + FormattedTextBox._globalHighlights.push(option); } else { - FormattedTextBox._highlights.splice(FormattedTextBox._highlights.indexOf(option), 1); + FormattedTextBox._globalHighlights.splice(FormattedTextBox._globalHighlights.indexOf(option), 1); } + runInAction(() => this.layoutDoc._highlights = FormattedTextBox._globalHighlights.join("")); this.updateHighlights(); }, icon: "expand-arrows-alt" })); @@ -923,6 +935,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._disposers.selected = reaction(() => this.props.isSelected(), action(selected => { + this.layoutDoc._highlights = selected ? FormattedTextBox._globalHighlights.join("") : ""; if (RichTextMenu.Instance?.view === this._editorView && !selected) { RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined); } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 152b7bbcb..48c045b57 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -341,6 +341,9 @@ export class SearchBox extends ViewBoxBaseComponent() { const query = StrCast(this._searchString); Doc.SetSearchQuery(query); + Array.from(this._results.keys()).forEach(doc => + DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true) + ); this._results.clear(); if (query) { -- cgit v1.2.3-70-g09d2 From 98435cb929b1e593bc561c6c56e2db07036aae63 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 5 Jun 2022 00:29:09 -0400 Subject: decreased size of video box ui bar. fixed autoHeight on native scaled text. --- src/client/views/nodes/VideoBox.scss | 23 +++++++++++----------- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index f267407eb..d4cddd65e 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -87,7 +87,6 @@ justify-content: center; display: flex; width: 100%; - height: 38px; visibility: none; opacity: 0; background-color: $dark-gray; @@ -98,7 +97,7 @@ bottom: 0; transition: top 0.5s, width 0.5s, opacity 0.2s, visibility 0s; - height: 38px; + height: 24px; padding: 0 20px; .timecode-controls { @@ -108,7 +107,7 @@ justify-content: center; margin: 0 5px; flex-grow: 2; - font-size: 14px; + font-size: 12px; .timecode { margin: 0 5px; @@ -128,8 +127,8 @@ .videobox-button { margin: 5px; cursor: pointer; - width: 38px; - height: 38px; + width: 24px; + height: 24px; border-radius: 50%; background: $dark-gray; display: flex; @@ -141,8 +140,8 @@ } svg { - width: 25px; - height: 25px; + width: 18px; + height: 18px; } } } @@ -205,21 +204,21 @@ input[type="range"]:focus { input[type="range"]::-webkit-slider-runnable-track { width: 100%; - height: 20px; + height: 18px; cursor: pointer; box-shadow: 0; background: $light-gray; - border-radius: 20px; + border-radius: 18px; } input[type="range"]::-webkit-slider-thumb { box-shadow: 0; border: 0; - height: 26px; - width: 26px; + height: 20px; + width: 20px; border-radius: 20px; background: $medium-blue; cursor: pointer; -webkit-appearance: none; - margin-top: -3px; + margin-top: -1px; } \ No newline at end of file diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 6004ac271..be38342d1 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -873,7 +873,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._disposers.componentHeights = reaction( // set the document height when one of the component heights changes and autoHeight is on () => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, autoHeight: this.autoHeight, marginsHeight: this.autoHeightMargins }), ({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => { - autoHeight && this.props.setHeight?.(marginsHeight + Math.max(sidebarHeight, textHeight)); + autoHeight && this.props.setHeight?.((this.props.scaling?.() || 1) * (marginsHeight + Math.max(sidebarHeight, textHeight))); }, { fireImmediately: true }); this._disposers.links = reaction(() => DocListCast(this.dataDoc.links), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks newLinks => { -- cgit v1.2.3-70-g09d2 From 9acba91baa0ee2ee43106d344392039a2cbd0e46 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 6 Jun 2022 10:16:13 -0400 Subject: fixed range filtering, filtering by string, --- src/client/documents/Documents.ts | 5 ++-- src/client/views/collections/TreeView.tsx | 2 +- src/client/views/nodes/FilterBox.tsx | 33 ++++++++++++++++++++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 ++- 4 files changed, 37 insertions(+), 7 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ecacc9fd5..2ca9cdb71 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1048,11 +1048,10 @@ export namespace DocUtils { const key = docRangeFilters[i]; const min = Number(docRangeFilters[i + 1]); const max = Number(docRangeFilters[i + 2]); - const val = Cast(d[key], "number", null); - if (val < min || val > max) return false; + const val = typeof d[key] === "string" ? (Number(StrCast(d[key])).toString() === StrCast(d[key]) ? Number(StrCast(d[key])) : undefined) : Cast(d[key], "number", null); if (val === undefined) { //console.log("Should 'undefined' pass range filter or not?") - } + } else if (val < min || val > max) return false; } return true; }); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 9de44fb00..23b6a7f72 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -499,7 +499,7 @@ export class TreeView extends React.Component { ; } - return
      { e.preventDefault(); e.stopPropagation(); }}>{this.renderEmbeddedDocument(false, returnFalse)}
    ; // "layout" + return
      { e.preventDefault(); e.stopPropagation(); }}>{this.renderEmbeddedDocument(false, this.props.treeView.props.childDocumentsActive ?? returnFalse)}
    ; // "layout" } get onCheckedClick() { return this.doc.type === DocumentType.COL ? undefined : this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick); } diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index a47e17dfc..28834a202 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -206,7 +206,7 @@ export class FilterBox extends ViewBoxBaseComponent() { facetValues.strings.map(val => { const num = val ? Number(val) : Number.NaN; if (Number.isNaN(num)) { - nonNumbers++; + num && nonNumbers++; } else { minVal = Math.min(num, minVal); maxVal = Math.max(num, maxVal); @@ -216,8 +216,9 @@ export class FilterBox extends ViewBoxBaseComponent() { if (facetHeader === "text" || facetValues.rtFields / allCollectionDocs.length > 0.1) { newFacet = Docs.Create.TextDocument("", { title: facetHeader, system: true, target: targetDoc, _width: 100, _height: 25, _stayInCollection: true, - treeViewExpandedView: "layout", _treeViewOpen: true, _forceActive: true, ignoreClick: true + treeViewExpandedView: "layout", _treeViewOpen: true, _forceActive: true, ignoreClick: true, }); + Doc.GetProto(newFacet).forceActive = true; // required for FormattedTextBox to be able to gain focus since it will never be 'selected' Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox newFacet._textBoxPaddingX = newFacet._textBoxPaddingY = 4; const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`; @@ -238,6 +239,7 @@ export class FilterBox extends ViewBoxBaseComponent() { Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal; const scriptText = `setDocRangeFilter(this?.target, "${facetHeader}", range)`; newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" }); + newFacet.data = ComputedField.MakeFunction(`readNumFacetData(self.target, self, "${FilterBox.targetDocChildKey}", "${facetHeader}")`); } else { newFacet = new Doc(); newFacet.system = true; @@ -401,6 +403,7 @@ export class FilterBox extends ViewBoxBaseComponent() { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} + childDocumentsActive={returnTrue} ContainingCollectionDoc={this.props.ContainingCollectionDoc} ContainingCollectionView={this.props.ContainingCollectionView} PanelWidth={this.props.PanelWidth} @@ -479,6 +482,32 @@ ScriptingGlobals.add(function determineCheckedState(layoutDoc: Doc, facetHeader: } return undefined; }); +ScriptingGlobals.add(function readNumFacetData(layoutDoc: Doc, facetDoc: Doc, childKey: string, facetHeader: string) { + const allCollectionDocs = new Set(); + const activeTabs = DocListCast(layoutDoc[childKey]); + SearchBox.foreachRecursiveDoc(activeTabs, (depth: number, doc: Doc) => allCollectionDocs.add(doc)); + const set = new Set(); + if (facetHeader === "tags") allCollectionDocs.forEach(child => Field.toString(child[facetHeader] as Field).split(":").forEach(key => set.add(key))); + else allCollectionDocs.forEach(child => set.add(Field.toString(child[facetHeader] as Field))); + const facetValues = Array.from(set).filter(v => v); + + let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE; + facetValues.map(val => { + const num = val ? Number(val) : Number.NaN; + if (!Number.isNaN(num)) { + minVal = Math.min(num, minVal); + maxVal = Math.max(num, maxVal); + } + }); + const newFacetField = Doc.LayoutFieldKey(facetDoc); + const ranged = Doc.readDocRangeFilter(layoutDoc, facetHeader); + const extendedMinVal = minVal - Math.min(1, Math.floor(Math.abs(maxVal - minVal) * .1)); + const extendedMaxVal = Math.max(minVal + 1, maxVal + Math.min(1, Math.ceil(Math.abs(maxVal - minVal) * .05))); + facetDoc[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0]; + facetDoc[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1]; + Doc.GetProto(facetDoc)[newFacetField + "-minThumb"] = extendedMinVal; + Doc.GetProto(facetDoc)[newFacetField + "-maxThumb"] = extendedMaxVal; +}) ScriptingGlobals.add(function readFacetData(layoutDoc: Doc, childKey: string, facetHeader: string) { const allCollectionDocs = new Set(); const activeTabs = DocListCast(layoutDoc[childKey]); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bf3c01d1f..7a500ac88 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -283,6 +283,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.dataDoc[this.props.fieldKey] = undefined; this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data))); this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; // mark the data field as not being split from any template it might have + ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText }); unchanged = false; } this._applyingChange = ""; @@ -1248,6 +1249,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } onPointerDown = (e: React.PointerEvent): void => { + if (this.Document.forceActive) e.stopPropagation(); this.tryUpdateScrollHeight(); // if a doc a fitwidth doc is being viewed in different context (eg freeform & lightbox), then it will have conflicting heights. so when the doc is clicked on, we want to make sure it has the appropriate height for the selected view. if ((e.target as any).tagName === "AUDIOTAG") { e.preventDefault(); @@ -1641,7 +1643,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } render() { TraceMobx(); - const selected = this.props.isSelected(); + const selected = this.props.isSelected() || this.Document.forceActive; const active = this.props.isContentActive(); const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; -- cgit v1.2.3-70-g09d2 From 42c7ca38a77ede7171f628346117da191bbf115d Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 6 Jun 2022 14:32:18 -0400 Subject: fixed scripting repl transformer error. fixed not being able to edit someone else's text in selfEdit mode --- src/client/views/ScriptingRepl.tsx | 3 ++- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index 2b045aa6c..4fecfa4d9 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -123,8 +123,9 @@ export class ScriptingRepl extends React.Component { let stopProp = true; switch (e.key) { case "Enter": { + e.stopPropagation(); const docGlobals: { [name: string]: any } = {}; - DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`d${i}`] = dv.props.Document); + Array.from(DocumentManager.Instance.DocumentViews).forEach((dv, i) => docGlobals[`d${i}`] = dv.props.Document); const globals = ScriptingGlobals.makeMutableGlobalsCopy(docGlobals); const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer(), globals }); if (!script.compiled) { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 7a500ac88..2ae9acfc8 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1504,9 +1504,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._rules!.EnteringStyle = false; } e.stopPropagation(); - for (var i = state.selection.from; i < state.selection.to; i++) { + for (var i = state.selection.from; i <= state.selection.to; i++) { const node = state.doc.resolve(i); - if (node?.marks?.().some(mark => mark.type === schema.marks.user_mark && + if (state.doc.content.size - 1 > i && node?.marks?.().some(mark => mark.type === schema.marks.user_mark && mark.attrs.userid !== Doc.CurrentUserEmail) && [AclAugment, AclSelfEdit].includes(GetEffectiveAcl(this.rootDoc))) { e.preventDefault(); -- cgit v1.2.3-70-g09d2 From c29b7151e390f8e5b2090a6e3cd858249703bea7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 6 Jun 2022 20:55:52 -0400 Subject: removed sort ui from pres box tree view. made expanding/closing text hierarchies simpler (not sure what it might break though). --- src/client/views/collections/TreeView.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a85b2a0d4..befd2020c 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -471,7 +471,7 @@ export class TreeView extends React.Component { const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; let downX = 0, downY = 0; return <> - {!docs?.length ? (null) :
    + {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? (null) :
    {sortings[sorting]?.label}
    }