aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-05-06 02:01:08 -0400
committerBob Zeleznik <zzzman@gmail.com>2020-05-06 02:01:08 -0400
commitfa826d828b0fc20afde675ffb060e4f24ca310d3 (patch)
treed4e3d9aadb867b7f3f2d407e69c17f72ee445a61
parentd179ac9a6e01fb7d917b4b5fdb56374c697752ce (diff)
fixed makeClone to handle text hyperlinks fixed documentBox background color. fixed formattedtextbox sidebar clicking to sto propagation.
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/nodes/DocHolderBox.scss1
-rw-r--r--src/client/views/nodes/DocHolderBox.tsx5
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx123
-rw-r--r--src/new_fields/Doc.ts72
-rw-r--r--src/new_fields/documentSchemas.ts1
6 files changed, 92 insertions, 114 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 1a285d4ec..e67f2f3a2 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -300,7 +300,7 @@ export class MainView extends React.Component {
defaultBackgroundColors = (doc: Doc) => {
if (this.darkScheme) {
- switch (doc.type) {
+ switch (doc?.type) {
case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d";
case DocumentType.LINK:
case DocumentType.COL: {
@@ -309,7 +309,7 @@ export class MainView extends React.Component {
default: return "black";
}
} else {
- switch (doc.type) {
+ switch (doc?.type) {
case DocumentType.RTF: return "#f1efeb";
case DocumentType.BUTTON:
case DocumentType.LABEL: return "lightgray";
diff --git a/src/client/views/nodes/DocHolderBox.scss b/src/client/views/nodes/DocHolderBox.scss
index 4949d16a3..6a9ef0b6f 100644
--- a/src/client/views/nodes/DocHolderBox.scss
+++ b/src/client/views/nodes/DocHolderBox.scss
@@ -2,7 +2,6 @@
width: 100%;
height: 100%;
pointer-events: all;
- background: rgb(241, 239, 235);
position: absolute;
.documentBox-lock {
margin: auto;
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index 17b2daabc..af8dc704c 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -122,6 +122,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
ContainingCollectionView={this as any} // bcz: hack! need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked. currently, the up selector allows only a containing collection to be selected
ContainingCollectionDoc={undefined}
fitToBox={true}
+ backgroundColor={this.props.backgroundColor}
LayoutTemplateString={layoutTemplate}
LayoutTemplate={this.layoutTemplateDoc}
rootSelected={this.props.isSelected}
@@ -149,6 +150,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
ContainingCollectionView={this as any} // bcz: hack! need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked. currently, the up selector allows only a containing collection to be selected
ContainingCollectionDoc={undefined}
fitToBox={true}
+ backgroundColor={this.props.backgroundColor}
ignoreAutoHeight={true}
LayoutTemplateString={layoutTemplate}
LayoutTemplate={this.layoutTemplateDoc}
@@ -174,12 +176,13 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
return contents;
}
render() {
+ const containedDoc = Cast(this.dataDoc[this.fieldKey], Doc, null);
TraceMobx();
return <div className="documentBox-container" ref={this._contRef}
onContextMenu={this.specificContextMenu}
onPointerDown={this.onPointerDown} onClick={this.onClick}
style={{
- background: StrCast(this.layoutDoc.backgroundColor),
+ background: this.props.backgroundColor?.(containedDoc),
border: `#00000021 solid ${this.xPad}px`,
borderTop: `#0000005e solid ${this.yPad}px`,
borderBottom: `#0000005e solid ${this.yPad}px`,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 5dc22d6f6..bccf569f8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -23,7 +23,7 @@ import { RichTextUtils } from '../../../../new_fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../../new_fields/Schema";
import { Cast, DateCast, NumCast, StrCast } from "../../../../new_fields/Types";
import { TraceMobx } from '../../../../new_fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils } from '../../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from '../../../documents/Documents';
@@ -72,7 +72,7 @@ export interface FormattedTextBoxProps {
}
const richTextSchema = createSchema({
- documentText: "string"
+ documentText: "string",
});
export const GoogleRef = "googleDocId";
@@ -93,9 +93,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
private _editorView: Opt<EditorView>;
private _applyingChange: boolean = false;
private _searchIndex = 0;
- private _sidebarMovement = 0;
- private _lastX = 0;
- private _lastY = 0;
private _undoTyping?: UndoManager.Batch;
private _disposers: { [name: string]: IReactionDisposer } = {};
private dropDisposer?: DragManager.DragDropDisposer;
@@ -161,7 +158,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
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.props.Document }, { doc: this.dataDoc[key] as Doc }, "link to named target", id);
+ else DocUtils.MakeLink({ doc: this.rootDoc }, { doc: this.dataDoc[key] as Doc }, "link to named target", id);
});
});
});
@@ -199,7 +196,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const tsel = this._editorView.state.selection.$from;
tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000)));
const curText = state.doc.textBetween(0, state.doc.content.size, " \n");
- const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField); // the actual text in the text box
+ const curTemp = Cast(this.layoutDoc[this.props.fieldKey + "-textTemplate"], RichTextField); // the actual text in the text box
const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
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());
@@ -207,7 +204,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._applyingChange = true;
this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if (curText !== curLayout?.Text) {
+ if (json !== curLayout?.Data) {
this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText);
this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
}
@@ -241,7 +238,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
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 alink = DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, "automatic")!;
+ const alink = DocUtils.MakeLink({ doc: this.rootDoc }, { doc: target }, "automatic")!;
const link = this._editorView.state.schema.marks.link.create({
href: Utils.prepend("/doc/" + alink[Id]),
title: "a link", location: location, linkId: alink[Id], targetId: target[Id]
@@ -280,7 +277,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
protected createDropTarget = (ele: HTMLDivElement) => {
this.ProseRef = ele;
this.dropDisposer?.();
- ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
+ ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc));
}
@undoBatch
@@ -399,26 +396,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
sidebarDown = (e: React.PointerEvent) => {
- this._lastX = e.clientX;
- this._lastY = e.clientY;
- this._sidebarMovement = 0;
- document.addEventListener("pointermove", this.sidebarMove);
- document.addEventListener("pointerup", this.sidebarUp);
- e.stopPropagation();
- e.preventDefault(); // prevents text from being selected during drag
+ setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction,
+ () => (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"));
}
- sidebarMove = (e: PointerEvent) => {
+ sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
const bounds = this.CurrentDiv.getBoundingClientRect();
- this._sidebarMovement += Math.sqrt((e.clientX - this._lastX) * (e.clientX - this._lastX) + (e.clientY - this._lastY) * (e.clientY - this._lastY));
- this.props.Document.sidebarWidthPercent = "" + 100 * (1 - (e.clientX - bounds.left) / bounds.width) + "%";
- }
- sidebarUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.sidebarMove);
- document.removeEventListener("pointerup", this.sidebarUp);
+ this.layoutDoc._sidebarWidthPercent = "" + 100 * (1 - (e.clientX - bounds.left) / bounds.width) + "%";
+ return false;
}
- toggleSidebar = () => this._sidebarMovement < 5 && (this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%");
-
public static get DefaultLayout(): Doc | string | undefined {
return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
}
@@ -426,12 +412,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const cm = ContextMenu.Instance;
const funcs: ContextMenuProps[] = [];
- this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" });
+ this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
!this.layoutDoc.isTemplateDoc && funcs.push({
description: "Make Template", event: () => {
this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc);
- Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.props.Document);
+ Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
}, icon: "eye"
});
this.layoutDoc.isTemplateDoc && funcs.push({
@@ -451,9 +437,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
}, icon: "eye"
});
- funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" });
- funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" });
- funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Single Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" });
const highlighting: ContextMenuProps[] = [];
@@ -480,7 +466,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
DocListCast(noteTypesDoc?.data).forEach(note => {
changeItems.push({
description: StrCast(note.title), event: undoBatch(() => {
- Doc.setNativeView(this.props.Document);
+ Doc.setNativeView(this.rootDoc);
Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note);
}), icon: "eye"
});
@@ -517,7 +503,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
toggleMenubar = () => {
- this.props.Document._chromeStatus = this.props.Document._chromeStatus === "disabled" ? "enabled" : "disabled";
+ this.layoutDoc._chromeStatus = this.layoutDoc._chromeStatus === "disabled" ? "enabled" : "disabled";
}
recordBullet = async () => {
@@ -630,10 +616,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
);
this._disposers.editorState = reaction(
() => {
- if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document[this.props.fieldKey + "-textTemplate"]) {
+ if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.layoutDoc[this.props.fieldKey + "-textTemplate"]) {
return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data;
}
- return Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField, null)?.Data;
+ return Cast(this.layoutDoc[this.props.fieldKey + "-textTemplate"], RichTextField, null)?.Data;
},
incomingValue => {
if (incomingValue !== undefined && this._editorView && !this._applyingChange) {
@@ -690,7 +676,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const nodes: Node[] = [];
frag.forEach((node, index) => {
const examinedNode = findLinkNode(node, editor);
- if (examinedNode && examinedNode.textContent) {
+ if (examinedNode?.textContent) {
nodes.push(examinedNode);
start += index;
}
@@ -707,7 +693,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return linkIndex !== -1 && scrollToLinkID === marks[linkIndex].attrs.href.replace(/.*\/doc\//, "") ? node : undefined;
};
- let start = -1;
+ let start = 0;
if (this._editorView && scrollToLinkID) {
const editor = this._editorView;
const ret = findLinkFrag(editor.state.doc.content, editor);
@@ -728,7 +714,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
},
{ fireImmediately: true }
);
- this._disposers.scroll = reaction(() => NumCast(this.props.Document.scrollPos),
+ this._disposers.scroll = reaction(() => NumCast(this.layoutDoc.scrollPos),
pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true }
);
@@ -849,7 +835,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
targetAnnotations?.push(pdfRegion);
});
- const link = DocUtils.MakeLink({ doc: this.props.Document }, { doc: pdfRegion }, "PDF pasted");
+ const link = DocUtils.MakeLink({ doc: this.rootDoc }, { doc: pdfRegion }, "PDF pasted");
if (link) {
cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
const linkId = link[Id];
@@ -886,8 +872,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
private setupEditor(config: any, fieldKey: string) {
const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null);
- const useTemplate = !curText?.Text && this.props.Document[this.props.fieldKey + "-textTemplate"];
- const rtfField = Cast((useTemplate && this.props.Document[this.props.fieldKey + "-textTemplate"]) || this.dataDoc[fieldKey], RichTextField);
+ const useTemplate = !curText?.Text && this.layoutDoc[this.props.fieldKey + "-textTemplate"];
+ const rtfField = Cast((useTemplate && this.layoutDoc[this.props.fieldKey + "-textTemplate"]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
const self = this;
this._editorView?.destroy();
@@ -983,9 +969,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if (this.props.onClick && e.button === 0 && !this.props.isSelected(false)) {
e.preventDefault();
}
- if (e.button === 0 && this.active(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
- if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // don't stop propagation if clicking in the sidebar
- //e.stopPropagation();
+ 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
+ e.stopPropagation(); // if the text box is selected, then it consumes all down events
}
}
if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
@@ -1023,7 +1009,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
// jump rich text menu to this textbox
const bounds = this._ref.current?.getBoundingClientRect();
- if (bounds && this.props.Document._chromeStatus !== "disabled") {
+ if (bounds && this.layoutDoc._chromeStatus !== "disabled") {
const x = Math.min(Math.max(bounds.left, 0), window.innerWidth - RichTextMenu.Instance.width);
let y = Math.min(Math.max(0, bounds.top - RichTextMenu.Instance.height - 50), window.innerHeight - RichTextMenu.Instance.height);
if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) {
@@ -1059,43 +1045,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; }
(e.nativeEvent as any).formattedHandled = true;
- // if (e.button === 0 && ((!this.props.isSelected(true) && !e.ctrlKey) || (this.props.isSelected(true) && e.ctrlKey)) && !e.metaKey && e.target) {
- // let href = (e.target as any).href;
- // let location: string;
- // if ((e.target as any).attributes.location) {
- // location = (e.target as any).attributes.location.value;
- // }
- // let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
- // let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos);
- // if (node) {
- // let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link);
- // if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above).
- // href = link && link.attrs.href;
- // location = link && link.attrs.location;
- // }
- // }
- // if (href) {
- // if (href.indexOf(Utils.prepend("/doc/")) === 0) {
- // let linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
- // if (linkClicked) {
- // DocServer.GetRefField(linkClicked).then(async linkDoc => {
- // (linkDoc instanceof Doc) &&
- // DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, location ? location : "inTab"), false);
- // });
- // }
- // } else {
- // let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.layoutDoc.x, 0) + NumCast(this.layoutDoc.width, 0), y: NumCast(this.layoutDoc.y) });
- // this.props.addDocument && this.props.addDocument(webDoc);
- // }
- // e.stopPropagation();
- // e.preventDefault();
- // }
- // }
if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientX - this._downX) < 4) {
this.props.select(e.ctrlKey);
this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false);
}
+ if (this.props.isSelected(true)) { // if text box is selected, then it consumes all click events
+ e.stopPropagation();
+ }
}
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
@@ -1212,7 +1169,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
onscrolled = (ev: React.UIEvent) => {
- this.props.Document.scrollPos = this._scrollRef.current!.scrollTop;
+ this.layoutDoc.scrollPos = this._scrollRef.current!.scrollTop;
}
@action
tryUpdateHeight(limitHeight?: number) {
@@ -1243,7 +1200,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); }
+ @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0);
@computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
@@ -1306,8 +1263,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
}} />
</div>
- {!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
- <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} onClick={e => this.toggleSidebar()} /> :
+ {!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} /> :
<div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")}
style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
<CollectionFreeFormView {...this.props}
@@ -1331,9 +1288,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
renderDepth={this.props.renderDepth + 1}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
</CollectionFreeFormView>
- <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} onClick={e => this.toggleSidebar()} />
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} />
</div>}
- {!this.props.Document._showAudio ? (null) :
+ {!this.layoutDoc._showAudio ? (null) :
<div className="formattedTextBox-dictation"
onPointerDown={e => {
runInAction(() => this._recording = !this._recording);
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index b41007e9c..2d4a4539e 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -6,7 +6,7 @@ import { DocumentType } from "../client/documents/DocumentTypes";
import { Scripting, scriptingGlobal } from "../client/util/Scripting";
import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper";
import { UndoManager } from "../client/util/UndoManager";
-import { intersectRect } from "../Utils";
+import { intersectRect, Utils } from "../Utils";
import { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update, Copy } from "./FieldSymbols";
import { List } from "./List";
import { ObjectField } from "./ObjectField";
@@ -20,6 +20,7 @@ import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, u
import { Docs, DocumentOptions } from "../client/documents/Documents";
import { PdfField, VideoField, AudioField, ImageField } from "./URLField";
import { LinkManager } from "../client/util/LinkManager";
+import { string32 } from "../../deploy/assets/pdf.worker";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -590,47 +591,64 @@ export namespace Doc {
return copy;
}
- export function MakeClone(doc: Doc, cloneMap: Map<Doc, Doc> = new Map()): Doc {
+ export function MakeClone(doc: Doc): Doc {
+ let cloneMap = new Map<string, Doc>();
+ let rtfMap: { copy: Doc, key: string, field: RichTextField }[] = [];
+ const copy = Doc.makeClone(doc, cloneMap, rtfMap);
+ rtfMap.map(({ copy, key, field }) => {
+ const replacer = (match: any, attr: string, id: string, offset: any, string: any) => {
+ const mapped = cloneMap.get(id);
+ return attr + "\"" + (mapped ? mapped[Id] : id) + "\"";
+ };
+ const replacer2 = (match: any, href: string, id: string, offset: any, string: any) => {
+ const mapped = cloneMap.get(id);
+ return href + (mapped ? mapped[Id] : id);
+ };
+ const regex = `(${Utils.prepend("/doc/")})([^"]*)`;
+ var re = new RegExp(regex, "g");
+ copy[key] = new RichTextField(field.Data.replace(/("docid":|"targetId":|"linkId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text);
+ });
+ return copy;
+ }
+
+ export function makeClone(doc: Doc, cloneMap: Map<string, Doc>, rtfs: { copy: Doc, key: string, field: RichTextField }[]): Doc {
if (Doc.IsBaseProto(doc)) return doc;
- if (cloneMap.get(doc)) return cloneMap.get(doc)!;
+ if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!;
const copy = new Doc(undefined, true);
- cloneMap.set(doc, copy);
- if (LinkManager.Instance.getAllLinks().includes(doc)) LinkManager.Instance.addLink(copy);
+ cloneMap.set(doc[Id], copy);
+ if (LinkManager.Instance.getAllLinks().includes(doc) && LinkManager.Instance.getAllLinks().indexOf(copy) === -1) LinkManager.Instance.addLink(copy);
const exclude = Cast(doc.excludeFields, listSpec("string"), []);
Object.keys(doc).forEach(key => {
if (exclude.includes(key)) return;
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const field = ProxyField.WithoutProxy(() => doc[key]);
+ const copyObjectField = (field: ObjectField) => {
+ const list = Cast(doc[key], listSpec(Doc));
+ if (list !== undefined && !(list instanceof Promise)) {
+ copy[key] = new List<Doc>(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs)));
+ } else if (doc[key] instanceof Doc)
+ copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields
+ else {
+ copy[key] = ObjectField.MakeCopy(field);
+ if (field instanceof RichTextField) {
+ if (field.Data.includes('"docid":') || field.Data.includes('"targetId":') || field.Data.includes('"linkId":')) {
+ rtfs.push({ copy, key, field });
+ }
+ }
+ }
+ }
if (key === "proto") {
if (doc[key] instanceof Doc) {
- copy[key] = Doc.MakeClone(doc[key]!, cloneMap);
+ copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs);
}
} else {
if (field instanceof RefField) {
copy[key] = field;
} else if (cfield instanceof ComputedField) {
copy[key] = ComputedField.MakeFunction(cfield.script.originalScript);
- if (field instanceof ObjectField) {
- const list = Cast(doc[key], listSpec(Doc));
- if (list !== undefined && !(list instanceof Promise)) {
- copy[key] = new List<Doc>(list.filter(d => d instanceof Doc).map(d => Doc.MakeClone(d as Doc, cloneMap)));
- } else {
- copy[key] = doc[key] instanceof Doc ?
- key.includes("layout[") ?
- undefined : Doc.MakeClone(doc[key] as Doc, cloneMap) : // reference documents except copy documents that are expanded teplate fields
- ObjectField.MakeCopy(field);
- }
- }
+ (key === "links" && field instanceof ObjectField) && copyObjectField(field);
} else if (field instanceof ObjectField) {
- const list = Cast(doc[key], listSpec(Doc));
- if (list !== undefined && !(list instanceof Promise)) {
- copy[key] = new List<Doc>(list.filter(d => d instanceof Doc).map(d => Doc.MakeClone(d as Doc, cloneMap)));
- } else {
- copy[key] = doc[key] instanceof Doc ?
- key.includes("layout[") ?
- undefined : Doc.MakeClone(doc[key] as Doc, cloneMap) : // reference documents except copy documents that are expanded teplate fields
- ObjectField.MakeCopy(field);
- }
+ copyObjectField(field);
} else if (field instanceof Promise) {
debugger; //This shouldn't happend...
} else {
@@ -640,7 +658,7 @@ export namespace Doc {
});
Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true);
copy.cloneOf = doc;
- cloneMap.set(doc, copy);
+ cloneMap.set(doc[Id], copy);
return copy;
}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index e7d27d81e..cacba43b6 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -44,6 +44,7 @@ export const documentSchema = createSchema({
_chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed'
_fontSize: "number",
_fontFamily: "string",
+ _sidebarWidthPercent: "string", // percent of text window width taken up by sidebar
// appearance properties on the data document
backgroundColor: "string", // background color of document