aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/DropConverter.ts8
-rw-r--r--src/client/util/RichTextRules.ts62
-rw-r--r--src/client/util/RichTextSchema.tsx97
-rw-r--r--src/client/views/DocComponent.tsx4
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx4
-rw-r--r--src/client/views/nodes/FieldView.tsx6
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx2
7 files changed, 104 insertions, 79 deletions
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 9c068d2d7..8d92de28f 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -4,7 +4,9 @@ import { DocumentType } from "../documents/DocumentTypes";
import { ObjectField } from "../../new_fields/ObjectField";
import { StrCast } from "../../new_fields/Types";
import { Docs } from "../documents/Documents";
-import { ScriptField } from "../../new_fields/ScriptField";
+import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
+import { RichTextField } from "../../new_fields/RichTextField";
+import { Compute } from "google-auth-library";
export function makeTemplate(doc: Doc): boolean {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
@@ -18,6 +20,10 @@ export function makeTemplate(doc: Doc): boolean {
Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc));
} else if (d.type === DocumentType.COL) {
any = makeTemplate(d) || any;
+ } else if (d.data instanceof RichTextField) {
+ d._textTemplate = ComputedField.MakeFunction("copyField(this.data)", { this: Doc.name });
+ d.isTemplateForField = "data";
+ any = true;
}
});
return any;
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index bc8a0abb1..0de0e21fd 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -2,14 +2,15 @@ import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from
import { schema } from "./RichTextSchema";
import { wrappingInputRule } from "./prosemirrorPatches";
import { NodeSelection, TextSelection } from "prosemirror-state";
-import { StrCast, Cast } from "../../new_fields/Types";
-import { Doc } from "../../new_fields/Doc";
+import { StrCast, Cast, NumCast } from "../../new_fields/Types";
+import { Doc, DataSym } from "../../new_fields/Doc";
import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
import { Docs, DocUtils } from "../documents/Documents";
import { Id } from "../../new_fields/FieldSymbols";
import { DocServer } from "../DocServer";
import { returnFalse, Utils } from "../../Utils";
import RichTextMenu from "./RichTextMenu";
+import { RichTextField } from "../../new_fields/RichTextField";
export const inpRules = {
rules: [
@@ -70,36 +71,26 @@ export const inpRules = {
return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: size }));
}),
- // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode)
+ // create a text display of a metadata field
new InputRule(
- new RegExp(/!$/),
+ new RegExp(/\[\[([a-zA-Z_ \-0-9]+)\]\]$/),
(state, match, start, end) => {
- if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null;
- const value = state.doc.textBetween(start, end);
-
- const node = (state.doc.resolve(start) as any).nodeAfter;
- const sm = state.storedMarks || undefined;
- const fieldView = state.schema.nodes.dashField.create({ fieldKey: StrCast(value) });
- const replaced = node ? state.tr.replaceRangeWith(start, end, fieldView).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
- return replaced.doc.nodeSize > end - 2 ? replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))) : replaced;
+ const fieldKey = match[1];
+ const fieldView = state.schema.nodes.dashField.create({ fieldKey: StrCast(fieldKey) });
+ return state.tr.deleteRange(start, end).insert(start, fieldView);
}),
- // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode)
+ // create a hyperlink portal
new InputRule(
- new RegExp(/@$/),
+ new RegExp(/\[\[:([a-zA-Z_ \-0-9]+)\]\]$/),
(state, match, start, end) => {
- if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null;
-
- const value = state.doc.textBetween(start, end);
- if (value) {
- DocServer.GetRefField(value).then(docx => {
- const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: value, _width: 500, _height: 500, }, value);
- DocUtils.Publish(target, value, returnFalse, returnFalse);
- DocUtils.MakeLink({ doc: (schema as any).Document }, { doc: target }, "portal link", "");
- });
- const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + value), location: "onRight", title: value, targetId: value });
- return state.tr.addMark(start, end, link);
- }
- return state.tr;
+ const docId = match[1].substring(1);
+ DocServer.GetRefField(docId).then(docx => {
+ const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: docId, _width: 500, _height: 500, }, docId);
+ DocUtils.Publish(target, docId, returnFalse, returnFalse);
+ DocUtils.MakeLink({ doc: (schema as any).Document }, { doc: target }, "portal link", "");
+ });
+ const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + docId), location: "onRight", title: docId, targetId: docId });
+ return state.tr.addMark(start, end, link);
}),
// stop using active style
new InputRule(
@@ -209,10 +200,21 @@ export const inpRules = {
new InputRule(
new RegExp(/%#$/),
(state, match, start, end) => {
- const target = Docs.Create.TextDocument("", { _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
+ const textDoc = Doc.GetProto(Cast((schema as any).Document[DataSym], Doc, null)!);
+ const numInlines = NumCast(textDoc.inlineTextCount);
+ textDoc.inlineTextCount = numInlines + 1;
+ const inlineFieldKey = "inline" + numInlines;
+ const textDocInline = Docs.Create.TextDocument("", { _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: textDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
+ textDocInline.layoutKey = "layout_" + inlineFieldKey;
+ textDocInline.customTitle = true;
+ textDocInline.title = "inline";
+ textDocInline.isTemplateForField = inlineFieldKey;
+ textDocInline.proto = textDoc;
+ textDoc[textDocInline.layoutKey] = FormattedTextBox.LayoutString(inlineFieldKey);
+ textDoc[inlineFieldKey] = "-inline-";
const node = (state.doc.resolve(start) as any).nodeAfter;
- const newNode = schema.nodes.dashComment.create({ docid: target[Id] });
- const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: target[Id], float: "right" });
+ const newNode = schema.nodes.dashComment.create({ docid: textDocInline[Id] });
+ const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: textDocInline[Id], float: "right" });
const sm = state.storedMarks || undefined;
const replaced = node ? state.tr.insert(start, newNode).replaceRangeWith(start + 1, end + 1, dashDoc).insertText(" ", start + 2).setStoredMarks([...node.marks, ...(sm ? sm : [])]) :
state.tr;
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 21916e3d6..0deedbe39 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -18,6 +18,7 @@ import { Transform } from "./Transform";
import React = require("react");
import { BoolCast, NumCast, StrCast } from "../../new_fields/Types";
import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
+import { ObjectField } from "../../new_fields/ObjectField";
const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -682,7 +683,7 @@ export class DashDocCommentView {
if (target) {
const expand = target.hidden;
const tr = view.state.tr.setNodeMarkup(target.pos, undefined, { ...target.node.attrs, hidden: target.node.attrs.hidden ? false : true });
- view.dispatch(tr.setSelection(TextSelection.create(tr.doc, getPos() + (expand ? 2 : 1)))); // update the attrs
+ view.dispatch(tr.setSelection(TextSelection.create(tr.doc, getPos() + (expand ? 2 : 1)))); // update the attrs
setTimeout(() => {
expand && DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc));
try { view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.tr.doc, getPos() + (expand ? 2 : 1)))); } catch (e) { }
@@ -734,12 +735,6 @@ export class DashDocView {
this._dashSpan.style.height = node.attrs.height;
this._dashSpan.style.position = "absolute";
this._dashSpan.style.display = "inline-block";
- const removeDoc = () => {
- const pos = getPos();
- const ns = new NodeSelection(view.state.doc.resolve(pos));
- view.dispatch(view.state.tr.setSelection(ns).deleteSelection());
- return true;
- };
this._dashSpan.onpointerleave = () => {
const ele = document.getElementById("DashDocCommentView-" + node.attrs.docid);
if (ele) {
@@ -752,46 +747,24 @@ export class DashDocView {
(ele as HTMLDivElement).style.backgroundColor = "orange";
}
};
+ const removeDoc = () => {
+ const pos = getPos();
+ const ns = new NodeSelection(view.state.doc.resolve(pos));
+ view.dispatch(view.state.tr.setSelection(ns).deleteSelection());
+ return true;
+ };
DocServer.GetRefField(node.attrs.docid).then(async dashDoc => {
if (dashDoc instanceof Doc) {
self._dashDoc = dashDoc;
dashDoc.hideSidebar = true;
- if (node.attrs.width !== dashDoc.width + "px" || node.attrs.height !== dashDoc.height + "px") {
+ if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") {
try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made
- view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc.width + "px", height: dashDoc.height + "px" }));
+ view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc._width + "px", height: dashDoc._height + "px" }));
} catch (e) {
console.log(e);
}
}
- this._reactionDisposer && this._reactionDisposer();
- this._reactionDisposer = reaction(() => dashDoc[HeightSym]() + dashDoc[WidthSym](), () => {
- this._dashSpan.style.height = this._outer.style.height = dashDoc[HeightSym]() + "px";
- this._dashSpan.style.width = this._outer.style.width = dashDoc[WidthSym]() + "px";
- });
- ReactDOM.render(<DocumentView
- Document={dashDoc}
- LibraryPath={tbox.props.LibraryPath}
- fitToBox={BoolCast(dashDoc._fitToBox)}
- addDocument={returnFalse}
- removeDocument={removeDoc}
- ScreenToLocalTransform={this.getDocTransform}
- addDocTab={self._textBox.props.addDocTab}
- pinToPres={returnFalse}
- renderDepth={1}
- PanelWidth={self._dashDoc[WidthSym]}
- PanelHeight={self._dashDoc[HeightSym]}
- focus={self.outerFocus}
- backgroundColor={returnEmptyString}
- parentActive={returnFalse}
- whenActiveChanged={returnFalse}
- bringToFront={emptyFunction}
- zoomToScale={emptyFunction}
- getScale={returnOne}
- dontRegisterView={false}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- ContentScaling={this.contentScaling}
- />, this._dashSpan);
+ self.doRender(dashDoc, removeDoc);
}
});
const self = this;
@@ -807,6 +780,49 @@ export class DashDocView {
this._outer.appendChild(this._dashSpan);
(this as any).dom = this._outer;
}
+ doRender(dashDoc: Doc, removeDoc: any) {
+ const self = this;
+ const finalLayout = Doc.expandTemplateLayout(dashDoc, this._textBox.dataDoc);
+ if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc), 0);
+ else {
+ const layoutKey = StrCast(finalLayout.layoutKey);
+ const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1];
+ if (finalLayout !== dashDoc && finalKey) {
+ const finalLayoutField = finalLayout[finalKey]
+ finalLayoutField instanceof ObjectField && (finalLayout._textTemplate = ObjectField.MakeCopy(finalLayoutField));
+ }
+ this._reactionDisposer && this._reactionDisposer();
+ this._reactionDisposer = reaction(() => [finalLayout[WidthSym](), finalLayout[HeightSym]()], (dim) => {
+ this._dashSpan.style.width = this._outer.style.width = dim[0] + "px";
+ this._dashSpan.style.height = this._outer.style.height = dim[1] + "px";
+ }, { fireImmediately: true });
+ ReactDOM.render(<DocumentView
+ Document={finalLayout}
+ DataDoc={this._textBox.dataDoc}
+ LibraryPath={this._textBox.props.LibraryPath}
+ fitToBox={BoolCast(dashDoc._fitToBox)}
+ addDocument={returnFalse}
+ removeDocument={removeDoc}
+ ScreenToLocalTransform={this.getDocTransform}
+ addDocTab={this._textBox.props.addDocTab}
+ pinToPres={returnFalse}
+ renderDepth={1}
+ PanelWidth={finalLayout[WidthSym]}
+ PanelHeight={finalLayout[HeightSym]}
+ focus={this.outerFocus}
+ backgroundColor={returnEmptyString}
+ parentActive={returnFalse}
+ whenActiveChanged={returnFalse}
+ bringToFront={emptyFunction}
+ zoomToScale={emptyFunction}
+ getScale={returnOne}
+ dontRegisterView={false}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ ContentScaling={this.contentScaling}
+ />, this._dashSpan);
+ }
+ }
destroy() {
this._reactionDisposer && this._reactionDisposer();
}
@@ -837,8 +853,9 @@ export class DashFieldView {
this._labelSpan.style.fontWeight = "bold";
this._labelSpan.style.fontSize = "larger";
this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `;
+ const ddoc = tbox.props.DataDoc || tbox.dataDoc;
this._reactionDisposer && this._reactionDisposer();
- this._reactionDisposer = reaction(() => this._textBoxDoc[DataSym][node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true });
+ this._reactionDisposer = reaction(() => ddoc[node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true });
this._fieldWrapper.appendChild(this._labelSpan);
this._fieldWrapper.appendChild(this._fieldSpan);
(this as any).dom = this._fieldWrapper;
@@ -1012,7 +1029,7 @@ export class SummaryView {
view.dispatch(view.state.tr.
setSelection(textSelection). // select the current summarized text (or where it will be if its collapsed)
replaceSelection(!visible ? new Slice(Fragment.fromArray([]), 0, 0) : node.attrs.text). // collapse/expand it
- setNodeMarkup(getPos(), undefined, attrs)); // update the attrs
+ setNodeMarkup(getPos(), undefined, attrs)); // update the attrs
e.preventDefault();
e.stopPropagation();
this._collapsed.className = this.className(visible);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index d98301cf6..a31997a10 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -34,7 +34,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
@computed get Document(): T { return schemaCtor(this.props.Document); }
@computed get layoutDoc() { return Doc.Layout(this.props.Document); }
- @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; }
+ @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools
}
return Component;
@@ -57,7 +57,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
@computed get Document(): T { return schemaCtor(this.props.Document); }
@computed get layoutDoc() { return Doc.Layout(this.props.Document); }
- @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; }
+ @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
_annotationKey: string = "annotations";
public set annotationKey(val: string) { this._annotationKey = val; }
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index f2cc2479f..9f32bb0c9 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -45,13 +45,13 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
Document={this.childLayoutPairs[index].layout}
DataDocument={this.childLayoutPairs[index].data}
getTransform={this.props.ScreenToLocalTransform} />
- <div className="carouselView-back" onClick={() => this.layoutDoc._itemIndex = (index - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length}>
+ <div className="carouselView-back" onClick={e => { e.stopPropagation(); this.layoutDoc._itemIndex = (index - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length }}>
<FontAwesomeIcon
icon={faCaretLeft}
size={"2x"}
/>
</div>
- <div className="carouselView-fwd" onClick={() => this.layoutDoc._itemIndex = (index + 1) % this.childLayoutPairs.length}>
+ <div className="carouselView-fwd" onClick={e => { e.stopPropagation(); this.layoutDoc._itemIndex = (index + 1) % this.childLayoutPairs.length }}>
<FontAwesomeIcon
icon={faCaretRight}
size={"2x"}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 538e433a9..4904ee5c3 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -69,9 +69,9 @@ export class FieldView extends React.Component<FieldViewProps> {
// if (typeof field === "string") {
// return <p>{field}</p>;
// }
- else if (field instanceof RichTextField) {
- return <FormattedTextBox {...this.props} />;
- }
+ // else if (field instanceof RichTextField) {
+ // return <FormattedTextBox {...this.props} />;
+ // }
else if (field instanceof ImageField) {
return <ImageBox {...this.props} />;
}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index fab267358..5c9f1a754 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -496,7 +496,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this._reactionDisposer = reaction(
() => {
- const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
+ const field = Cast(this.props.Document._textTemplate || this.dataDoc[this.props.fieldKey], RichTextField);
return field ? field.Data : RichTextUtils.Initialize();
},
incomingValue => {