aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/DocComponent.tsx2
-rw-r--r--src/client/views/DocumentButtonBar.tsx6
-rw-r--r--src/client/views/DocumentDecorations.tsx60
-rw-r--r--src/client/views/InkingStroke.tsx2
-rw-r--r--src/client/views/LightboxView.tsx9
-rw-r--r--src/client/views/MainView.tsx12
-rw-r--r--src/client/views/MarqueeAnnotator.tsx30
-rw-r--r--src/client/views/PreviewCursor.tsx2
-rw-r--r--src/client/views/PropertiesButtons.tsx38
-rw-r--r--src/client/views/StyleProvider.tsx26
-rw-r--r--src/client/views/TemplateMenu.tsx1
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx6
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx50
-rw-r--r--src/client/views/collections/CollectionSubView.tsx19
-rw-r--r--src/client/views/collections/CollectionView.tsx5
-rw-r--r--src/client/views/collections/TabDocView.tsx4
-rw-r--r--src/client/views/collections/TreeView.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx33
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx7
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx2
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx6
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx16
-rw-r--r--src/client/views/nodes/ColorBox.tsx5
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx4
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx10
-rw-r--r--src/client/views/nodes/DocumentView.tsx122
-rw-r--r--src/client/views/nodes/EquationBox.scss0
-rw-r--r--src/client/views/nodes/EquationBox.tsx82
-rw-r--r--src/client/views/nodes/FieldView.tsx3
-rw-r--r--src/client/views/nodes/FilterBox.tsx5
-rw-r--r--src/client/views/nodes/FontIconBox.tsx1
-rw-r--r--src/client/views/nodes/ImageBox.tsx11
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx1
-rw-r--r--src/client/views/nodes/LabelBox.tsx8
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx2
-rw-r--r--src/client/views/nodes/VideoBox.tsx13
-rw-r--r--src/client/views/nodes/WebBox.tsx11
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx12
-rw-r--r--src/client/views/nodes/formattedText/EquationView.tsx75
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx511
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx2
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts34
-rw-r--r--src/client/views/nodes/formattedText/nodes_rts.ts13
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx4
-rw-r--r--src/client/views/pdf/PDFViewer.tsx6
-rw-r--r--src/client/views/search/SearchBox.tsx2
47 files changed, 640 insertions, 653 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index ef1228976..128ba858f 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -11,7 +11,7 @@ import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail }
/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
-interface DocComponentProps {
+export interface DocComponentProps {
Document: Doc;
LayoutTemplate?: () => Opt<Doc>;
LayoutTemplateString?: string;
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 209e750d6..a9cd7b4a9 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -312,7 +312,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
return false;
}
- _ref = React.createRef<TemplateMenu>();
+ _ref = React.createRef<HTMLDivElement>();
@observable _tooltipOpen: boolean = false;
@computed
get templateButton() {
@@ -321,11 +321,11 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
return !view0 ? (null) :
<Tooltip title={<div className="dash-tooltip">Tap to Customize Layout. Drag an embeddable alias</div>} open={this._tooltipOpen} onClose={action(() => this._tooltipOpen = false)} placement="bottom">
<div className="documentButtonBar-linkFlyout" ref={this._dragRef}
- onPointerEnter={action(() => !(this._ref.current as any as HTMLElement)?.getBoundingClientRect().width && (this._tooltipOpen = true))} >
+ onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))} >
<Flyout anchorPoint={anchorPoints.LEFT_TOP} onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
content={!this._aliasDown ? (null) :
- <TemplateMenu ref={this._ref} docViews={views.filter(v => v).map(v => v as DocumentView)} />}>
+ <div ref={this._ref}> <TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} /></div>}>
<div className={"documentButtonBar-linkButton-empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} >
{<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
</div>
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2391a21e6..1e3c0ba92 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -292,10 +292,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
this._rotateUndo = undefined;
}
-
-
- _initialAutoHeight = false;
- _dragHeights = new Map<Doc, number>();
+ _dragHeights = new Map<Doc, { start: number, lowest: number }>();
@action
onPointerDown = (e: React.PointerEvent): void => {
@@ -323,12 +320,9 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
}
this._snapX = e.pageX;
this._snapY = e.pageY;
- this._initialAutoHeight = true;
DragManager.docsBeingDragged = SelectionManager.Views().map(dv => dv.rootDoc);
- SelectionManager.Views().map(dv => {
- this._dragHeights.set(dv.layoutDoc, NumCast(dv.layoutDoc._height));
- dv.layoutDoc._delayAutoHeight = dv.layoutDoc._height;
- });
+ SelectionManager.Views().map(dv =>
+ this._dragHeights.set(dv.layoutDoc, { start: NumCast(dv.layoutDoc._height), lowest: NumCast(dv.layoutDoc._height) }));
}
onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
@@ -369,8 +363,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
let dX = 0, dY = 0, dW = 0, dH = 0;
const unfreeze = () =>
SelectionManager.Views().forEach(action((element: DocumentView) =>
- ((element.rootDoc.type === DocumentType.RTF ||
- element.rootDoc.type === DocumentType.COMPARISON ||
+ ((element.rootDoc.type === DocumentType.COMPARISON ||
(element.rootDoc.type === DocumentType.WEB && Doc.LayoutField(element.rootDoc) instanceof HtmlField))
&& Doc.NativeHeight(element.layoutDoc)) && element.toggleNativeDimensions()));
switch (this._resizeHdlId) {
@@ -421,8 +414,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
if (e.ctrlKey && !Doc.NativeHeight(docView.props.Document)) docView.toggleNativeDimensions();
if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
const doc = Document(docView.rootDoc);
- let nwidth = docView.nativeWidth;
- let nheight = docView.nativeHeight;
+ const nwidth = docView.nativeWidth;
+ const nheight = docView.nativeHeight;
const width = (doc._width || 0);
let height = (doc._height || (nheight / nwidth * width));
height = !height || isNaN(height) ? 20 : height;
@@ -431,7 +424,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
if (nwidth / nheight !== width / height && !dragBottom) {
height = nheight / nwidth * width;
}
- if (e.ctrlKey || (!dragBottom || !docView.layoutDoc._fitWidth)) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
+ if (e.ctrlKey && !dragBottom) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
else dW = dH * nwidth / nheight;
}
@@ -441,10 +434,6 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
doc.x = (doc.x || 0) + dX * (actualdW - width);
doc.y = (doc.y || 0) + dY * (actualdH - height);
const fixedAspect = (nwidth && nheight);
- if (fixedAspect && (!nwidth || !nheight)) {
- doc._nativeWidth = nwidth = doc._width || 0;
- doc._nativeHeight = nheight = doc._height || 0;
- }
if (e.ctrlKey && [DocumentType.IMG, DocumentType.SCREENSHOT, DocumentType.VID].includes(doc.type as DocumentType)) {
dW !== 0 && runInAction(() => {
const dataDoc = doc[DataSym];
@@ -454,29 +443,33 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
Doc.SetNativeHeight(dataDoc, nh + (dW > 0 ? 10 : -10) * nh / nw);
});
}
- else if (nwidth > 0 && nheight > 0) {
- if (Math.abs(dW) > Math.abs(dH) || dragRight) {
- if (!fixedAspect || (dragRight && e.ctrlKey)) {
+ else if (fixedAspect) {
+ if ((Math.abs(dW) > Math.abs(dH) && (!dragBottom || !e.ctrlKey)) || dragRight) {
+ if (dragRight && e.ctrlKey) {
doc._nativeWidth = actualdW / (doc._width || 1) * Doc.NativeWidth(doc);
+ } else {
+ if (!doc._fitWidth) doc._height = nheight / nwidth * actualdW;
+ else if (!e.ctrlKey) doc._height = actualdH;
}
doc._width = actualdW;
- if (fixedAspect && !doc._fitWidth) doc._height = nheight / nwidth * doc._width;
- else if (!fixedAspect || !e.ctrlKey) doc._height = actualdH;
}
else {
- if (!fixedAspect || (dragBottom && (e.ctrlKey || docView.layoutDoc._fitWidth))) {
+ if (dragBottom && (e.ctrlKey || docView.layoutDoc._fitWidth)) { // frozen web pages and others that fitWidth can't grow horizontally to match a vertical resize so the only choice is to change the nativeheight even if the ctrl key isn't used
doc._nativeHeight = actualdH / (doc._height || 1) * Doc.NativeHeight(doc);
+ } else {
+ if (!doc._fitWidth) doc._width = nwidth / nheight * actualdH;
+ else if (!e.ctrlKey) doc._width = actualdW;
}
doc._height = actualdH;
- if (fixedAspect && !doc._fitWidth) doc._width = nwidth / nheight * doc._height;
- else if (!fixedAspect || !e.ctrlKey) doc._width = actualdW;
}
} else {
dW && (doc._width = actualdW);
dH && (doc._height = actualdH);
- dH && this._initialAutoHeight && (doc._autoHeight = this._initialAutoHeight = false);
+ dH && (doc._autoHeight = false);
}
}
+ const val = this._dragHeights.get(docView.layoutDoc);
+ if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) });
}));
return false;
}
@@ -484,11 +477,12 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
@action
onPointerUp = (e: PointerEvent): void => {
SelectionManager.Views().map(dv => {
- if (NumCast(dv.layoutDoc._delayAutoHeight) < this._dragHeights.get(dv.layoutDoc)!) {
- dv.nativeWidth > 0 && Doc.toggleNativeDimensions(dv.layoutDoc, dv.ContentScale(), dv.props.PanelWidth(), dv.props.PanelHeight());
- dv.layoutDoc._autoHeight = true;
+ const hgts = this._dragHeights.get(dv.layoutDoc);
+ if (hgts && hgts.lowest < hgts.start && hgts.lowest <= 20) {
+ dv.effectiveNativeWidth > 0 && Doc.toggleNativeDimensions(dv.layoutDoc, dv.ContentScale(), dv.props.PanelWidth(), dv.props.PanelHeight());
+ if (dv.layoutDoc._autoHeight) dv.layoutDoc._autoHeight = false;
+ setTimeout(() => dv.layoutDoc._autoHeight = true);
}
- dv.layoutDoc._delayAutoHeight = undefined;
});
this._resizeHdlId = "";
this.Interacting = false;
@@ -617,8 +611,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
}}>
{closeIcon}
- {titleArea}
- {seldoc.props.hideResizeHandles ? (null) :
+ {seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea}
+ {seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) :
<>
{SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) :
<Tooltip key="i" title={<div className="dash-tooltip">{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}</div>} placement="top">
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 19b23af13..462d78865 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -233,7 +233,7 @@ export function SetActiveFillColor(value: string) { ActiveInkPen() && (ActiveInk
export function SetActiveArrowStart(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); }
export function SetActiveArrowEnd(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); }
export function SetActiveDash(dash: string): void { !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); }
-export function ActiveInkPen(): Doc { return Cast(Doc.UserDoc().activeInkPen, Doc, null); }
+export function ActiveInkPen(): Doc { return Doc.UserDoc(); }
export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, "black"); }
export function ActiveFillColor(): string { return StrCast(ActiveInkPen()?.activeFillColor, ""); }
export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ""); }
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index babc518ff..3fc72c45c 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -46,7 +46,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
this._docFilters && (this._docFilters.length = 0);
this._future = this._history = [];
} else {
- TabDocView.PinDoc(doc, { hidePresBox: true });
+ //TabDocView.PinDoc(doc, { hidePresBox: true });
this._history ? this._history.push({ doc, target }) : this._history = [{ doc, target }];
if (doc !== LightboxView.LightboxDoc) {
this._savedState = {
@@ -247,6 +247,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
ContainingCollectionDoc={undefined}
renderDepth={0} />
</div>
+
{this.navBtn(0, undefined, this.props.PanelHeight / 2 - 12.50, "chevron-left",
() => LightboxView.LightboxDoc && LightboxView._history?.length ? "" : "none", e => {
e.stopPropagation();
@@ -258,6 +259,10 @@ export class LightboxView extends React.Component<LightboxViewProps> {
LightboxView.Next();
})}
<LightboxTourBtn navBtn={this.navBtn} future={this.future} stepInto={this.stepInto} tourMap={this.tourMap} />
+ <div className="lightboxView-navBtn" title={"toggle fit width"} style={{ position: "absolute", right: 10, top: 10, color: "white" }}
+ onClick={e => { e.stopPropagation(); LightboxView.LightboxDoc!._fitWidth = !LightboxView.LightboxDoc!._fitWidth }}>
+ <FontAwesomeIcon icon={"arrows-alt-h"} size="2x" />
+ </div>
</div>;
}
}
@@ -276,6 +281,6 @@ export class LightboxTourBtn extends React.Component<LightboxTourBtnProps> {
this.props.stepInto();
},
StrCast(this.props.tourMap()?.lastElement()?.TourMap)
- )
+ );
}
} \ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6010eb518..c356aa0f5 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -102,7 +102,7 @@ export class MainView extends React.Component {
}
new InkStrokeProperties();
this._sidebarContent.proto = undefined;
- DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_delayAutoHeight", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
+ DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // 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)));
@@ -230,7 +230,7 @@ export class MainView extends React.Component {
createNewPresentation = async () => {
if (!await this.userDoc.myPresentations) {
this.userDoc.myPresentations = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "PRESENTATION TRAILS", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true, system: true
+ title: "PRESENTATION TRAILS", _height: 100, _forceActive: true, boxShadow: "0 0", _lockedPosition: true, treeViewOpen: true, system: true
}));
}
const pres = Docs.Create.PresDocument(new List<Doc>(),
@@ -321,8 +321,8 @@ export class MainView extends React.Component {
<div className={`styleProvider-treeView-hide${doc.hidden ? "-active" : ""}`} onClick={e => toggleField(e, doc, "hidden")}>
<FontAwesomeIcon icon={doc.hidden ? "eye-slash" : "eye"} size="sm" />
</div>
- <div className={`styleProvider-treeView-lock${doc.lockedPosition ? "-active" : ""}`} onClick={e => toggleField(e, doc, "lockedPosition")}>
- <FontAwesomeIcon icon={doc.lockedPosition ? "lock" : "unlock"} size="sm" />
+ <div className={`styleProvider-treeView-lock${doc._lockedPosition ? "-active" : ""}`} onClick={e => toggleField(e, doc, "_lockedPosition")}>
+ <FontAwesomeIcon icon={doc._lockedPosition ? "lock" : "unlock"} size="sm" />
</div>
</>;
}
@@ -484,6 +484,7 @@ export class MainView extends React.Component {
DataDoc={undefined}
fieldKey={"data"}
dropAction={"alias"}
+ setHeight={returnFalse}
parentActive={returnFalse}
styleProvider={DefaultStyleProvider}
layerProvider={undefined}
@@ -554,6 +555,7 @@ export class MainView extends React.Component {
isSelected={returnTrue}
active={returnTrue}
select={returnTrue}
+ setHeight={returnFalse}
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
@@ -591,6 +593,7 @@ export class MainView extends React.Component {
styleProvider={undefined}
isSelected={returnFalse}
select={returnFalse}
+ setHeight={returnFalse}
rootSelected={returnFalse}
renderDepth={0}
parentActive={returnFalse}
@@ -663,6 +666,7 @@ export class MainView extends React.Component {
select={returnFalse}
rootSelected={returnFalse}
renderDepth={0}
+ setHeight={returnFalse}
layerProvider={undefined}
styleProvider={undefined}
addDocTab={returnFalse}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 6e8f9a2df..f03e1dd9d 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -64,27 +64,24 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
* This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation.
* It also initiates a Drag/Drop interaction to place the text annotation.
*/
- AnchorMenu.Instance.StartDrag = action(async (e: PointerEvent, ele: HTMLElement) => {
+ AnchorMenu.Instance.StartDrag = action((e: PointerEvent, ele: HTMLElement) => {
e.preventDefault();
e.stopPropagation();
- const targetCreator = () => {
- const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.props.rootDoc.title, 0, 0, 100, 100);
- FormattedTextBox.SelectOnLoad = target[Id];
- return target;
- };
- const anchorCreator = () => {
- const annoDoc = this.highlight("rgba(173, 216, 230, 0.75)"); // hyperlink color
- annoDoc.isLinkButton = true; // prevents link button from showing up --- maybe not a good thing?
+ const sourceAnchorCreator = () => {
+ const annoDoc = this.highlight("rgba(173, 216, 230, 0.75)", true); // hyperlink color
this.props.addDocument(annoDoc);
return annoDoc;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.rootDoc, anchorCreator, targetCreator), e.pageX, e.pageY, {
+ const targetCreator = (annotationOn: Doc | undefined) => {
+ const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.props.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn);
+ FormattedTextBox.SelectOnLoad = target[Id];
+ return target;
+ };
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.rootDoc, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
dragComplete: e => {
- if (!e.aborted && e.annoDragData && e.annoDragData.annotationDocument && e.annoDragData.dropDocument && !e.linkDocument) {
- e.linkDocument = DocUtils.MakeLink({ doc: e.annoDragData.annotationDocument }, { doc: e.annoDragData.dropDocument }, "Annotation");
- e.annoDragData.annotationDocument.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.rootDoc;
+ if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
+ e.annoDragData.linkSourceDoc.isPushpin = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
}
- e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument
}
});
});
@@ -141,11 +138,12 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
}
}
@action
- highlight = (color: string) => {
+ highlight = (color: string, isLinkButton: boolean) => {
// creates annotation documents for current highlights
const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DataSym]);
const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color);
annotationDoc && this.props.addDocument(annotationDoc);
+ annotationDoc && (annotationDoc.isLinkButton = isLinkButton);
return annotationDoc as Doc ?? undefined;
}
@@ -197,7 +195,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
if (AnchorMenu.Instance.Highlighting) {// when highlighter has been toggled when menu is pinned, we auto-highlight immediately on mouse up
- this.highlight("rgba(245, 230, 95, 0.75)"); // yellowish highlight color for highlighted text (should match AnchorMenu's highlight color)
+ this.highlight("rgba(245, 230, 95, 0.75)", false); // yellowish highlight color for highlighted text (should match AnchorMenu's highlight color)
}
} else {
runInAction(() => this._width = this._height = 0);
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 5b57ad19f..679a4b81e 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -79,7 +79,7 @@ export class PreviewCursor extends React.Component<{}> {
else {
// creates text document
FormattedTextBox.PasteOnLoad = e;
- UndoManager.RunInBatch(() => PreviewCursor._addLiveTextDoc(CurrentUserUtils.GetNewTextDoc("-pasted text-", newPoint[0], newPoint[1], 500)), "paste");
+ UndoManager.RunInBatch(() => PreviewCursor._addLiveTextDoc(CurrentUserUtils.GetNewTextDoc("-pasted text-", newPoint[0], newPoint[1], 500, undefined, undefined, undefined, 750)), "paste");
}
} else
//pasting in images
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 8ad5f3f2b..e418a6f3c 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -194,12 +194,12 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get lockButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<div className="dash-tooltip">{`${this.selectedDoc?.lockedPosition ? "Unlock" : "Lock"} Position`}</div>} placement="top">
+ title={<div className="dash-tooltip">{`${this.selectedDoc?._lockedPosition ? "Unlock" : "Lock"} Position`}</div>} placement="top">
<div>
- <div className={`propertiesButtons-linkButton-empty toggle-${targetDoc.lockedPosition ? "on" : "off"}`} onPointerDown={this.onLock} >
+ <div className={`propertiesButtons-linkButton-empty toggle-${targetDoc._lockedPosition ? "on" : "off"}`} onPointerDown={this.onLock} >
<FontAwesomeIcon className="documentdecorations-icon" size="lg"
- color={this.selectedDoc?.lockedPosition ? "black" : "white"}
- icon={this.selectedDoc?.lockedPosition ? "unlock" : "lock"} />
+ color={this.selectedDoc?._lockedPosition ? "black" : "white"}
+ icon={this.selectedDoc?._lockedPosition ? "unlock" : "lock"} />
</div>
<div className="propertiesButtons-title"
>Position </div>
@@ -260,7 +260,10 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@undoBatch
@action
setCaption = () => {
- SelectionManager.Views().forEach(dv => dv.rootDoc._showCaption = dv.rootDoc._showCaption === undefined ? "caption" : undefined);
+ SelectionManager.Views().forEach(dv => {
+ dv.rootDoc._showCaption = dv.rootDoc._showCaption === undefined ? "caption" : undefined;
+ console.log("caption = " + dv.rootDoc._showCaption);
+ });
}
@computed
@@ -427,6 +430,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
}
@action @undoBatch
+ changeFitWidth = () => {
+ if (this.selectedDoc) {
+ if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => dv.rootDoc._fitWidth = !dv.rootDoc._fitWidth);
+ else this.selectedDoc._fitWidth = !this.selectedDoc._fitWidth;
+ }
+ }
+
+ @action @undoBatch
changeClusters = () => {
if (this.selectedDoc) {
if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => dv.rootDoc._useClusters = !dv.rootDoc._useClusters);
@@ -448,6 +459,20 @@ export class PropertiesButtons extends React.Component<{}, {}> {
</Tooltip>;
}
+ @computed
+ get fitWidthButton() {
+ const targetDoc = this.selectedDoc;
+ return !targetDoc ? (null) : <Tooltip
+ title={<><div className="dash-tooltip">{this.selectedDoc?._fitWidth ? "Stop Fitting Width" : "Fit Width"}</div></>} placement="top">
+ <div>
+ <div className={`propertiesButtons-linkButton-empty toggle-${targetDoc._fitWidth ? "on" : "off"}`} onPointerDown={this.changeFitWidth}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon="arrows-alt-h" size="lg" />
+ </div>
+ <div className="propertiesButtons-title"> {this.selectedDoc?._fitWidth ? "unfit" : "fit"} </div>
+ </div>
+ </Tooltip>;
+ }
+
@undoBatch
@action
private makeMask = () => {
@@ -521,6 +546,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-button" style={{ display: !isFreeForm && !isText ? "none" : "" }}>
{this.fitContentButton}
</div>
+ <div className="propertiesButtons-button">
+ {this.fitWidthButton}
+ </div>
<div className="propertiesButtons-button" style={{ display: !isInk ? "none" : "" }}>
{this.maskButton}
</div>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index e272fbaa6..91667fd64 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -47,9 +47,9 @@ function darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkSc
function toggleBackground(doc: Doc) {
UndoManager.RunInBatch(() => runInAction(() => {
- const layers = StrListCast(doc.layers);
+ const layers = StrListCast(doc._layerTags);
if (!layers.includes(StyleLayers.Background)) {
- if (!layers.length) doc.layers = new List<string>([StyleLayers.Background]);
+ if (!layers.length) doc._layerTags = new List<string>([StyleLayers.Background]);
else layers.push(StyleLayers.Background);
}
else layers.splice(layers.indexOf(StyleLayers.Background), 1);
@@ -68,16 +68,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
const selected = property.includes(":selected");
const isCaption = property.includes(":caption");
const isAnchor = property.includes(":anchor");
- const isFooter = property.includes(":footer");
-
- const isBackground = () => StrListCast(doc?.layers).includes(StyleLayers.Background);
+ const isAnnotated = property.includes(":annotated");
+ const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
switch (property.split(":")[0]) {
case StyleProp.TreeViewIcon: return doc ? Doc.toIcon(doc) : "question";
case StyleProp.DocContents: return undefined;
- case StyleProp.WidgetColor: return darkScheme() ? "lightgrey" : "dimgrey";
+ case StyleProp.WidgetColor: return isAnnotated ? "lightBlue" : darkScheme() ? "lightgrey" : "dimgrey";
case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
case StyleProp.HideLinkButton: return isAnchor || props?.dontRegisterView || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));
case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle,
@@ -90,15 +89,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
const colsum = (col.red() + col.green() + col.blue());
if (colsum / col.alpha() > 400 || col.alpha() < 0.25) return "black";
return "white";
- case StyleProp.Hidden: return BoolCast(doc?._hidden, BoolCast(doc?.hidden));
- case StyleProp.BorderRounding: return StrCast(doc?._borderRounding, StrCast(doc?.borderRounding));
+ case StyleProp.Hidden: return BoolCast(doc?._hidden);
+ case StyleProp.BorderRounding: return StrCast(doc?._borderRounding);
case StyleProp.TitleHeight: return 15;
case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry].includes(doc?._viewType as any) || doc?.type === DocumentType.RTF) && doc?._showTitle && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0;
case StyleProp.BackgroundColor: {
if (isAnchor && docProps) return "transparent";
if (isCaption) return "rgba(0,0,0 ,0.4)";
if (Doc.UserDoc().renderStyle === "comic") return "transparent";
- let docColor: Opt<string> = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor));
+ let docColor: Opt<string> = StrCast(doc?._backgroundColor);
if (!docProps) {
if (MainView.Instance.LastButton === doc) return darkScheme() ? "dimgrey" : "lightgrey";
switch (doc?.type) {
@@ -115,6 +114,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
case DocumentType.FILTER: docColor = docColor || (darkScheme() ? "#2d2d2d" : "rgba(105, 105, 105, 0.432)"); break;
case DocumentType.INK: docColor = doc?.isInkMask ? "rgba(0,0,0,0.7)" : undefined; break;
case DocumentType.SLIDER: break;
+ case DocumentType.EQUATION: docColor = docColor || "transparent"; break;
case DocumentType.LABEL: docColor = docColor || (doc.annotationOn !== undefined ? "rgba(128, 128, 128, 0.18)" : undefined); break;
case DocumentType.BUTTON: docColor = docColor || (darkScheme() ? "#2d2d2d" : "lightgray"); break;
case DocumentType.LINK: return "transparent";
@@ -163,7 +163,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
if (isAnchor && docProps) return "none";
if (props?.pointerEvents === "none") return "none";
const layer = doc && props?.layerProvider?.(doc);
- if (opacity() === 0 || doc?.type === DocumentType.INK || doc?.isInkMask) return "none";
+ if (opacity() === 0 || (doc?.type === DocumentType.INK && !docProps?.treeViewDoc) || doc?.isInkMask) return "none";
if (layer === false && !selected && !SnappingManager.GetIsDragging()) return "none";
if (doc?.type !== DocumentType.INK && layer === true) return "all";
return undefined;
@@ -271,15 +271,15 @@ export function DefaultLayerProvider(thisDoc: Doc) {
if (assign) {
const activeLayer = StrCast(thisDoc?.activeLayer);
if (activeLayer) {
- const layers = Cast(doc.layers, listSpec("string"), []);
+ const layers = Cast(doc._layerTags, listSpec("string"), []);
if (layers.length && !layers.includes(activeLayer)) layers.push(activeLayer);
- else if (!layers.length) doc.layers = new List<string>([activeLayer]);
+ else if (!layers.length) doc._layerTags = new List<string>([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.layers);
+ const layers = StrListCast(doc._layerTags);
if (!layers.length && !thisDoc?.activeLayer) return true;
if (layers.includes(StrCast(thisDoc?.activeLayer))) return true;
return false;
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index d2e0cb265..f39d5ee4c 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -140,6 +140,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
rootSelected={returnFalse}
onCheckedClick={this.scriptField}
onChildClick={this.scriptField}
+ setHeight={returnFalse}
dropAction={undefined}
active={returnTrue}
parentActive={returnFalse}
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 4bdd39194..077e50dd2 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -16,6 +16,8 @@ import { EditableView } from "../EditableView";
import { CollectionStackingView } from "./CollectionStackingView";
import "./CollectionStackingView.scss";
import { SnappingManager } from "../../util/SnappingManager";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
+import { Id } from "../../../fields/FieldSymbols";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -142,8 +144,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
if (!value && !forceEmptyNote) return false;
this._createAliasSelected = false;
const key = StrCast(this.props.parent.props.Document._pivotField);
- const newDoc = Docs.Create.TextDocument(value, { _autoHeight: true, _width: 200, title: value });
+ const newDoc = Docs.Create.TextDocument("", { _autoHeight: true, _width: 200, title: value });
const onLayoutDoc = this.onLayoutDoc(key);
+ FormattedTextBox.SelectOnLoad = newDoc[Id];
+ FormattedTextBox.SelectOnLoadChar = value;
(onLayoutDoc ? newDoc : newDoc[DataSym])[key] = this.getValue(this.props.heading);
const docs = this.props.parent.childDocList;
return docs ? (docs.splice(0, 0, newDoc) ? true : false) : this.props.parent.props.addDocument?.(newDoc) || false;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 504cf32a0..a265045b8 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -553,7 +553,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
</div>;
return <div className={"collectionSchemaView" + (this.props.Document._searchDoc ? "-searchContainer" : "-container")}
style={{
- overflow: this.props.overflow === true ? "scroll" : undefined, backgroundColor: "white",
+ overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white",
pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 77046f5ea..7152f4272 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -29,6 +29,7 @@ import "./CollectionStackingView.scss";
import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
import { CollectionSubView } from "./CollectionSubView";
import { CollectionViewType } from "./CollectionView";
+import { LightboxView } from "../LightboxView";
const _global = (window /* browser */ || global /* node */) as any;
type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
@@ -140,8 +141,10 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
() => this.pivotField,
() => this.layoutDoc._columnHeaders = new List()
);
- this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, this.forceAutoHeight);
+ this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight,
+ () => this.props.setHeight(this.headerMargin + this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0)));
}
+
componentWillUnmount() {
super.componentWillUnmount();
this._pivotFieldDisposer?.();
@@ -202,10 +205,10 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc;
const height = () => this.getDocHeight(doc);
- let dref: Opt<HTMLDivElement>;
+ let dref: Opt<DocumentView>;
const stackedDocTransform = () => this.getDocTransform(doc, dref);
this._docXfs.push({ stackedDocTransform, width, height });
- return <DocumentView ref={r => dref = r?.ContentDiv ? r.ContentDiv : undefined}
+ return <DocumentView ref={r => dref = r || undefined}
Document={doc}
DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])}
renderDepth={this.props.renderDepth + 1}
@@ -245,18 +248,24 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
/>;
}
+ getDocTransform(doc: Doc, dref?: DocumentView) {
+ const y = this._scroll; // required for document decorations to update when the text box container is scrolled
+ const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
+ // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
+ return new Transform(- translateX - (dref?.centeringX || 0), - translateY - (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale * (this.props.scaling?.() || 1));
+ }
getDocWidth(d?: Doc) {
if (!d) return 0;
- const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
- const nw = Doc.NativeWidth(layoutDoc);
- return Math.min(nw && !this.layoutDoc._columnsFill ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+ const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const nw = Doc.NativeWidth(childLayoutDoc) || (childLayoutDoc._fitWidth ? 0 : d[WidthSym]());
+ return Math.min(nw && !this.layoutDoc._columnsFill ? (this.props.scaling?.() || 1) * d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
}
getDocHeight(d?: Doc) {
if (!d) return 0;
const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc;
const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
- const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc);
- const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc);
+ const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (childLayoutDoc._fitWidth ? 0 : d[WidthSym]());
+ const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (childLayoutDoc._fitWidth ? 0 : d[HeightSym]());
let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
if (!this.layoutDoc._columnsFill) wid = Math.min(wid, childLayoutDoc[WidthSym]());
const hllimit = NumCast(this.layoutDoc.childLimitHeight, -1);
@@ -266,7 +275,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
return Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, wid * aspect);
}
return childLayoutDoc._fitWidth ?
- (!nh ? this.props.PanelHeight() - 2 * this.yMargin :
+ (!nh ? Math.min(NumCast(childLayoutDoc.height, 10000) * (this.props.scaling?.() || 1), this.props.PanelHeight() - 2 * this.yMargin) :
Math.min(wid * nh / (nw || 1), this.layoutDoc._autoHeight ? 100000 : this.props.PanelHeight() - 2 * this.yMargin)) :
Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, Math.max(20, childLayoutDoc[HeightSym]()));
}
@@ -359,8 +368,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const cols = () => this.isStackingView ? 1 : Math.max(1, Math.min(this.filteredChildren.length,
Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
return <CollectionStackingViewFieldColumn
- unobserveHeight={(ref) => this.refList.splice(this.refList.indexOf(ref), 1)}
- observeHeight={(ref) => {
+ unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
+ observeHeight={ref => {
if (ref) {
this.refList.push(ref);
const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
@@ -369,10 +378,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const height = this.headerMargin +
Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
Math.max(...this.refList.map(r => NumCast(Doc.Layout(doc)._viewScale, 1) * Number(getComputedStyle(r).height.replace("px", "")))));
- if (this.props.isAnnotationOverlay) {
- doc[this.props.fieldKey + "-height"] = height;
- } else {
- Doc.Layout(doc)._height = height * NumCast(Doc.Layout(doc)._viewScale, 1);
+ if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
+ this.props.setHeight(height * NumCast(Doc.Layout(doc)._viewScale, 1));
}
}
}));
@@ -392,17 +399,6 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
/>;
}
- getDocTransform(doc: Doc, dref?: HTMLDivElement) {
- const y = this._scroll; // required for document decorations to update when the text box container is scrolled
- const { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
- return new Transform(-translateX, -translateY, 1).scale(this.props.ScreenToLocalTransform().Scale);
- }
-
- forceAutoHeight = () => {
- const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
- Doc.Layout(doc)._height = this.headerMargin + this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
- }
-
sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => {
const key = this.pivotField;
let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
@@ -422,7 +418,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
this.observer = new _global.ResizeObserver(action((entries: any) => {
if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
- Doc.Layout(doc)._height = this.headerMargin + Math.max(height, NumCast(doc[this.props.fieldKey + "-height"]));
+ this.props.setHeight(this.headerMargin + height);
}
}));
this.observer.observe(ref);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a9438f8f7..639650b94 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -224,11 +224,14 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
e.stopPropagation();
return added;
}
- else if (de.complete.annoDragData && (!this.props.isAnnotationOverlay || de.complete.annoDragData.dragDocument === this.props.Document)) {
- e.stopPropagation();
- de.complete.annoDragData.annotationDocument = de.complete.annoDragData.annotationDocCreator();
- de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator();
- return de.complete.annoDragData.dropDocument && this.addDocument(de.complete.annoDragData.dropDocument);
+ else if (de.complete.annoDragData) {
+ const dropCreator = de.complete.annoDragData.dropDocCreator;
+ de.complete.annoDragData.dropDocCreator = () => {
+ const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined);
+ this.addDocument(dropped);
+ return dropped;
+ }
+ return true;
}
return false;
}
@@ -253,11 +256,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
e.stopPropagation();
e.preventDefault();
- const addDocument = (doc: Doc | Doc[]) => {
- const docs = doc instanceof Doc ? [doc] : doc;
- docs.forEach(doc => Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", doc));
- return this.addDocument(doc);
- };
+ const addDocument = (doc: Doc | Doc[]) => this.addDocument(doc);
if (html) {
if (FormattedTextBox.IsFragment(html)) {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f305174f1..a217de193 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -153,12 +153,10 @@ export class CollectionView extends Touchable<CollectionViewProps> {
const hasContextAnchor = DocListCast(doc.links).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context));
if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
const pushpin = Docs.Create.FontIconDocument({
- title: "pushpin", label: "",
+ title: "pushpin", label: "", annotationOn: Cast(doc.annotationOn, Doc, null), isPushpin: true,
icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), _backgroundColor: "#0000003d", color: "#ACCEF7",
_width: 15, _height: 15, _xPadding: 0, isLinkButton: true, _timecodeToShow: Cast(doc._timecodeToShow, "number", null)
});
- pushpin.isPushpin = true;
- Doc.GetProto(pushpin).annotationOn = doc.annotationOn;
Doc.SetInPlace(doc, "annotationOn", undefined, true);
Doc.AddDocToList(context, Doc.LayoutFieldKey(context) + "-annotations", pushpin);
const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, "pushpin", "");
@@ -191,6 +189,7 @@ export class CollectionView extends Touchable<CollectionViewProps> {
const ind = (targetDataDoc[this.props.fieldKey] as List<Doc>).indexOf(doc);
if (ind !== -1) {
Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc);
+ doc.context = undefined;
recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
}
});
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 3f8794665..f7e067399 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -382,7 +382,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
}
}
@computed get renderBounds() {
- const bounds = this.props.tabView()?.ComponentView?.freeformData?.(true)?.bounds;
+ const compView = this.props.tabView()?.ComponentView as CollectionFreeFormView;
+ const bounds = compView?.freeformData?.(true)?.bounds;
if (!bounds) return undefined;
const xbounds = bounds.r - bounds.x;
const ybounds = bounds.b - bounds.y;
@@ -419,6 +420,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
docViewPath={returnEmptyDoclist}
childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
noOverlay={true} // don't render overlay Docs since they won't scale
+ setHeight={returnFalse}
active={returnTrue}
select={emptyFunction}
dropAction={undefined}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 0852b2a46..e383cf176 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -101,13 +101,13 @@ export class TreeView extends React.Component<TreeViewProps> {
@observable _dref: DocumentView | undefined | null;
get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
get treeViewLockExpandedView() { return this.doc.treeViewLockExpandedView; }
- get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.fileSysMode ? "data" : Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields"); }
+ get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.fileSysMode ? (this.doc.isFolder ? "data" : "layout") : Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields"); }
get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
@computed get doc() { TraceMobx(); return this.props.document; }
@computed get outlineMode() { return this.props.treeView.doc.treeViewType === "outline"; }
@computed get fileSysMode() { return this.props.treeView.doc.treeViewType === "fileSystem"; }
- @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && BoolCast(this.doc.treeViewOpen)) || this._overrideTreeViewOpen; }
+ @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._overrideTreeViewOpen; }
@computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.treeViewDefaultExpandedView); }
@computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
@computed get dataDoc() { return this.doc[DataSym]; }
@@ -123,7 +123,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
return ((this.props.dataDoc ? DocListCastOrNull(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
(layout ? DocListCastOrNull(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
- DocListCastOrNull(this.doc[field])); // otherwise use the document's data field
+ DocListCastOrNull(this.doc[field]))?.filter(doc => !this.fileSysMode || field !== "aliases");// || Doc.GetT(doc, "context", Doc, true)); // otherwise use the document's data field
}
@undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
return this.doc !== target && this.props.removeDoc?.(doc) === true && addDoc(doc);
@@ -254,7 +254,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const before = pt[1] < rect.top + rect.height / 2;
const inside = this.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
if (de.complete.linkDragData) {
- const sourceDoc = de.complete.linkDragData.linkSourceDocument;
+ const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor();
const destDoc = this.doc;
DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree link", "");
e.stopPropagation();
@@ -477,8 +477,8 @@ export class TreeView extends React.Component<TreeViewProps> {
<span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
onPointerDown={action(() => {
if (this.fileSysMode) {
- this.doc.treeViewExpandedView = this.doc.isFolder ? this.fieldKey : this.treeViewExpandedView === "layout" ? "fields" :
- this.treeViewExpandedView === "fields" ? "aliases" : "layout";
+ this.doc.treeViewExpandedView = this.doc.isFolder ? this.fieldKey : this.treeViewExpandedView === "layout" ? "aliases" :
+ this.treeViewExpandedView === "aliases" && !Doc.UserDoc().noviceMode ? "fields" : "layout";
} else if (this.treeViewOpen) {
this.doc.treeViewExpandedView = this.treeViewLockExpandedView ? this.doc.treeViewExpandedView :
this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields") :
@@ -495,7 +495,11 @@ export class TreeView extends React.Component<TreeViewProps> {
}
showContextMenu = (e: React.MouseEvent) => simulateMouseClick(this._docRef?.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
- contextMenuItems = () => this.doc.isFolder ? [{ script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" }] : Doc.IsSystem(this.doc) ? [] : [{ script: ScriptField.MakeFunction(`openOnRight(self)`)!, label: "Open" }, { script: ScriptField.MakeFunction(`DocFocus(self)`)!, label: "Focus" }];
+ contextMenuItems = () => this.doc.isFolder ?
+ [{ script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" }] : Doc.IsSystem(this.doc) ? [] :
+ this.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
+ [{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }] :
+ [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }]
truncateTitleWidth = () => NumCast(this.props.treeView.props.Document.treeViewTruncateTitleWidth, this.props.panelWidth());
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
onChildDoubleClick = () => (!this.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4040362d8..af8ccb9c5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -264,7 +264,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
layoutDoc._width = NumCast(layoutDoc._width, 300);
layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
- !StrListCast(d.layers).includes(StyleLayers.Background) && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+ !StrListCast(d._layerTags).includes(StyleLayers.Background) && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
}
this.updateGroupBounds();
@@ -275,16 +275,23 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@undoBatch
internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData, xp: number, yp: number) {
- annoDragData.dropDocument!.x = xp - annoDragData.offset[0];
- annoDragData.dropDocument!.y = yp - annoDragData.offset[1];
- this.bringToFront(annoDragData.dropDocument!);
+ const dropCreator = annoDragData.dropDocCreator;
+ annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => {
+ const dropDoc = dropCreator(annotationOn);
+ if (dropDoc) {
+ dropDoc.x = xp - annoDragData.offset[0];
+ dropDoc.y = yp - annoDragData.offset[1];
+ this.bringToFront(dropDoc);
+ }
+ return dropDoc || this.rootDoc;
+ }
return true;
}
@undoBatch
internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
- if (linkDragData.linkSourceDocument === this.props.Document || this.props.Document.annotationOn) return false;
- if (!linkDragData.linkSourceDocument.context || StrCast(Cast(linkDragData.linkSourceDocument.context, Doc, null)?.type) === DocumentType.COL) {
+ if (linkDragData.dragDocument === this.props.Document || this.props.Document.annotationOn) return false;
+ if (!linkDragData.dragDocument.context || StrCast(Cast(linkDragData.dragDocument.context, Doc, null)?.type) === DocumentType.COL) {
// const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
// this.props.addDocument(source);
// linkDragData.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceDocument }, "doc annotation"); // TODODO this is where in text links get passed
@@ -292,7 +299,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
} else {
const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
this.props.addDocument?.(source);
- de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceDocument }, "doc annotation", ""); // TODODO this is where in text links get passed
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceGetAnchor() }, "doc annotation", ""); // TODODO this is where in text links get passed
e.stopPropagation();
return true;
}
@@ -300,9 +307,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
const [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
- if (this.isAnnotationOverlay !== true && de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp);
if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData, xp, yp);
- if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData, xp, yp);
+ else if (this.isAnnotationOverlay !== true && de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp);
+ else if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData, xp, yp);
return false;
}
@@ -429,8 +436,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
styleProp = colors[cluster % colors.length];
const set = this._clusterSets[cluster]?.filter(s => 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.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor));
- set?.filter(s => StrListCast(s.layers).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?.filter(s => StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor));
}
} //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray";
return styleProp;
@@ -869,7 +876,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
bringToFront = (doc: Doc, sendToBack?: boolean) => {
- if (sendToBack || StrListCast(doc.layers).includes(StyleLayers.Background)) {
+ if (sendToBack || StrListCast(doc._layerTags).includes(StyleLayers.Background)) {
doc.zIndex = 0;
} else if (doc.isInkMask) {
doc.zIndex = 5000;
@@ -1363,7 +1370,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => 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.layers).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 => !StrListCast(doc._layerTags).includes(StyleLayers.Background) && 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
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 9e442a8c8..2a30e5fd0 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -167,7 +167,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout && !this.props.childLayoutString ? e.key : "";
FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
- this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0));
+ this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0, this.props.isAnnotationOverlay ? this.props.Document : undefined));
e.stopPropagation();
}
}
@@ -359,11 +359,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
Doc.GetProto(doc).data = new List<Doc>(selected);
Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform";
+ !this.props.isAnnotationOverlay && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", Doc.GetProto(doc));
doc._panX = doc._panY = 0;
return doc;
})(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
newCollection.system = undefined;
- newCollection.layers = new List<string>(layers);
+ newCollection._layerTags = new List<string>(layers);
newCollection._width = this.Bounds.width;
newCollection._height = this.Bounds.height;
newCollection._isGroup = makeGroup;
@@ -652,7 +653,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
render() {
return <div className="marqueeView"
style={{
- overflow: (!this.props.ContainingCollectionView && this.props.isAnnotationOverlay) ? "visible" :
+ overflow: //(!this.props.ContainingCollectionView && this.props.isAnnotationOverlay) ? "visible" :
StrCast(this.props.Document._overflow),
cursor: "hand"
}}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 58db080ad..e2feff5ed 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -235,7 +235,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
i, y, h,
x: x + w > this.numCols ? 0 : x, // handles wrapping around of nodes when numCols decreases
w: Math.min(w, this.numCols), // reduces width if greater than numCols
- static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout.lockedPosition, false) // checks if the lock position item has been selected in the context menu
+ static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout._lockedPosition, false) // checks if the lock position item has been selected in the context menu
})) :
this.savedLayoutList.map((layout, index) => { Object.assign(layout, this.unflexedPosition(index)); return layout; });
}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index e51417f64..d23f3309e 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -217,8 +217,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
Document={layout}
DataDoc={layout.resolvedDataDoc as Doc}
styleProvider={this.props.styleProvider}
- layerProvider={undefined}
- docViewPath={returnEmptyDoclist}
+ layerProvider={this.props.layerProvider}
+ docViewPath={this.props.docViewPath}
LayoutTemplate={this.props.childLayoutTemplate}
LayoutTemplateString={this.props.childLayoutString}
freezeDimensions={this.props.childFreezeDimensions}
@@ -257,7 +257,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
const collector: JSX.Element[] = [];
for (let i = 0; i < childLayoutPairs.length; i++) {
const { layout } = childLayoutPairs[i];
- const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin));
+ const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)).scale((this.props.scaling?.() || 1));
const width = () => this.lookupPixels(layout);
const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
collector.push(
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index d61a2bb72..641ae6ce1 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -217,8 +217,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
Document={layout}
DataDoc={layout.resolvedDataDoc as Doc}
styleProvider={this.props.styleProvider}
- layerProvider={undefined}
- docViewPath={returnEmptyDoclist}
+ layerProvider={this.props.layerProvider}
+ docViewPath={this.props.docViewPath}
LayoutTemplate={this.props.childLayoutTemplate}
LayoutTemplateString={this.props.childLayoutString}
freezeDimensions={this.props.childFreezeDimensions}
@@ -257,19 +257,13 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
const collector: JSX.Element[] = [];
for (let i = 0; i < childLayoutPairs.length; i++) {
const { layout } = childLayoutPairs[i];
- const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin));
+ const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)).scale((this.props.scaling?.() || 1));
const height = () => this.lookupPixels(layout);
const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
collector.push(
- <div
- className={"document-wrapper"}
- key={"wrapper" + i}
- >
+ <div className={"document-wrapper"} key={"wrapper" + i} >
{this.getDisplayDoc(layout, dxf, width, height)}
- <HeightLabel
- layout={layout}
- collectionDoc={Document}
- />
+ <HeightLabel layout={layout} collectionDoc={Document} />
</div>,
<ResizeBar
height={resizerHeight}
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index d5b6a269e..715ec92f8 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -11,7 +11,7 @@ import { StrCast } from "../../../fields/Types";
import { SelectionManager } from "../../util/SelectionManager";
import { undoBatch } from "../../util/UndoManager";
import { ViewBoxBaseComponent } from "../DocComponent";
-import { ActiveInkPen, ActiveInkWidth, ActiveInkBezierApprox, SetActiveInkColor, SetActiveInkWidth, SetActiveBezierApprox } from "../InkingStroke";
+import { ActiveInkPen, ActiveInkWidth, ActiveInkBezierApprox, SetActiveInkColor, SetActiveInkWidth, SetActiveBezierApprox, ActiveInkColor } from "../InkingStroke";
import "./ColorBox.scss";
import { FieldView, FieldViewProps } from './FieldView';
import { DocumentType } from "../../documents/DocumentTypes";
@@ -60,8 +60,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
style={{ width: `${100}%`, height: `${100}%` }} >
<SketchPicker onChange={ColorBox.switchColor} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={StrCast(ActiveInkPen()?.backgroundColor,
- StrCast(selDoc?._backgroundColor, StrCast(selDoc?.backgroundColor, "black")))} />
+ color={StrCast(selDoc?._backgroundColor, ActiveInkColor())} />
<div style={{ display: "grid", gridTemplateColumns: "20% 80%", paddingTop: "10px" }}>
<div> {ActiveInkWidth() ?? 2}</div>
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 7a8eb5628..02c112745 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -11,6 +11,7 @@ import { CollectionView } from "../collections/CollectionView";
import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
import { AudioBox } from "./AudioBox";
import { LabelBox } from "./LabelBox";
+import { EquationBox } from "./EquationBox";
import { SliderBox } from "./SliderBox";
import { LinkBox } from "./LinkBox";
import { ScriptingBox } from "./ScriptingBox";
@@ -109,6 +110,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
isSelected: (outsideReaction: boolean) => boolean,
select: (ctrl: boolean) => void,
scaling?: () => number,
+ setHeight: (height: number) => void,
layoutKey: string,
hideOnLeave?: boolean,
}> {
@@ -219,7 +221,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
blacklistedAttrs={emptyPath}
renderInWrapper={false}
components={{
- FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
+ FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, EquationBox, SliderBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox,
ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 18cabc309..085ffae26 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -51,16 +51,10 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
if (this.props.InMenu && this.props.StartLink) {
if (this._linkButton.current !== null) {
const linkDrag = UndoManager.StartBatch("Drag Link");
- this.props.View && DragManager.StartLinkDrag(this._linkButton.current, this.props.View.props.Document, e.pageX, e.pageY, {
+ this.props.View && DragManager.StartLinkDrag(this._linkButton.current, this.props.View.props.Document, this.props.View.ComponentView?.getAnchor, e.pageX, e.pageY, {
dragComplete: dropEv => {
if (this.props.View && dropEv.linkDocument) {// dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
!dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = "hyperlink");
-
- // we want to allow specific views to handle the link creation in their own way (e.g., rich text makes text hyperlinks)
- // the dragged view can regiser a linkDropCallback to be notified that the link was made and to update their data structures
- // however, the dropped document isn't so accessible. What we do is set the newly created link document on the documentView
- // The documentView passes a function prop returning this link doc to its descendants who can react to changes to it.
- dropEv.linkDragData?.linkDropCallback?.(dropEv as { linkDocument: Doc }); // bcz: typescript can't figure out that this is valid even though we tested dropEv.linkDocument above
}
linkDrag?.end();
},
@@ -106,7 +100,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
const alias = Doc.MakeAlias(otherdoc);
alias.x = wid;
alias.y = 0;
- alias.lockedPosition = false;
+ alias._lockedPosition = false;
wid += otherdoc[WidthSym]();
Doc.AddDocToList(Doc.GetProto(target), "data", alias);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f07cbfbf5..cd61d20b1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, runInAction } from "mobx";
+import { action, computed, observable, runInAction, reaction, IReactionDisposer } from "mobx";
import { observer } from "mobx-react";
import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast } from "../../../fields/Doc";
import { Document } from '../../../fields/documentSchemas';
@@ -275,7 +275,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._downX = touch.clientX;
this._downY = touch.clientY;
if (!e.nativeEvent.cancelBubble) {
- if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
+ if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
this.removeMoveListeners();
this.addMoveListeners();
this.removeEndListeners();
@@ -290,7 +290,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e.cancelBubble && this.active) {
this.removeMoveListeners();
}
- else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+ else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
const touch = me.touchEvent.changedTouches.item(0);
if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) {
@@ -429,7 +429,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
(Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
let stopPropagate = true;
let preventDefault = true;
- !StrListCast(this.props.Document.layers).includes(StyleLayers.Background) && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
+ !StrListCast(this.props.Document._layerTags).includes(StyleLayers.Background) && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
if (this._timeout) {
clearTimeout(this._timeout);
@@ -528,7 +528,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e.cancelBubble && this.active) {
document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
}
- else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+ else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
document.removeEventListener("pointermove", this.onPointerMove);
@@ -596,7 +596,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@undoBatch deleteClicked = () => this.props.removeDocument?.(this.props.Document);
@undoBatch toggleDetail = () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`);
- @undoBatch toggleLockPosition = () => this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
+ @undoBatch toggleLockPosition = () => this.Document._lockedPosition = this.Document._lockedPosition ? undefined : true;
@undoBatch @action
drop = async (e: Event, de: DragManager.DropEvent) => {
@@ -607,13 +607,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
"Linking to document tabs not yet supported. Drop link on document content.");
return;
}
- if (de.complete.annoDragData) de.complete.annoDragData.annotationDocument = de.complete.annoDragData.annotationDocCreator();
- const linkSource = de.complete.annoDragData ? de.complete.annoDragData.annotationDocument : de.complete.linkDragData ? de.complete.linkDragData.linkSourceDocument : undefined;
- if (linkSource && linkSource !== this.props.Document) {
+ const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
+ if (linkdrag) linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor();
+ if (linkdrag?.linkSourceDoc) {
e.stopPropagation();
- const dropDoc = this._componentView?.getAnchor?.() || this.rootDoc;
- if (de.complete.annoDragData) de.complete.annoDragData.dropDocument = dropDoc;
- de.complete.linkDocument = DocUtils.MakeLink({ doc: linkSource }, { doc: dropDoc }, "link", undefined, undefined, undefined, [de.x, de.y]);
+ if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) {
+ de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
+ }
+ if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
+ const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.() ?? this.props.Document;
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, "link", undefined, undefined, undefined, [de.x, de.y]);
+ }
}
}
@@ -687,7 +691,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (!this.Document.annotationOn) {
const options = cm.findByDescription("Options...");
const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
- this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
+ this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && optionItems.push({ description: this.Document._lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document._lockedPosition) ? "unlock" : "lock" });
!options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
@@ -755,6 +759,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
contentScaling = () => this.ContentScale;
onClickFunc = () => this.onClickHandler;
+ setHeight = (height: number) => this.rootDoc._height = height;
setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view;
@observable contentsActive: () => boolean = returnFalse;
@action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive;
@@ -780,6 +785,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
setContentView={this.setContentView}
scaling={this.contentScaling}
PanelHeight={this.panelHeight}
+ setHeight={this.setHeight}
contentsActive={this.setContentsActive}
parentActive={this.parentActive}
ScreenToLocalTransform={this.screenToLocal}
@@ -953,7 +959,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] :
["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"])[highlightIndex];
const highlightStyle = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"][highlightIndex];
- let highlighting = !this.props.cantBrush && highlightIndex && ![DocumentType.FONTICON, DocumentType.INK].includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear;
+ const excludeTypes = !this.props.treeViewDoc ? [DocumentType.FONTICON, DocumentType.INK] : [DocumentType.FONTICON];
+ let highlighting = !this.props.cantBrush && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear;
highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
const boxShadow = highlighting && this.borderRounding && highlightStyle !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColor}` :
@@ -982,6 +989,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
public static ROOT_DIV = "documentView-effectsWrapper";
public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
public ContentRef = React.createRef<HTMLDivElement>();
+ private _disposers: { [name: string]: IReactionDisposer } = {};
@observable public docView: DocumentViewInternal | undefined | null;
@@ -997,30 +1005,40 @@ export class DocumentView extends React.Component<DocumentViewProps> {
@computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; }
@computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); }
- @computed get nativeWidth() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); }
- @computed get nativeHeight() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); }
+ @computed get nativeWidth() {
+ return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
+ returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions));
+ }
+ @computed get nativeHeight() {
+ return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
+ returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions));
+ }
+ shouldNotScale = () => this.layoutDoc._fitWidth || [CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._viewType as any);
+ @computed get effectiveNativeWidth() { return this.nativeWidth || (this.shouldNotScale() ? 0 : NumCast(this.layoutDoc.width)); }
+ @computed get effectiveNativeHeight() { return this.nativeHeight || (this.shouldNotScale() ? 0 : NumCast(this.layoutDoc.height)); }
@computed get nativeScaling() {
- if (this.nativeWidth && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / this.nativeHeight > this.props.PanelWidth() / this.nativeWidth)) {
- return this.props.PanelWidth() / this.nativeWidth; // width-limited or fitWidth
+ const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0;
+ if (this.effectiveNativeWidth && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / this.effectiveNativeHeight > this.props.PanelWidth() / this.effectiveNativeWidth)) {
+ return Math.max(minTextScale, this.props.PanelWidth() / this.effectiveNativeWidth); // width-limited or fitWidth
}
- return this.nativeWidth && this.nativeHeight ? this.props.PanelHeight() / this.nativeHeight : 1; // height-limited or unscaled
+ return this.effectiveNativeWidth && this.effectiveNativeHeight ? Math.max(minTextScale, this.props.PanelHeight() / this.effectiveNativeHeight) : 1; // height-limited or unscaled
}
- @computed get panelWidth() { return this.nativeWidth ? this.nativeWidth * this.nativeScaling : this.props.PanelWidth(); }
+ @computed get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); }
@computed get panelHeight() {
- if (this.nativeHeight) {
+ if (this.effectiveNativeHeight) {
return Math.min(this.props.PanelHeight(),
this.props.Document._fitWidth ?
- Math.max(NumCast(this.props.Document._height), NumCast(((this.props.Document.scrollHeight || 0) as number) * this.props.PanelWidth() / this.nativeWidth, this.props.PanelHeight())) :
- this.nativeHeight * this.nativeScaling
+ Math.max(NumCast(this.props.Document._height), NumCast(((this.props.Document.scrollHeight || 0) as number) * this.props.PanelWidth() / this.effectiveNativeWidth, this.props.PanelHeight())) :
+ this.effectiveNativeHeight * this.nativeScaling
);
}
return this.props.PanelHeight();
}
- @computed get Xshift() { return this.nativeWidth ? (this.props.PanelWidth() - this.nativeWidth * this.nativeScaling) / 2 : 0; }
- @computed get YShift() { return this.nativeWidth && this.nativeHeight && Math.abs(this.Xshift) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.nativeScaling) / 2 : 0; }
+ @computed get Xshift() { return this.effectiveNativeWidth ? (this.props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2 : 0; }
+ @computed get Yshift() { return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 ? (this.props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2 : 0; }
@computed get centeringX() { return this.props.dontCenter?.includes("x") ? 0 : this.Xshift; }
- @computed get centeringY() { return this.props.Document._fitWidth || this.props.dontCenter?.includes("y") ? 0 : this.YShift; }
+ @computed get centeringY() { return this.props.Document._fitWidth || this.props.dontCenter?.includes("y") ? 0 : this.Yshift; }
toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight());
contentsActive = () => this.docView?.contentsActive();
@@ -1067,8 +1085,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
docViewPathFunc = () => this.docViewPath;
isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection);
- NativeWidth = () => this.nativeWidth;
- NativeHeight = () => this.nativeHeight;
+ NativeWidth = () => this.effectiveNativeWidth;
+ NativeHeight = () => this.effectiveNativeHeight;
PanelWidth = () => this.panelWidth;
PanelHeight = () => this.panelHeight;
ContentScale = () => this.nativeScaling;
@@ -1076,41 +1094,49 @@ export class DocumentView extends React.Component<DocumentViewProps> {
screenToLocalTransform = () => {
return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling);
}
-
componentDidMount() {
- !BoolCast(this.props.Document?.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
+ this._disposers.height = reaction(
+ () => NumCast(this.layoutDoc._height),
+ action(height => {
+ const docMax = NumCast(this.layoutDoc.docMaxAutoHeight);
+ if (docMax && docMax < height) this.layoutDoc.docMaxAutoHeight = height;
+ })
+ );
+ !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
}
componentWillUnmount() {
+ Object.values(this._disposers).forEach(disposer => disposer?.());
!this.props.dontRegisterView && DocumentManager.Instance.RemoveView(this);
}
render() {
TraceMobx();
- const internalProps = {
- ...this.props,
- DocumentView: this.selfView,
- viewPath: this.docViewPathFunc,
- PanelWidth: this.PanelWidth,
- PanelHeight: this.PanelHeight,
- NativeWidth: this.NativeWidth,
- NativeHeight: this.NativeHeight,
- isSelected: this.isSelected,
- select: this.select,
- ContentScaling: this.ContentScale,
- ScreenToLocalTransform: this.screenToLocalTransform,
- focus: this.props.focus || emptyFunction,
- bringToFront: emptyFunction,
- };
+ const xshift = this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined;
+ const yshift = this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined;
return (<div className="contentFittingDocumentView">
{!this.props.Document || !this.props.PanelWidth() ? (null) : (
<div className="contentFittingDocumentView-previewDoc" ref={this.ContentRef}
style={{
position: this.props.Document.isInkMask ? "absolute" : undefined,
transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
- width: this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Xshift) > 0.001 ? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth(),
- height: this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.YShift) > 0.001 ? this.props.Document._fitWidth ? `${this.panelHeight}px` : `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
+ width: xshift ?? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%`,
+ height: yshift ?? this.props.Document._fitWidth ? `${this.panelHeight}px` :
+ `${100 * this.effectiveNativeHeight / this.effectiveNativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%`,
}}>
- <DocumentViewInternal {...this.props} {...internalProps} ref={action((r: DocumentViewInternal | null) => this.docView = r)} />
+ <DocumentViewInternal {...this.props}
+ DocumentView={this.selfView}
+ viewPath={this.docViewPathFunc}
+ PanelWidth={this.PanelWidth}
+ PanelHeight={this.PanelHeight}
+ NativeWidth={this.NativeWidth}
+ NativeHeight={this.NativeHeight}
+ isSelected={this.isSelected}
+ select={this.select}
+ ContentScaling={this.ContentScale}
+ ScreenToLocalTransform={this.screenToLocalTransform}
+ focus={this.props.focus || emptyFunction}
+ bringToFront={emptyFunction}
+ ref={action((r: DocumentViewInternal | null) => this.docView = r)} />
</div>)}
</div>);
}
diff --git a/src/client/views/nodes/EquationBox.scss b/src/client/views/nodes/EquationBox.scss
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/client/views/nodes/EquationBox.scss
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
new file mode 100644
index 000000000..5bc73d5d9
--- /dev/null
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -0,0 +1,82 @@
+import EquationEditor from 'equation-editor-react';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { documentSchema } from '../../../fields/documentSchemas';
+import { createSchema, makeInterface } from '../../../fields/Schema';
+import { StrCast, NumCast } from '../../../fields/Types';
+import { ViewBoxBaseComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './LabelBox.scss';
+import { Id } from '../../../fields/FieldSymbols';
+import { simulateMouseClick } from '../../../Utils';
+import { TraceMobx } from '../../../fields/util';
+import { reaction, action } from 'mobx';
+import { Docs } from '../../documents/Documents';
+import { LightboxView } from '../LightboxView';
+
+const EquationSchema = createSchema({});
+
+type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSchema]>;
+const EquationDocument = makeInterface(EquationSchema, documentSchema);
+
+@observer
+export class EquationBox extends ViewBoxBaseComponent<FieldViewProps, EquationDocument>(EquationDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(EquationBox, fieldKey); }
+ public static SelectOnLoad: string = "";
+ _ref: React.RefObject<EquationEditor> = React.createRef();
+ componentDidMount() {
+ if (EquationBox.SelectOnLoad === this.rootDoc[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
+ this.props.select(false);
+
+ this._ref.current!.mathField.focus();
+ this._ref.current!.mathField.select();
+ }
+ reaction(() => this.props.isSelected(),
+ selected => {
+ if (this._ref.current) {
+ if (selected) this._ref.current.element.current.children[0].addEventListener("keydown", this.keyPressed, true);
+ else this._ref.current.element.current.children[0].removeEventListener("keydown", this.keyPressed);
+ }
+ }, { fireImmediately: true });
+ }
+ @action
+ keyPressed = (e: KeyboardEvent) => {
+ const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace("px", ""));
+ const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace("px", ""));
+ if (e.key === "Enter" || e.key === "Tab") {
+ const nextEq = Docs.Create.EquationDocument({
+ title: "# math", text: StrCast(this.dataDoc.text), _width, _height: 25,
+ x: NumCast(this.layoutDoc.x) + (e.key === "Tab" ? _width + 10 : 0), y: NumCast(this.layoutDoc.y) + (e.key === "Enter" ? _height + 10 : 0)
+ });
+ EquationBox.SelectOnLoad = nextEq[Id];
+ this.props.addDocument?.(nextEq);
+ e.stopPropagation();
+ }
+ if (e.key === "Backspace" && !this.dataDoc.text) this.props.removeDocument?.(this.rootDoc);
+ }
+ onChange = (str: string) => {
+ this.dataDoc.text = str;
+ const style = this._ref.current && getComputedStyle(this._ref.current.element.current);
+ if (style) {
+ const _height = Number(style.height.replace("px", ""));
+ const _width = Number(style.width.replace("px", ""));
+ this.layoutDoc._width = Math.max(35, _width);
+ this.layoutDoc._height = Math.max(25, _height);
+ }
+ }
+ render() {
+ TraceMobx();
+ return (<div onPointerDown={e => !e.ctrlKey && e.stopPropagation()}
+ style={{
+ pointerEvents: !this.props.isSelected() ? "none" : undefined,
+ }}
+ >
+ <EquationEditor ref={this._ref}
+ value={this.dataDoc.text || "y"}
+ spaceBehavesLikeTab={true}
+ onChange={this.onChange}
+ autoCommands="pi theta sqrt sum prod alpha beta gamma rho"
+ autoOperatorNames="sin cos tan" /></div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 1b4119210..465c18309 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -16,12 +16,13 @@ import { VideoBox } from "./VideoBox";
export interface FieldViewProps extends DocumentViewSharedProps {
// FieldView specific props that are not part of DocumentView props
fieldKey: string;
- overflow?: boolean; // bcz: would like to think this can be avoided -- need to look at further
+ scrollOverflow?: boolean; // bcz: would like to think this can be avoided -- need to look at further
active: (outsideReaction?: boolean) => boolean;
select: (isCtrlPressed: boolean) => void;
isSelected: (outsideReaction?: boolean) => boolean;
scaling?: () => number;
+ setHeight: (height: number) => void;
// properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
pointerEvents?: string;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index a3a3ec662..b25d78a1e 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -190,8 +190,8 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
}
});
let newFacet: Opt<Doc>;
- if (facetHeader === "text") {//} || facetValues.rtFields / allCollectionDocs.length > 0.1) {
- newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, system: true, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true });
+ if (facetHeader === "text" || facetValues.rtFields / allCollectionDocs.length > 0.1) {
+ newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, system: true, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, _forceActive: true, ignoreClick: true });
Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
newFacet._textBoxPadding = 4;
const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`;
@@ -352,6 +352,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
fieldKey={this.props.fieldKey}
CollectionView={undefined}
cantBrush={true}
+ setHeight={returnFalse} // if the tree view can trigger the height of the filter box to change, then this needs to be filled in.
onChildClick={this.suppressChildClick}
docFilters={returnEmptyFilter}
docRangeFilters={returnEmptyFilter}
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 121b9f26c..56c79cde9 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -50,7 +50,6 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
style={{ width: presSize, height: presSize, filter: `invert(${color === "white" ? "100%" : "0%"})`, marginBottom: "5px" }} />;
const button = <button className={`menuButton-${shape}`} onContextMenu={this.specificContextMenu}
style={{
- boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined,
backgroundColor: this.layoutDoc.iconShape === "square" ? backgroundColor : "",
}}>
<div className="menuButton-wrap">
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 4c3031ae2..240aa1659 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -62,13 +62,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
componentDidMount() {
this._disposers.selection = reaction(() => this.props.isSelected(),
- selected => {
- if (!selected) {
- this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
- this._savedAnnotations.clear();
- }
- },
- { fireImmediately: true });
+ selected => !selected && setTimeout(() => {
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.clear();
+ }));
this._disposers.path = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }),
action(({ nativeSize, width }) => {
if (!this.layoutDoc._height) {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index ebb953dad..83a49a393 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -67,6 +67,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
fieldKey: this.props.keyName,
rootSelected: returnFalse,
isSelected: returnFalse,
+ setHeight: returnFalse,
select: emptyFunction,
dropAction: "alias",
bringToFront: emptyFunction,
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 87d5b07a2..6a7793ff0 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -59,9 +59,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
}
@observable _mouseOver = false;
- @computed get backColor() { return this.clicked || this._mouseOver ? StrCast(this.layoutDoc.hovercolor) : "unset"; }
+ @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; }
- @observable clicked = false;
// (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
render() {
const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
@@ -70,15 +69,12 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
const label = typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title);
return (
<div className="labelBox-outerDiv"
- onClick={action(() => this.clicked = !this.clicked)}
onMouseLeave={action(() => this._mouseOver = false)}
onMouseOver={action(() => this._mouseOver = true)}
ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}>
<div className="labelBox-mainButton" style={{
- background: StrCast(this.layoutDoc.backgroundColor),
- backgroundColor: this.backColor,
- color: StrCast(this.layoutDoc.color, "inherit"),
+ backgroundColor: this.hoverColor,
fontSize: StrCast(this.layoutDoc._fontSize) || "inherit",
fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit",
letterSpacing: StrCast(this.layoutDoc.letterSpacing),
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index d76b61502..392565402 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -94,7 +94,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
openLinkTargetOnRight = (e: React.MouseEvent) => {
const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null));
alias.isLinkButton = undefined;
- alias.layers = undefined;
+ alias._layerTags = undefined;
alias.layoutKey = "layout";
this.props.addDocTab(alias, "add:right");
}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index ac67949f9..6afc2258a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -204,13 +204,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
componentDidMount() {
this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
this._disposers.selection = reaction(() => this.props.isSelected(),
- selected => {
- if (!selected) {
- this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
- this._savedAnnotations.clear();
- }
- },
- { fireImmediately: true });
+ selected => !selected && setTimeout(() => {
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.clear();
+ }));
this._disposers.triggerVideo = reaction(
() => !LinkDocPreview.LinkInfo && this.props.renderDepth !== -1 ? NumCast(this.Document._triggerVideo, null) : undefined,
time => time !== undefined && setTimeout(() => {
@@ -485,7 +482,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
playing = () => this._playing;
isActiveChild = () => this._isChildActive;
- timelineWhenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(runInAction(() => this._isChildActive = isActive));
+ timelineWhenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
timelineScreenToLocal = () => this.props.ScreenToLocalTransform().scale(this.scaling()).translate(0, -this.heightPercent / 100 * this.props.PanelHeight());
setAnchorTime = (time: number) => this.player!.currentTime = this.layoutDoc._currentTimecode = time;
timelineHeight = () => this.props.PanelHeight() * (100 - this.heightPercent) / 100;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 2cd6f5f33..0cf052501 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -140,13 +140,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
runInAction(() => this._url = urlField?.url.toString() || "");
this._disposers.selection = reaction(() => this.props.isSelected(),
- selected => {
- if (!selected) {
- this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
- this._savedAnnotations.clear();
- }
- },
- { fireImmediately: true });
+ selected => !selected && setTimeout(() => {
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.clear();
+ }));
document.addEventListener("pointerup", this.onLongPressUp);
document.addEventListener("pointermove", this.onLongPressMove);
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index b39a845db..62f65cdae 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -1,18 +1,18 @@
-import { IReactionDisposer, observable, computed, action } from "mobx";
-import { Doc, DocListCast, Field, DataSym } from "../../../../fields/Doc";
+import { action, computed, IReactionDisposer, observable } from "mobx";
+import { observer } from "mobx-react";
+import * as ReactDOM from 'react-dom';
+import { DataSym, Doc, DocListCast, Field } from "../../../../fields/Doc";
import { List } from "../../../../fields/List";
import { listSpec } from "../../../../fields/Schema";
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 * as ReactDOM from 'react-dom';
-import "./DashFieldView.scss";
-import { observer } from "mobx-react";
-import { DocUtils } from "../../../documents/Documents";
export class DashFieldView {
_fieldWrapper: HTMLDivElement; // container for label and value
diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx
new file mode 100644
index 000000000..eff018635
--- /dev/null
+++ b/src/client/views/nodes/formattedText/EquationView.tsx
@@ -0,0 +1,75 @@
+import EquationEditor from "equation-editor-react";
+import { IReactionDisposer } from "mobx";
+import { observer } from "mobx-react";
+import * as ReactDOM from 'react-dom';
+import { Doc } from "../../../../fields/Doc";
+import { StrCast } from "../../../../fields/Types";
+import "./DashFieldView.scss";
+import { FormattedTextBox } from "./FormattedTextBox";
+import React = require("react");
+
+export class EquationView {
+ _fieldWrapper: HTMLDivElement; // container for label and value
+
+ constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
+ 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.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(<EquationViewInternal
+ fieldKey={node.attrs.fieldKey}
+ width={node.attrs.width}
+ height={node.attrs.height}
+ tbox={tbox}
+ />, this._fieldWrapper);
+ (this as any).dom = this._fieldWrapper;
+ }
+ destroy() { ReactDOM.unmountComponentAtNode(this._fieldWrapper); }
+ selectNode() { }
+}
+
+interface IEquationViewInternal {
+ fieldKey: string;
+ tbox: FormattedTextBox;
+ width: number;
+ height: number;
+}
+
+@observer
+export class EquationViewInternal extends React.Component<IEquationViewInternal> {
+ _reactionDisposer: IReactionDisposer | undefined;
+ _textBoxDoc: Doc;
+ _fieldKey: string;
+
+ constructor(props: IEquationViewInternal) {
+ super(props);
+ this._fieldKey = this.props.fieldKey;
+ this._textBoxDoc = this.props.tbox.props.Document;
+ }
+
+ componentWillUnmount() { this._reactionDisposer?.(); }
+
+ render() {
+ return <div className="equationView" style={{
+ position: "relative",
+ display: "inline-block",
+ width: this.props.width,
+ height: this.props.height,
+ }}>
+ <EquationEditor
+ value={StrCast(this._textBoxDoc[this._fieldKey], "y=")}
+ onChange={str => this._textBoxDoc[this._fieldKey] = str}
+ autoCommands="pi theta sqrt sum prod alpha beta gamma rho"
+ autoOperatorNames="sin cos tan"
+ spaceBehavesLikeTab={true}
+ />
+ </div >;
+ }
+} \ 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 b4fbda9f4..104d60fff 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -40,6 +40,7 @@ import { DashDocView } from "./RichTextSchema";
import { DashDocCommentView } from "./DashDocCommentView";
import { DashFieldView } from "./DashFieldView";
+import { EquationView } from "./EquationView";
import { SummaryView } from "./SummaryView";
import { OrderedListView } from "./OrderedListView";
import { FootnoteView } from "./FootnoteView";
@@ -47,7 +48,7 @@ import { FootnoteView } from "./FootnoteView";
import { schema } from "./schema_rts";
import { SelectionManager } from "../../../util/SelectionManager";
import { undoBatch, UndoManager } from "../../../util/UndoManager";
-import { CollectionFreeFormView, collectionFreeformViewProps } from '../../collections/collectionFreeForm/CollectionFreeFormView';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from "../../DocComponent";
@@ -58,16 +59,13 @@ import "./FormattedTextBox.scss";
import { FormattedTextBoxComment, findLinkMark } from './FormattedTextBoxComment';
import React = require("react");
import { CollectionStackingView } from '../../collections/CollectionStackingView';
-import { CollectionViewType } from '../../collections/CollectionView';
import { SnappingManager } from '../../../util/SnappingManager';
import { LinkDocPreview } from '../LinkDocPreview';
-import { SubCollectionViewProps } from '../../collections/CollectionSubView';
import { StyleProp } from '../../StyleProvider';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
import { DocumentManager } from '../../../util/DocumentManager';
import { LightboxView } from '../../LightboxView';
-import { DocAfterFocusFunc } from '../DocumentView';
const translateGoogleApi = require("translate-google-api");
export interface FormattedTextBoxProps {
@@ -89,24 +87,38 @@ type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, da
export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
+ public static get DefaultLayout() {
+ return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
+ }
public static CanAnnotate = true;
public static Instance: FormattedTextBox;
public ProseRef?: HTMLDivElement;
public get EditorView() { return this._editorView; }
public get SidebarKey() { return this.fieldKey + "-sidebar"; }
- private _boxRef: React.RefObject<HTMLDivElement> = React.createRef();
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
private _editorView: Opt<EditorView>;
private _applyingChange: string = "";
private _searchIndex = 0;
+ private _lastTimedMark: Mark | undefined = undefined;
private _cachedLinks: Doc[] = [];
private _undoTyping?: UndoManager.Batch;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _dropDisposer?: DragManager.DragDropDisposer;
private _recordingStart: number = 0;
private _ignoreScroll = false;
+ private _lastText = "";
+ private _focusSpeed: Opt<number>;
+ private _keymap: any = undefined;
+ private _rules: RichTextRules | undefined;
+ @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
+ @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
+ @computed get autoHeight() { return this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight; }
+ @computed get textHeight() { return NumCast(this.rootDoc[this.fieldKey + "-height"]); }
+ @computed get scrollHeight() { return NumCast(this.rootDoc[this.fieldKey + "-scrollHeight"]); }
+ @computed get sidebarHeight() { return NumCast(this.rootDoc[this.SidebarKey + "-height"]); }
+ @computed get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
@computed get _recording() { return this.dataDoc?.audioState === "recording"; }
set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; }
@@ -114,9 +126,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
public static SelectOnLoad = "";
public static PasteOnLoad: ClipboardEvent | undefined;
public static SelectOnLoadChar = "";
- public static IsFragment(html: string) {
- return html.indexOf("data-pm-slice") !== -1;
- }
+ public static IsFragment(html: string) { return html.indexOf("data-pm-slice") !== -1; }
public static GetHref(html: string): string {
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(html, 'text/html');
@@ -127,24 +137,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return "";
}
public static GetDocFromUrl(url: string) {
- if (url.startsWith(document.location.origin)) {
- const split = new URL(url).pathname.split("doc/");
- const docid = split[split.length - 1];
- return docid;
- }
- return "";
- }
-
- @undoBatch
- public setFontColor(color: string) {
- const view = this._editorView!;
- if (view.state.selection.from === view.state.selection.to) return false;
- if (view.state.selection.to - view.state.selection.from > view.state.doc.nodeSize - 3) {
- this.layoutDoc.color = color;
- }
- const colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color: color });
- view.dispatch(view.state.tr.addMark(view.state.selection.from, view.state.selection.to, colorMark));
- return true;
+ return url.startsWith(document.location.origin) ? new URL(url).pathname.split("doc/").lastElement() : ""; // docid
}
constructor(props: any) {
@@ -154,8 +147,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._recordingStart = Date.now();
}
- public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
-
// removes all hyperlink anchors for the removed linkDoc
// TODO: bcz: Argh... if a section of text has multiple anchors, this should just remove the intended one.
// but since removing one anchor from the list of attr anchors isn't implemented, this will end up removing nothing.
@@ -192,35 +183,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
getAnchor = () => this.makeLinkAnchor(undefined, "add:right", undefined, "Anchored Selection");
- linkOnDeselect: Map<string, string> = new Map();
-
- doLinkOnDeselect() {
-
- Array.from(this.linkOnDeselect.entries()).map(entry => {
- const key = entry[0];
- const value = entry[1];
-
- const id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
- DocServer.GetRefField(value).then(doc => {
- DocServer.GetRefField(id).then(linkDoc => {
- this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, _width: 500, _height: 500 }, value);
- DocUtils.Publish(this.dataDoc[key] as Doc, value, this.props.addDocument, this.props.removeDocument);
- if (linkDoc) {
- (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc;
- } else {
- DocUtils.MakeLink({ doc: this.rootDoc }, { doc: this.dataDoc[key] as Doc }, "portal link", "link to named target", id);
- }
- });
- });
- });
-
- this.linkOnDeselect.clear();
- }
-
@action
setupAnchorMenu = () => {
AnchorMenu.Instance.Status = "marquee";
- AnchorMenu.Instance.Highlight = action((color: string) => {
+ AnchorMenu.Instance.Highlight = action((color: string, isLinkButton: boolean) => {
this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch);
return undefined;
});
@@ -231,55 +197,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
AnchorMenu.Instance.StartDrag = action(async (e: PointerEvent, ele: HTMLElement) => {
e.preventDefault();
e.stopPropagation();
- const targetCreator = () => {
- const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.rootDoc.title, 0, 0, 100, 100);
+ const targetCreator = (annotationOn?: Doc) => {
+ const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn);
FormattedTextBox.SelectOnLoad = target[Id];
return target;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.rootDoc, () => this.rootDoc, targetCreator), e.pageX, e.pageY, {
- dragComplete: e => {
- const anchor = this.makeLinkAnchor(undefined, "add:right", undefined, "a link");
- if (!e.aborted && e.annoDragData && e.annoDragData.annotationDocument && e.annoDragData.dropDocument && !e.linkDocument) {
- e.linkDocument = DocUtils.MakeLink({ doc: anchor }, { doc: e.annoDragData.dropDocument }, "hyperlink", "link to note");
- e.annoDragData.annotationDocument.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.rootDoc;
- }
- e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument
- }
- });
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.rootDoc, this.getAnchor, targetCreator), e.pageX, e.pageY);
});
const coordsT = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
this.props.isSelected(true) && AnchorMenu.Instance.jumpTo(Math.min(coordsT.left, coordsB.left), Math.max(coordsT.bottom, coordsB.bottom));
}
- _lastText = "";
dispatchTransaction = (tx: Transaction) => {
if (this._editorView) {
- const metadata = tx.selection.$from.marks().find((m: Mark) => m.type === schema.marks.metadata);
- if (metadata) {
- const range = tx.selection.$from.blockRange(tx.selection.$to);
- let text = range ? tx.doc.textBetween(range.start, range.end) : "";
- let textEndSelection = tx.selection.to;
- for (; textEndSelection < range!.end && text[textEndSelection - range!.start] !== " "; textEndSelection++) { }
- text = text.substr(0, textEndSelection - range!.start);
- text = text.split(" ")[text.split(" ").length - 1];
- const split = text.split("::");
- if (split.length > 1 && split[1]) {
- const key = split[0];
- const value = split[split.length - 1];
- this.linkOnDeselect.set(key, value);
-
- const id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
- const allAnchors = [{ href: Utils.prepend("/doc/" + id), title: value, anchorId: id }];
- const link = this._editorView.state.schema.marks.linkAnchor.create({ allAnchors, location: "add:right", title: value });
- const mval = this._editorView.state.schema.marks.metadataVal.create();
- const offset = (tx.selection.to === range!.end - 1 ? -1 : 0);
- tx = tx.addMark(textEndSelection - value.length + offset, textEndSelection, link).addMark(textEndSelection - value.length + offset, textEndSelection, mval);
- this.dataDoc[key] = value;
- }
- }
-
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
@@ -290,14 +222,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
const json = JSON.stringify(state.toJSON());
- let unchanged = true;
const effectiveAcl = GetEffectiveAcl(this.dataDoc);
- const removeSelection = (json: string | undefined) => {
- return json?.indexOf("\"storedMarks\"") === -1 ? json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
- };
+ const removeSelection = (json: string | undefined) => json?.indexOf("\"storedMarks\"") === -1 ?
+ json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
+ let unchanged = true;
if (this._applyingChange !== this.fieldKey && removeSelection(json) !== removeSelection(curProto?.Data)) {
this._applyingChange = this.fieldKey;
(curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
@@ -309,9 +240,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this.dataDoc[this.props.fieldKey + "-noTemplate"] = true;//(curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
unchanged = false;
-
}
-
} else { // if we've deleted all the text in a note driven by a template, then restore the template data
this.dataDoc[this.props.fieldKey] = undefined;
this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
@@ -321,7 +250,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._applyingChange = "";
if (!unchanged) {
this.updateTitle();
- this.tryUpdateHeight();
+ this.tryUpdateScrollHeight();
}
}
} else {
@@ -381,25 +310,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
let node = this._editorView.state.doc;
while (node.firstChild && node.firstChild.type.name !== "text") node = node.firstChild;
const str = node.textContent;
- const titlestr = str.substr(0, Math.min(40, str.length));
- this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
+ this.dataDoc.title = "-" + str.substr(0, Math.min(40, str.length)) + (str.length > 40 ? "..." : "");
}
}
// needs a better API for taking in a set of words with target documents instead of just one target
public hyperlinkTerms = (terms: string[], target: Doc) => {
if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
- const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
- const tr = this._editorView.state.tr;
- const flattened: TextSelection[] = [];
- res.map(r => r.map(h => flattened.push(h)));
- const lastSel = Math.min(flattened.length - 1, this._searchIndex);
- this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
- const anchor = new Doc();
- const alink = DocUtils.MakeLink({ doc: anchor }, { doc: target }, "automatic")!;
- const allAnchors = [{ href: Utils.prepend("/doc/" + anchor[Id]), title: "a link", anchorId: anchor[Id] }];
- const link = this._editorView.state.schema.marks.linkAnchor.create({ allAnchors, title: "a link", location });
- this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
+ const res1 = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+ let tr = this._editorView.state.tr;
+ const flattened1: TextSelection[] = [];
+ res1.map(r => r.map(h => flattened1.push(h)));
+ flattened1.forEach((flat, i) => {
+ const flattened: TextSelection[] = [];
+ const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+ res.map(r => r.map(h => flattened.push(h)));
+ this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+ const anchor = Docs.Create.TextanchorDocument();
+ const alink = DocUtils.MakeLink({ doc: anchor }, { doc: target }, "automatic")!;
+ const allAnchors = [{ href: Utils.prepend("/doc/" + anchor[Id]), title: "a link", anchorId: anchor[Id] }];
+ const link = this._editorView!.state.schema.marks.linkAnchor.create({ allAnchors, title: "auto link", location });
+ tr = tr.addMark(flattened[i].from, flattened[i].to, link);
+ });
+ this._editorView.dispatch(tr);
}
}
public highlightSearchTerms = (terms: string[], backward: boolean) => {
@@ -460,7 +393,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@undoBatch
@action
- drop = async (e: Event, de: DragManager.DropEvent) => {
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = this.getAnchor;
const dragData = de.complete.docDragData;
if (dragData) {
const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0];
@@ -483,22 +417,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
});
const view = this._editorView!;
view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
- this.tryUpdateHeight();
e.stopPropagation();
// }
} // otherwise, fall through to outer collection to handle drop
- } else if (de.complete.linkDragData) {
- de.complete.linkDragData.linkDropCallback = this.linkDrop;
- }
- else if (de.complete.annoDragData) {
- de.complete.annoDragData.linkDropCallback = this.linkDrop;
}
}
- linkDrop = (data: { linkDocument: Doc }) => {
- const anchor1Title = data.linkDocument.anchor1 instanceof Doc ? StrCast(data.linkDocument.anchor1.title) : "-untitled-";
- const anchor1 = data.linkDocument.anchor1 instanceof Doc ? data.linkDocument.anchor1 : undefined;
- this.makeLinkAnchor(anchor1, "add:right", undefined, anchor1Title);
- }
getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null {
let offset = 0;
@@ -523,7 +446,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
-
//Recursively finds matches within a given node
findInNode(pm: EditorView, node: Node, find: string) {
let ret: TextSelection[] = [];
@@ -544,8 +466,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
return ret;
}
- static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
+ static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
updateHighlights = () => {
clearStyleSheetRules(FormattedTextBox._userStyleSheet);
if (FormattedTextBox._highlights.indexOf("Audio Tags") === -1) {
@@ -591,22 +513,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
})), false);
}
sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
- const bounds = this.CurrentDiv.getBoundingClientRect();
+ const bounds = this._ref.current!.getBoundingClientRect();
this.layoutDoc._sidebarWidthPercent = "" + 100 * Math.max(0, (1 - (e.clientX - bounds.left) / bounds.width)) + "%";
this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== "0%";
e.preventDefault();
return false;
}
- @undoBatch
- @action
- toggleNativeDimensions = () => {
- alert("need to fix");
- // Doc.toggleNativeDimensions(this.layoutDoc, 1, this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0);
- }
- public static get DefaultLayout(): Doc | string | undefined {
- return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
- }
specificContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
@@ -680,78 +593,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
}, icon: "eye"
});
- !Doc.UserDoc().noviceMode && appearanceItems.push({ description: "Create progressivized slide...", event: this.progressivizeText, icon: "desktop" });
cm.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
const options = cm.findByDescription("Options...");
const optionItems = options && "subitems" in options ? options.subitems : [];
- !Doc.UserDoc().noviceMode && optionItems.push({ description: !this.Document._singleLine ? "Make Single Line" : "Make Multi Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
+ optionItems.push({ description: !this.Document._noSidebar ? "Hide Sidebar Handle" : "Show Sidebar Handle", event: () => this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar, icon: "expand-arrows-alt" });
+ optionItems.push({ description: !this.Document._singleLine ? "Make Single Line" : "Make Multi Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
optionItems.push({ description: `${this.Document._autoHeight ? "Lock" : "Auto"} Height`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
- optionItems.push({ description: `${!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? "Lock" : "Unlock"} Aspect`, event: this.toggleNativeDimensions, icon: "snowflake" });
!options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
this._downX = this._downY = Number.NaN;
}
- progressivizeText = () => {
- const list = this.ProseRef?.getElementsByTagName("li");
- const mainBulletText: string[] = [];
- const mainBulletList: Doc[] = [];
- if (list) {
- const newBullets: Doc[] = this.recursiveProgressivize(1, list)[0];
- mainBulletList.push.apply(mainBulletList, newBullets);
- }
- const title = Docs.Create.TextDocument(StrCast(this.rootDoc.title), { title: "Title", _width: 800, _height: 70, x: 20, y: -10, _fontSize: '20pt', backgroundColor: "rgba(0,0,0,0)", appearFrame: 0, _fontWeight: 700 });
- mainBulletList.push(title);
- const doc = Docs.Create.FreeformDocument(mainBulletList, {
- title: StrCast(this.rootDoc.title),
- x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document._height) + 10,
- _width: 400, _height: 225, _fitToBox: true,
- });
- this.props.addDocument?.(doc);
- }
-
- recursiveProgressivize = (nestDepth: number, list: HTMLCollectionOf<HTMLLIElement>, d?: number, y?: number, before?: string): [Doc[], number] => {
- const mainBulletList: Doc[] = [];
- let b = d ? d : 0;
- let yLoc = y ? y : 0;
- let nestCount = 0;
- let count: string = before ? before : '';
- const fontSize: string = (16 - (nestDepth * 2)) + 'pt';
- const xLoc: number = (nestDepth * 20);
- const width: number = 390 - xLoc;
- const height: number = 55 - (nestDepth * 5);
- Array.from(list).forEach(listItem => {
- const mainBullets: number = Number(listItem.getAttribute("data-bulletstyle"));
- if (mainBullets === nestDepth) {
- if (listItem.childElementCount > 1) {
- b++;
- nestCount++;
- yLoc += height;
- count = before ? count + nestCount + "." : nestCount + ".";
- const text = listItem.getElementsByTagName("p")[0].innerText;
- const length = text.length;
- const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _autoHeight: true, x: xLoc, y: (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
- // yLoc += NumCast(bullet1._height);
- mainBulletList.push(bullet1);
- const newList = this.recursiveProgressivize(nestDepth + 1, listItem.getElementsByTagName("li"), b, yLoc, count);
- mainBulletList.push.apply(mainBulletList, newList[0]);
- yLoc += newList.length * (55 - ((nestDepth + 1) * 5));
- } else {
- b++;
- nestCount++;
- yLoc += height;
- count = before ? count + nestCount + "." : nestCount + ".";
- const text = listItem.innerText;
- const length = text.length;
- const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _autoHeight: true, x: xLoc, y: (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
- // yLoc += NumCast(bullet1._height);
- mainBulletList.push(bullet1);
- }
- }
- });
- return [mainBulletList, yLoc];
- }
-
recordDictation = () => {
DictationManager.Controls.listen({
interimHandler: this.setDictationContent,
@@ -791,8 +643,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- _keymap: any = undefined;
- _rules: RichTextRules | undefined;
@computed get config() {
this._keymap = buildKeymap(schema, this.props);
this._rules = new RichTextRules(this.props.Document, this);
@@ -846,7 +696,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return this.active();//this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0;
}
- focusSpeed: Opt<number>;
scrollFocus = (doc: Doc, smooth: boolean) => {
const anchorId = doc[Id];
const findAnchorFrag = (frag: Fragment, editor: EditorView) => {
@@ -878,7 +727,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const ret = findAnchorFrag(editor.state.doc.content, editor);
if (ret.frag.size > 2 && ret.start >= 0) {
- smooth && (this.focusSpeed = 500);
+ smooth && (this._focusSpeed = 500);
let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
if (ret.frag.firstChild) {
selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
@@ -886,23 +735,32 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
const escAnchorId = anchorId[0] >= '0' && anchorId[0] <= '9' ? `\\3${anchorId[0]} ${anchorId.substr(1)}` : anchorId;
addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: "yellow" });
- setTimeout(() => this.focusSpeed = undefined, this.focusSpeed);
- setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this.focusSpeed || 0, 1500));
+ setTimeout(() => this._focusSpeed = undefined, this._focusSpeed);
+ setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 1500));
}
}
- return this.focusSpeed;
+ return this._focusSpeed;
+ }
+
+ // if the scroll height has changed and we're in autoHeight mode, then we need to update the textHeight component of the doc.
+ // Since we also monitor all component height changes, this will update the document's height.
+ resetNativeHeight = (scrollHeight: number) => {
+ const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
+ this.rootDoc[this.fieldKey + "-height"] = scrollHeight + this.titleHeight;
+ if (nh) this.layoutDoc._nativeHeight = scrollHeight;
}
componentDidMount() {
this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
this.props.contentsActive?.(this.IsActive);
this._cachedLinks = DocListCast(this.Document.links);
- this._disposers.sidebarheight = reaction(
- () => ({ annoHeight: NumCast(this.rootDoc[this.annotationKey + "-height"]), textHeight: NumCast(this.rootDoc[this.fieldKey + "-height"]) }),
- ({ annoHeight, textHeight }) => {
- this.layoutDoc._autoHeight && (this.rootDoc._height = Math.max(annoHeight, textHeight));
- });
+ this._disposers.autoHeight = reaction(() => ({ scrollHeight: this.scrollHeight, autoHeight: this.autoHeight, width: NumCast(this.layoutDoc._width) }),
+ ({ width, autoHeight, scrollHeight }) => width && autoHeight && this.resetNativeHeight(scrollHeight)
+ );
+ 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 }),
+ ({ sidebarHeight, textHeight, autoHeight }) => autoHeight && this.props.setHeight(Math.max(sidebarHeight, textHeight)));
this._disposers.links = reaction(() => DocListCast(this.Document.links), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks
newLinks => {
this._cachedLinks.forEach(l => !newLinks.includes(l) && this.RemoveLinkFromDoc(l));
@@ -930,7 +788,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const updatedState = JSON.parse(incomingValue.data.Data);
if (JSON.stringify(this._editorView.state.toJSON()) !== JSON.stringify(updatedState)) {
this._editorView.updateState(EditorState.fromJSON(this.config, updatedState));
- this.tryUpdateHeight();
+ this.tryUpdateScrollHeight();
}
} else if (incomingValue?.str) {
selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue.str)));
@@ -957,21 +815,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
);
- this._disposers.autoHeight = reaction(
- () => ({
- width: NumCast(this.layoutDoc._width),
- autoHeight: this.layoutDoc?._autoHeight
- }),
- ({ width, autoHeight }) => width !== undefined && setTimeout(() => this.tryUpdateHeight(), 0)
- );
- this._disposers.height = reaction(
- () => Cast(this.layoutDoc._height, "number", null),
- action(height => {
- if (height !== undefined && height <= 20 && height < NumCast(this.layoutDoc._delayAutoHeight, 20)) {
- this.layoutDoc._delayAutoHeight = height;
- }
- })
- );
this.setupEditor(this.config, this.props.fieldKey);
@@ -1016,8 +859,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}, { fireImmediately: true }
);
quickScroll = undefined;
-
- setTimeout(() => this.tryUpdateHeight(NumCast(this.layoutDoc.limitHeight)));
+ this.tryUpdateScrollHeight();
}
pushToGoogleDoc = async () => {
@@ -1114,10 +956,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return text;
}
- sliceSingleNode(slice: Slice) {
- return slice.openStart === 0 && slice.openEnd === 0 && slice.content.childCount === 1 ? slice.content.firstChild : null;
- }
-
handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
const cbe = event as ClipboardEvent;
const pdfDocId = cbe.clipboardData?.getData("dash/pdfOrigin");
@@ -1180,7 +1018,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- private isActiveTab(el: Element | null | undefined) {
+ isActiveTab(el: Element | null | undefined) {
while (el && el !== document.body) {
if (getComputedStyle(el).display === "none") return false;
el = el.parentNode as any;
@@ -1188,7 +1026,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return true;
}
- private setupEditor(config: any, fieldKey: string) {
+ richTextMenuPlugin() {
+ const self = this;
+ return new Plugin({
+ view(newView) {
+ runInAction(() => self.props.isSelected(true) && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView));
+ return new RichTextMenuPlugin({ editorProps: this.props });
+ }
+ });
+ }
+ setupEditor(config: any, fieldKey: string) {
const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null);
const rtfField = Cast((!curText?.Text && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
@@ -1202,8 +1049,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const scrollRef = self._scrollRef.current;
if ((docPos.top < viewRect.top || docPos.top > viewRect.bottom) && scrollRef) {
const scrollPos = scrollRef.scrollTop + (docPos.top - viewRect.top) * self.props.ScreenToLocalTransform().Scale;
- if (this.focusSpeed !== undefined) {
- scrollPos && smoothScroll(this.focusSpeed, scrollRef, scrollPos);
+ if (this._focusSpeed !== undefined) {
+ scrollPos && smoothScroll(this._focusSpeed, scrollRef, scrollPos);
} else {
scrollRef.scrollTo({ top: scrollPos });
}
@@ -1215,6 +1062,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
dashComment(node, view, getPos) { return new DashDocCommentView(node, view, getPos); },
dashDoc(node, view, getPos) { return new DashDocView(node, view, getPos, self); },
dashField(node, view, getPos) { return new DashFieldView(node, view, getPos, self); },
+ equation(node, view, getPos) { return new EquationView(node, view, getPos, self); },
summary(node, view, getPos) { return new SummaryView(node, view, getPos); },
ordered_list(node, view, getPos) { return new OrderedListView(); },
footnote(node, view, getPos) { return new FootnoteView(node, view, getPos); }
@@ -1254,18 +1102,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ?? []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
}
}
- getFont(font: string) {
- switch (font) {
- case "Arial": return schema.marks.arial.create();
- case "Times New Roman": return schema.marks.timesNewRoman.create();
- case "Georgia": return schema.marks.georgia.create();
- case "Comic Sans MS": return schema.marks.comicSans.create();
- case "Tahoma": return schema.marks.tahoma.create();
- case "Impact": return schema.marks.impact.create();
- case "ACrimson Textrial": return schema.marks.crimson.create();
- }
- return schema.marks.arial.create();
- }
componentWillUnmount() {
Object.values(this._disposers).forEach(disposer => disposer?.());
@@ -1308,7 +1144,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
this._downX = e.clientX;
this._downY = e.clientY;
- this.doLinkOnDeselect();
this._downEvent = true;
FormattedTextBoxComment.textBox = this;
if (e.button === 0 && (this.props.rootSelected(true) || this.props.isSelected(true)) && !e.altKey && !e.ctrlKey && !e.metaKey) {
@@ -1331,7 +1166,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
onPointerUp = (e: React.PointerEvent): void => {
- FormattedTextBox.CanAnnotate = true;
if (!this._editorView?.state.selection.empty && FormattedTextBox.CanAnnotate) this.setupAnchorMenu();
if (!this._downEvent) return;
this._downEvent = false;
@@ -1339,7 +1173,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const editor = this._editorView!;
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
!this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0))));
- const target = (e.target as any).parentElement; // hrefs are store don the database of the <a> node that wraps the hyerlink <span>
+ let target = (e.target as any).parentElement; // hrefs are stored on the database of the <a> node that wraps the hyerlink <span>
+ while (target && !target.dataset?.targethrefs) target = target.parentElement;
FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs);
}
(e.nativeEvent as any).formattedHandled = true;
@@ -1351,7 +1186,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
onDoubleClick = (e: React.MouseEvent): void => {
- this.doLinkOnDeselect();
FormattedTextBoxComment.textBox = this;
if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // stop propagation if not in sidebar
@@ -1373,7 +1207,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
onFocused = (e: React.FocusEvent): void => {
FormattedTextBox.FocusedBox = this;
- this.tryUpdateHeight();
//applyDevTools.applyDevTools(this._editorView);
// see if we need to preserve the insertion point
@@ -1495,18 +1328,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- menuPlugin: any;
-
- richTextMenuPlugin() {
- const self = this;
- return new Plugin({
- view(newView) {
- runInAction(() => self.props.isSelected(true) && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView));
- return self.menuPlugin = new RichTextMenuPlugin({ editorProps: this.props });
- }
- });
- }
-
public startUndoTypingBatch() {
!this._undoTyping && (this._undoTyping = UndoManager.StartBatch("undoTyping"));
}
@@ -1525,7 +1346,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
FormattedTextBox.HadSelection = window.getSelection()?.toString() !== "";
this.endUndoTypingBatch();
- this.doLinkOnDeselect();
FormattedTextBox.LiveTextUndo?.end();
FormattedTextBox.LiveTextUndo = undefined;
@@ -1544,7 +1364,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- _lastTimedMark: Mark | undefined = undefined;
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))) {
@@ -1573,9 +1392,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
} else {
if (e.key === "Tab" || e.key === "Enter") {
- if (e.key === "Enter") {
- this.insertTime();
- }
+ if (e.key === "Enter") this.insertTime();
e.preventDefault();
}
if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) {
@@ -1598,99 +1415,73 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
-
- @action
- tryUpdateHeight(limitHeight?: number) {
- let scrollHeight = this.ProseRef?.scrollHeight || 0;
- if (this.props.renderDepth && this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
- scrollHeight = scrollHeight * NumCast(this.layoutDoc._viewScale, 1);
- if (limitHeight && scrollHeight > limitHeight) {
- scrollHeight = limitHeight;
- this.layoutDoc.limitHeight = undefined;
- this.layoutDoc._autoHeight = false;
- }
- const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
- const dh = NumCast(this.rootDoc._height);
- const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + this.titleHeight);
- if (this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) {
- // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
- console.log("Delayed height adjustment...");
- setTimeout(() => {
- this.rootDoc._height = newHeight;
- this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined;
- }, 10);
- } else {
- try {
- const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", "")) * NumCast(this.Document._viewScale, 1);
- const outer = this.rootDoc[HeightSym]() - boxHeight - this.titleHeight;
- this.rootDoc[this.fieldKey + "-height"] = newHeight + Math.max(0, outer);
- } catch (e) { console.log("Error in tryUpdateHeight"); }
- }
- } //else this.rootDoc[this.fieldKey + "-height"] = 0;
+ tryUpdateScrollHeight() {
+ const proseHeight = this.ProseRef?.scrollHeight || 0;
+ const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+ if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+ const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
+ if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
+ setScrollHeight();
+ } else setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
+ }
}
+ fitToBox = () => this.props.Document._fitToBox;
+ sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+ sidebarAddDocument = (doc: Doc | Doc[]) => this.addDocument(doc, this.SidebarKey);
+ sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
+ sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
+ setSidebarHeight = (height: number) => this.rootDoc[this.SidebarKey + "-height"] = height;
+ sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
+ sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.scaling?.() || 1), 0).scale(1 / NumCast(this.layoutDoc._viewScale, 1));
+
@computed get audioHandle() {
- return !this.layoutDoc._showAudio ? (null) :
- <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
- <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
- </div>;
+ return <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
+ <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
+ </div>;
}
-
@computed get sidebarHandle() {
const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length;
- return this.props.noSidebar || (!this.props.isSelected() && !(annotated && !this.sidebarWidth())) ? (null) :
- <div className="formattedTextBox-sidebar-handle"
- style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: annotated ? "lightblue" : this.props.styleProvider?.(this.props.Document, this.props, StyleProp.WidgetColor) }}
- onPointerDown={this.sidebarDown}
- />;
+ return <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
+ style={{
+ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`,
+ background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : ""))
+ }} />;
}
-
- sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
- fitToBox = () => this.props.Document._fitToBox;
- sidebarAddDocument = (doc: Doc | Doc[]) => this.addDocument(doc, this.SidebarKey);
- sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
- sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
@computed get sidebarCollection() {
- const collectionProps: SubCollectionViewProps & collectionFreeformViewProps = {
- ...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit,
- NativeWidth: returnZero,
- NativeHeight: returnZero,
- PanelHeight: this.props.PanelHeight,
- PanelWidth: this.sidebarWidth,
- xMargin: 0,
- yMargin: 0,
- chromeStatus: "enabled",
- scaleField: this.SidebarKey + "-scale",
- isAnnotationOverlay: false,
- fieldKey: this.SidebarKey,
- fitContentsToDoc: this.fitToBox,
- select: emptyFunction,
- active: this.annotationsActive,
- scaling: this.sidebarContentScaling,
- whenActiveChanged: this.whenActiveChanged,
- removeDocument: this.sidebarRemDocument,
- moveDocument: this.sidebarMoveDocument,
- addDocument: this.sidebarAddDocument,
- CollectionView: undefined,
- ScreenToLocalTransform: this.sidebarScreenToLocal,
- renderDepth: this.props.renderDepth + 1,
+ const renderComponent = (tag: string) => {
+ const ComponentTag = tag === "freeform" ? CollectionFreeFormView : tag === "translation" ? FormattedTextBox : CollectionStackingView;
+ return <ComponentTag
+ {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ PanelHeight={this.props.PanelHeight}
+ PanelWidth={this.sidebarWidth}
+ xMargin={0}
+ yMargin={0}
+ chromeStatus={"enabled"}
+ scaleField={this.SidebarKey + "-scale"}
+ isAnnotationOverlay={false}
+ setHeight={this.setSidebarHeight}
+ fitContentsToDoc={this.fitToBox}
+ select={emptyFunction}
+ active={this.annotationsActive}
+ scaling={this.sidebarContentScaling}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.sidebarRemDocument}
+ moveDocument={this.sidebarMoveDocument}
+ addDocument={this.sidebarAddDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={this.sidebarScreenToLocal}
+ renderDepth={this.props.renderDepth + 1}
+ noSidebar={true}
+ fieldKey={this.layoutDoc.sidebarViewType === "translation" ? `${this.fieldKey}-translation` : this.SidebarKey} />;
};
- return this.props.noSidebar || !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
- <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
- style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
- {this.layoutDoc.sidebarViewType === "translation" ?
- <FormattedTextBox {...collectionProps} noSidebar={true} fieldKey={`${this.fieldKey}-translation`} /> :
- this.layoutDoc.sidebarViewType === CollectionViewType.Freeform ?
- <CollectionFreeFormView {...collectionProps} /> :
- <CollectionStackingView {...collectionProps} />}
- </div>;
+ return <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
+ style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+ </div>;
}
-
- @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
- sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
- sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.scaling?.() || 1), 0).scale(1 / NumCast(this.layoutDoc._viewScale, 1));
- @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
render() {
TraceMobx();
const selected = this.props.isSelected();
@@ -1705,19 +1496,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const padding = Math.max(margins + ((selected && !this.layoutDoc._singleLine) || minimal ? -selPad : 0), 0);
const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
return (
- <div className="formattedTextBox-cont" ref={this._boxRef}
+ <div className="formattedTextBox-cont"
style={{
transform: `scale(${scale})`,
transformOrigin: "top left",
width: `${100 / scale}%`,
height: `${100 / scale}%`,
- overflowY: this.layoutDoc._autoHeight ? "hidden" : undefined,
+ // overflowY: this.layoutDoc._autoHeight ? "hidden" : undefined,
...this.styleFromLayoutString(scale) // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._headerHeight}px' >
}}>
<div className={`formattedTextBox-cont`} ref={this._ref}
style={{
- overflow: this.layoutDoc._autoHeight ? "hidden" : undefined,
- height: this.props.height || (this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : undefined),
+ overflow: this.autoHeight ? "hidden" : undefined,
+ height: this.props.height || (this.autoHeight && this.props.renderDepth ? "max-content" : undefined),
background: this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor)),
color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color)),
pointerEvents: interactive ? undefined : "none",
@@ -1751,9 +1542,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}}
/>
</div>
- {this.sidebarCollection}
- {this.sidebarHandle}
- {this.audioHandle}
+ {(this.props.noSidebar || this.Document._noSidebar) || !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) : this.sidebarCollection}
+ {(this.props.noSidebar || this.Document._noSidebar) || this.Document._singleLine ? (null) : this.sidebarHandle}
+ {!this.layoutDoc._showAudio ? (null) : this.audioHandle}
</div>
</div>
);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 15c669338..6821935a0 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -85,7 +85,7 @@ export class FormattedTextBoxComment {
static update(textBox: FormattedTextBox, view: EditorView, lastState?: EditorState, hrefs: string = "") {
FormattedTextBoxComment.textBox = textBox;
if ((hrefs || !lastState?.doc.eq(view.state.doc) || !lastState?.selection.eq(view.state.selection))) {
- FormattedTextBoxComment.setupPreview(view, textBox, hrefs ? hrefs.trim().split(" ") : undefined);
+ FormattedTextBoxComment.setupPreview(view, textBox, hrefs?.trim().split(" "));
}
}
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 243cfc6de..aa51a3a64 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -144,6 +144,10 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
bind("Alt-\\", setBlockType(schema.nodes.paragraph));
bind("Shift-Ctrl-\\", setBlockType(schema.nodes.code_block));
+ bind("Ctrl-m", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
+ dispatch(state.tr.replaceSelectionWith(schema.nodes.equation.create({ fieldKey: "math" + Utils.GenerateGuid() })));
+ })
+
for (let i = 1; i <= 6; i++) {
bind("Shift-Ctrl-" + i, setBlockType(schema.nodes.heading, { level: i }));
}
@@ -255,36 +259,6 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
// bind("Mod-Enter", cmd);
bind("Shift-Enter", cmd);
-
- bind(":", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
- const range = state.selection.$from.blockRange(state.selection.$to, (node: any) => {
- return !node.marks || !node.marks.find((m: any) => m.type === schema.marks.metadata);
- });
-
- const path = (state.doc.resolve(state.selection.from - 1) as any).path;
-
- const spaceSeparator = path[path.length - 3].childCount > 1 ? 0 : -1;
-
- const anchor = range!.end - path[path.length - 3].lastChild.nodeSize + spaceSeparator;
-
- if (anchor >= 0) {
-
- const textsel = TextSelection.create(state.doc, anchor, range!.end);
-
- const text = range ? state.doc.textBetween(textsel.from, textsel.to) : "";
-
- let whitespace = text.length - 1;
-
- for (; whitespace >= 0 && text[whitespace] !== " "; whitespace--) { }
- if (text.endsWith(":")) {
- dispatch(state.tr.addMark(textsel.from + whitespace + 1, textsel.to, schema.marks.metadata.create() as any).
- addMark(textsel.from + whitespace + 1, textsel.to - 2, schema.marks.metadataKey.create() as any));
- }
- }
-
- return false;
- });
-
return keys;
}
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 5d9c8b56d..3bd41fa7d 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -242,6 +242,19 @@ export const nodes: { [index: string]: NodeSpec } = {
}
},
+ equation: {
+ inline: true,
+ attrs: {
+ fieldKey: { default: "" },
+ },
+ group: "inline",
+ draggable: false,
+ toDOM(node) {
+ const attrs = { style: `width: ${node.attrs.width}, height: ${node.attrs.height}` };
+ return ["div", { ...node.attrs, ...attrs }];
+ }
+ },
+
video: {
inline: true,
attrs: {
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index d1fdc6c44..e3d14d620 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -43,7 +43,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable public Status: "marquee" | "annotation" | "" = "";
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string) => Opt<Doc> = (color: string) => undefined;
+ public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
public Delete: () => void = unimplementedFunction;
public AddTag: (key: string, value: string) => boolean = returnFalse;
public PinToPres: () => void = unimplementedFunction;
@@ -76,7 +76,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@action
highlightClicked = (e: React.MouseEvent) => {
- if (!this.Highlight(this.highlightColor) && this.Pinned) {
+ if (!this.Highlight(this.highlightColor, false) && this.Pinned) {
this.Highlighting = !this.Highlighting;
}
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index ca6dc87ae..720d2d92e 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -123,6 +123,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
this.props.startupLive && this.setupPdfJsViewer();
this._mainCont.current?.addEventListener("scroll", e => (e.target as any).scrollLeft = 0);
+ this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight,
+ () => {
+ this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.fieldKey + "-nativeHeight"]);
+ this.props.setHeight(NumCast(this.props.Document[this.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
+ });
+
this._disposers.searchMatch = reaction(() => Doc.IsSearchMatch(this.rootDoc),
m => {
if (m) (this._lastSearch = true) && this.search(Doc.SearchQuery(), m.searchMatch > 0);
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 553443931..c82d03fce 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -565,7 +565,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
removeDocument={returnFalse}
PanelHeight={this.open ? this.returnHeight : returnZero}
PanelWidth={this.open ? this.returnLength : returnZero}
- overflow={length > window.innerWidth || this.children > 6 ? true : false}
+ scrollOverflow={length > window.innerWidth || this.children > 6 ? true : false}
focus={this.selectElement}
ScreenToLocalTransform={Transform.Identity}
/>