aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/RichTextRules.ts90
-rw-r--r--src/client/util/RichTextSchema.tsx37
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/TemplateMenu.tsx20
-rw-r--r--src/scraping/buxton/scraper.py5
5 files changed, 83 insertions, 71 deletions
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index 38cd5ca5c..00ce3ef73 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -72,32 +72,63 @@ export const inpRules = {
return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: size }));
}),
- // create a text display of a metadata field
+ // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
new InputRule(
- new RegExp(/\[\[([a-zA-Z_ \-0-9]+)\]\]$/),
+ new RegExp(/\[\[([a-zA-Z_ \-0-9]*)(:[a-zA-Z_ \-0-9]+)?\]\]$/),
(state, match, start, end) => {
- const fieldView = state.schema.nodes.dashField.create({ fieldKey: match[1] });
- return state.tr.deleteRange(start, end).insert(start, fieldView);
- }),
- // create a text display of a metadata field on another document
- new InputRule(
- new RegExp(/\[\[([a-zA-Z_ \-0-9]+):([a-zA-Z_ \-0-9]+)\]\]$/),
- (state, match, start, end) => {
- const fieldView = state.schema.nodes.dashField.create({ fieldKey: match[2], docid: match[1] });
+ if (!match[2]) {
+ const docId = match[1];
+ DocServer.GetRefField(docId).then(docx => {
+ const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: docId, _width: 500, _height: 500, _LODdisable: true, }, 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.deleteRange(end - 1, end).deleteRange(start, start + 2).addMark(start, end - 3, link);
+ }
+ const fieldView = state.schema.nodes.dashField.create({ fieldKey: match[2]?.substring(1), docid: match[1] });
return state.tr.deleteRange(start, end).insert(start, fieldView);
}),
- // create a hyperlink portal
+ // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
new InputRule(
- new RegExp(/@@([a-zA-Z_ \-0-9]+)@@$/),
+ new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(:[a-zA-Z_ \-0-9]+)?\}\}$/),
(state, match, start, end) => {
const docId = match[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", "");
+ if (!(docx instanceof Doc && docx)) {
+ const docx = Docs.Create.FreeformDocument([], { title: docId, _width: 500, _height: 500, _LODdisable: true }, docId);
+ DocUtils.Publish(docx, docId, returnFalse, returnFalse);
+ }
});
- const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + docId), location: "onRight", title: docId, targetId: docId });
- return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 2).addMark(start, end - 3, link);
+ const node = (state.doc.resolve(start) as any).nodeAfter;
+ const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid: docId, float: "right", fieldKey: match[2], alias: Utils.GenerateGuid() });
+ const sm = state.storedMarks || undefined;
+ return node ? state.tr.replaceRangeWith(start, end, dashDoc).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
+ }),
+ new InputRule(
+ new RegExp(/##$/),
+ (state, match, start, end) => {
+ const schemaDoc = Doc.GetDataDoc((schema as any).Document);
+ const textDoc = Doc.GetProto(Cast(schemaDoc[DataSym], Doc, null)!);
+ const numInlines = NumCast(textDoc.inlineTextCount);
+ textDoc.inlineTextCount = numInlines + 1;
+ const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to
+ const inlineLayoutKey = "layout_" + inlineFieldKey; // the field holding the layout string that will render the inline annotation
+ const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
+ textDocInline.title = inlineFieldKey; // give the annotation its own title
+ textDocInline.customTitle = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
+ textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
+ textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
+ textDocInline._textContext = ComputedField.MakeFunction(`copyField(this.${inlineFieldKey})`, { this: Doc.name });
+ textDoc[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
+ textDoc[inlineFieldKey] = ""; // set a default value for the annotation
+ const node = (state.doc.resolve(start) as any).nodeAfter;
+ 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;
+ return replaced;
}),
// stop using active style
new InputRule(
@@ -205,31 +236,6 @@ export const inpRules = {
return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2)));
}),
new InputRule(
- new RegExp(/##$/),
- (state, match, start, end) => {
- const schemaDoc = Doc.GetDataDoc((schema as any).Document);
- const textDoc = Doc.GetProto(Cast(schemaDoc[DataSym], Doc, null)!);
- const numInlines = NumCast(textDoc.inlineTextCount);
- textDoc.inlineTextCount = numInlines + 1;
- const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to
- const inlineLayoutKey = "layout_" + inlineFieldKey; // the field holding the layout string that will render the inline annotation
- const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
- textDocInline.title = inlineFieldKey; // give the annotation its own title
- textDocInline.customTitle = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
- textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
- textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
- textDocInline._textContext = ComputedField.MakeFunction(`copyField(this.${inlineFieldKey})`, { this: Doc.name });
- textDoc[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
- textDoc[inlineFieldKey] = ""; // set a default value for the annotation
- const node = (state.doc.resolve(start) as any).nodeAfter;
- 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;
- return replaced;
- }),
- new InputRule(
new RegExp(/%\(/),
(state, match, start, end) => {
const node = (state.doc.resolve(start) as any).nodeAfter;
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index f14e09a40..d1e0f07cb 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -168,7 +168,9 @@ export const nodes: { [index: string]: NodeSpec } = {
float: { default: "right" },
location: { default: "onRight" },
hidden: { default: false },
+ fieldKey: { default: "" },
docid: { default: "" },
+ alias: { default: "" }
},
group: "inline",
draggable: false,
@@ -756,18 +758,16 @@ export class DashDocView {
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") {
- 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" }));
- } catch (e) {
- console.log(e);
+ const alias = node.attrs.alias;
+ DocServer.GetRefField(node.attrs.docid + alias).then(async dashDoc => {
+ if (!(dashDoc instanceof Doc)) {
+ alias && DocServer.GetRefField(node.attrs.docid).then(async dashDocBase => {
+ if (dashDocBase instanceof Doc) {
+ self.doRender(Doc.MakeAlias(dashDocBase), removeDoc, node, view, getPos);
}
- }
- self.doRender(dashDoc, removeDoc);
+ });
+ } else {
+ self.doRender(dashDoc, removeDoc, node, view, getPos);
}
});
const self = this;
@@ -783,10 +783,19 @@ export class DashDocView {
this._outer.appendChild(this._dashSpan);
(this as any).dom = this._outer;
}
- doRender(dashDoc: Doc, removeDoc: any) {
+ doRender(dashDoc: Doc, removeDoc: any, node: any, view: any, getPos: any) {
+ this._dashDoc = dashDoc;
+ dashDoc._hideSidebar = true;
+ 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" }));
+ } catch (e) {
+ console.log(e);
+ }
+ }
const self = this;
const finalLayout = Doc.expandTemplateLayout(dashDoc, !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.Document) ? this._textBox.dataDoc : undefined);
- if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc), 0);
+ if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc, node, view, getPos), 0);
else {
const layoutKey = StrCast(finalLayout.layoutKey);
const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1];
@@ -803,7 +812,7 @@ export class DashDocView {
}, { fireImmediately: true });
ReactDOM.render(<DocumentView
Document={finalLayout}
- DataDoc={this._textBox.dataDoc}
+ DataDoc={Doc.AreProtosEqual(this._textBox.Document, dashDoc) ? this._textBox.dataDoc : undefined}
LibraryPath={this._textBox.props.LibraryPath}
fitToBox={BoolCast(dashDoc._fitToBox)}
addDocument={returnFalse}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 6abb7108f..65d1ade2a 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -280,7 +280,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.getLayoutPropStr("show" + template.Name) ? true : false, false as boolean)));
return !view0 ? (null) : <div title="Customize layout" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
<Flyout anchorPoint={anchorPoints.LEFT_TOP}
- content={<TemplateMenu docs={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
+ content={<TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
<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/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 2f36d4fbd..d5554fd4f 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -41,7 +41,7 @@ class OtherToggle extends React.Component<{ checked: boolean, name: string, togg
}
export interface TemplateMenuProps {
- docs: DocumentView[];
+ docViews: DocumentView[];
templates: Map<Template, boolean>;
}
@@ -51,12 +51,12 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
@observable private _hidden: boolean = true;
toggleLayout = (e: React.ChangeEvent<HTMLInputElement>, layout: string): void => {
- this.props.docs.map(dv => dv.setCustomView(e.target.checked, layout));
+ this.props.docViews.map(dv => dv.setCustomView(e.target.checked, layout));
}
toggleFloat = (e: React.ChangeEvent<HTMLInputElement>): void => {
SelectionManager.DeselectAll();
- const topDocView = this.props.docs[0];
+ const topDocView = this.props.docViews[0];
const ex = e.target.getBoundingClientRect().left;
const ey = e.target.getBoundingClientRect().top;
DocumentView.FloatDoc(topDocView, ex, ey);
@@ -67,9 +67,9 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
@action
toggleTemplate = (event: React.ChangeEvent<HTMLInputElement>, template: Template): void => {
if (event.target.checked) {
- this.props.docs.map(d => d.Document["show" + template.Name] = template.Name.toLowerCase());
+ this.props.docViews.map(d => d.Document["show" + template.Name] = template.Name.toLowerCase());
} else {
- this.props.docs.map(d => d.Document["show" + template.Name] = "");
+ this.props.docViews.map(d => d.Document["show" + template.Name] = "");
}
}
@@ -81,7 +81,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
@undoBatch
@action
toggleChrome = (): void => {
- this.props.docs.map(dv => {
+ this.props.docViews.map(dv => {
const layout = Doc.Layout(dv.Document);
layout._chromeStatus = (layout._chromeStatus !== "disabled" ? "disabled" : "enabled");
});
@@ -95,7 +95,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
}
componentDidMount() {
!TemplateMenu._addedKeys && (TemplateMenu._addedKeys = new ObservableSet(["narrative"]));
- Array.from(Object.keys(Doc.GetProto(this.props.docs[0].props.Document))).
+ Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))).
filter(key => key.startsWith("layout_")).
map(key => runInAction(() => TemplateMenu._addedKeys.add(key.replace("layout_", ""))));
DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => {
@@ -108,14 +108,14 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
static _addedKeys = new ObservableSet(["narrative"]);
_customRef = React.createRef<HTMLInputElement>();
render() {
- const layout = Doc.Layout(this.props.docs[0].Document);
+ const layout = Doc.Layout(this.props.docViews[0].Document);
const templateMenu: Array<JSX.Element> = [];
this.props.templates.forEach((checked, template) =>
templateMenu.push(<TemplateToggle key={template.Name} template={template} checked={checked} toggle={this.toggleTemplate} />));
- templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={this.props.docs[0].Document.z ? true : false} toggle={this.toggleFloat} />);
+ templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={this.props.docViews[0].Document.z ? true : false} toggle={this.toggleFloat} />);
templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout._chromeStatus !== "disabled"} toggle={this.toggleChrome} />);
TemplateMenu._addedKeys && Array.from(TemplateMenu._addedKeys).map(layout =>
- templateMenu.push(<OtherToggle key={layout} name={layout} checked={StrCast(this.props.docs[0].Document.layoutKey, "layout") === "layout_" + layout} toggle={e => this.toggleLayout(e, layout)} />)
+ templateMenu.push(<OtherToggle key={layout} name={layout} checked={StrCast(this.props.docViews[0].Document.layoutKey, "layout") === "layout_" + layout} toggle={e => this.toggleLayout(e, layout)} />)
);
return <ul className="template-list" style={{ display: "block" }}>
{templateMenu}
diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py
index 7cfa4696d..ec9c3f72c 100644
--- a/src/scraping/buxton/scraper.py
+++ b/src/scraping/buxton/scraper.py
@@ -100,8 +100,6 @@ def write_collection(parse_results, display_fields, storage_key, viewType):
fields["proto"] = protofy(common_proto_id)
fields[storage_key] = listify(proxify_guids(view_guids))
fields["schemaColumns"] = listify(display_fields)
- fields["backgroundColor"] = "white"
- fields["_viewType"] = 2
fields["author"] = "Bill Buxton"
fields["creationDate"] = {
"date": datetime.datetime.utcnow().microsecond,
@@ -113,7 +111,6 @@ def write_collection(parse_results, display_fields, storage_key, viewType):
"__type": "image"
}
fields["isPrototype"] = True
- fields["page"] = -1
target_collection.insert_one(data_doc)
target_collection.insert_one(view_doc)
@@ -409,7 +406,7 @@ parent_guid = write_collection({
"__type": "Doc"
},
"child_guids": schema_guids
-}, ["title", "short_description", "original_price"], "data", 4)
+}, ["title", "short_description", "original_price"], "data", 2)
print("appending parent schema to main workspace...\n")
target_collection.update_one(