From f93abfc577225cc04eb94d67c62eec67d7e22bca Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Jan 2020 22:37:44 -0500 Subject: changed hideSidebar to showSidebar. added contextmenu for choosing pivot field. --- src/client/util/RichTextSchema.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 287a1049b..9e4f06919 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -790,7 +790,6 @@ export class DashDocView { } 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" })); -- cgit v1.2.3-70-g09d2 From 11b4645ce52df01f071a9a4a2582cae10a0140ba Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 3 Feb 2020 20:53:19 -0500 Subject: template fixes for nesting documents. --- src/client/util/RichTextRules.ts | 30 ++++++++++++++++-------------- src/client/util/RichTextSchema.tsx | 10 +++++----- src/new_fields/Doc.ts | 15 +++++---------- src/new_fields/util.ts | 2 +- 4 files changed, 27 insertions(+), 30 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 8411cc6ee..77b111412 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -72,36 +72,38 @@ export const inpRules = { return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: size })); }), - // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document + // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document [[ : ]] // [[:Doc]] => hyperlink [[fieldKey]] => show field [[fieldKey:Doc]] => show field of doc new InputRule( new RegExp(/\[\[([a-zA-Z_ \-0-9]*)(:[a-zA-Z_ \-0-9]+)?\]\]$/), (state, match, start, end) => { - 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); + const fieldKey = match[1]; + const docid = match[2]?.substring(1); + if (!fieldKey) { + 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 }); + 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] }); + const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid }); return state.tr.deleteRange(start, end).insert(start, fieldView); }), - // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document + // create an inline view of a document {{ : }} // {{:Doc}} => show default view of document {{}} => show layout for this doc {{ : Doc}} => show layout for another doc new InputRule( 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 fieldKey = match[1]; + const docid = match[2]?.substring(1); + DocServer.GetRefField(docid).then(docx => { 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 docx = Docs.Create.FreeformDocument([], { title: docid, _width: 500, _height: 500, _LODdisable: true }, docid); + DocUtils.Publish(docx, docid, returnFalse, returnFalse); } }); 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]?.substring(1), alias: Utils.GenerateGuid() }); + const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid, fieldKey, float: "right", alias: Utils.GenerateGuid() }); const sm = state.storedMarks || undefined; return node ? state.tr.replaceRangeWith(start, end, dashDoc).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; }), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 9e4f06919..9c52e3107 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -766,8 +766,8 @@ export class DashDocView { if (!(dashDoc instanceof Doc)) { alias && DocServer.GetRefField(docid).then(async dashDocBase => { if (dashDocBase instanceof Doc) { - const aliasedDoc = Doc.MakeDelegate(dashDocBase, docid + alias); - aliasedDoc.layoutKey = "layout_" + node.attrs.fieldKey; + const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); + aliasedDoc.layoutKey = "layout" + (node.attrs.fieldKey ? "_" + node.attrs.fieldKey : ""); self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); @@ -809,10 +809,10 @@ export class DashDocView { finalLayout._textTemplate = ComputedField.MakeFunction(`copyField(this.${finalKey})`, { this: Doc.name }); } } - this._reactionDisposer && 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"; + this._dashSpan.style.width = this._outer.style.width = Math.max(20, dim[0]) + "px"; + this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px"; }, { fireImmediately: true }); ReactDOM.render( Date: Mon, 3 Feb 2020 23:48:03 -0500 Subject: maded field views editable --- src/client/util/RichTextSchema.tsx | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 9e4f06919..3957a1f26 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -22,6 +22,7 @@ import { ObjectField } from "../../new_fields/ObjectField"; import { ComputedField } from "../../new_fields/ScriptField"; import { observer } from "mobx-react"; import { Id } from "../../new_fields/FieldSymbols"; +import { OnChangeHandler } from "react-color/lib/components/common/ColorWrap"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -850,22 +851,42 @@ export class DashDocView { export class DashFieldView { _fieldWrapper: HTMLDivElement; _labelSpan: HTMLSpanElement; - _fieldSpan: HTMLSpanElement; + _fieldSpan: HTMLDivElement; _reactionDisposer: IReactionDisposer | undefined; _textBoxDoc: Doc; @observable _dashDoc: Doc | undefined; + _fieldKey: string; constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + this._fieldKey = node.attrs.fieldKey; this._textBoxDoc = tbox.props.Document; this._fieldWrapper = document.createElement("div"); this._fieldWrapper.style.width = node.attrs.width; this._fieldWrapper.style.height = node.attrs.height; this._fieldWrapper.style.position = "relative"; - this._fieldWrapper.style.display = "inline"; + this._fieldWrapper.style.display = "inline-block"; - this._fieldSpan = document.createElement("span"); + this._fieldSpan = document.createElement("div"); + this._fieldSpan.id = Utils.GenerateGuid(); + this._fieldSpan.contentEditable = "true"; this._fieldSpan.style.position = "relative"; - this._fieldSpan.style.display = "inline"; + this._fieldSpan.style.display = "inline-block"; + this._fieldSpan.style.minWidth = "50px"; + this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; + this._fieldSpan.addEventListener("input", this.onchanged); + const self = this; + this._fieldSpan.onkeydown = function (e: any) { + e.stopPropagation(); + if (e.key === "Tab" || e.key === "Enter" || (e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { + if (window.getSelection) { + var range = document.createRange(); + range.selectNodeContents(self._fieldSpan); + window.getSelection()!.removeAllRanges(); + window.getSelection()!.addRange(range); + } + e.preventDefault(); + } + }; this._labelSpan = document.createElement("span"); this._labelSpan.style.position = "relative"; @@ -880,15 +901,22 @@ export class DashFieldView { this._dashDoc = tbox.props.DataDoc || tbox.dataDoc; } this._reactionDisposer?.(); - this._reactionDisposer = reaction(() => this._dashDoc?.[node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true }); + this._reactionDisposer = reaction(() => this._dashDoc?.[node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true }); this._fieldWrapper.appendChild(this._labelSpan); this._fieldWrapper.appendChild(this._fieldSpan); (this as any).dom = this._fieldWrapper; } + onchanged = () => { + this._reactionDisposer?.(); + this._dashDoc![this._fieldKey] = this._fieldSpan.innerText; + this._reactionDisposer = reaction(() => this._dashDoc?.[this._fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)"); + + } destroy() { this._reactionDisposer?.(); } + selectNode() { } } export class OrderedListView { -- cgit v1.2.3-70-g09d2 From 72f50feacb1c023d093b8169ef85e1e7773aa483 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 4 Feb 2020 00:12:52 -0500 Subject: from last --- src/client/util/RichTextSchema.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index b98e422cb..c07ebe2ed 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -874,10 +874,16 @@ export class DashFieldView { this._fieldSpan.style.minWidth = "50px"; this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldSpan.addEventListener("input", this.onchanged); + this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; + this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; + this._fieldSpan.onmousedown = function (e: any) { + console.log(e); + e.stopPropagation(); + }; const self = this; this._fieldSpan.onkeydown = function (e: any) { e.stopPropagation(); - if (e.key === "Tab" || e.key === "Enter" || (e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { + if ((e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { if (window.getSelection) { var range = document.createRange(); range.selectNodeContents(self._fieldSpan); -- cgit v1.2.3-70-g09d2 From 60a008f635177acccaa9dacb4006491725c93702 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 10 Feb 2020 15:05:30 -0500 Subject: small cleanups to adding stacking views to contentfittingboxes (like time/pivot). needs to have nativeWidth/Height set. --- src/client/documents/Documents.ts | 4 +++ src/client/util/RichTextRules.ts | 19 ++++++------ src/client/util/RichTextSchema.tsx | 18 +++++------ .../views/collections/CollectionStackingView.tsx | 35 +++++++++------------- src/client/views/collections/CollectionSubView.tsx | 5 +++- .../views/collections/CollectionTimeView.tsx | 3 +- src/client/views/collections/CollectionView.tsx | 6 ++-- .../CollectionFreeFormLayoutEngines.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 +++++++------- .../CollectionMulticolumnView.scss | 2 +- .../CollectionMultirowView.scss | 2 +- src/client/views/nodes/DocumentView.tsx | 20 ++++++++----- src/new_fields/Doc.ts | 17 +++++++++-- .../authentication/models/current_user_utils.ts | 6 ++-- 14 files changed, 87 insertions(+), 75 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6775d2302..29f253115 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -594,6 +594,10 @@ export namespace Docs { export function MulticolumnDocument(documents: Array, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Multicolumn }); } + export function MultirowDocument(documents: Array, options: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Multirow }); + } + export function MasonryDocument(documents: Array, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Masonry }); diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 3b30b5b3f..1b67b4fe4 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -1,17 +1,16 @@ -import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from "prosemirror-inputrules"; -import { schema } from "./RichTextSchema"; -import { wrappingInputRule } from "./prosemirrorPatches"; +import { ellipsis, emDash, InputRule, smartQuotes, textblockTypeInputRule } from "prosemirror-inputrules"; import { NodeSelection, TextSelection } from "prosemirror-state"; -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 { DataSym, Doc } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; -import { DocServer } from "../DocServer"; +import { ComputedField } from "../../new_fields/ScriptField"; +import { Cast, NumCast } from "../../new_fields/Types"; import { returnFalse, Utils } from "../../Utils"; +import { DocServer } from "../DocServer"; +import { Docs, DocUtils } from "../documents/Documents"; +import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; +import { wrappingInputRule } from "./prosemirrorPatches"; import RichTextMenu from "./RichTextMenu"; -import { RichTextField } from "../../new_fields/RichTextField"; -import { ComputedField } from "../../new_fields/ScriptField"; +import { schema } from "./RichTextSchema"; export const inpRules = { rules: [ diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c07ebe2ed..043b277de 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,28 +1,26 @@ -import { reaction, IReactionDisposer, observable, runInAction } from "mobx"; +import { IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { baseKeymap, toggleMark } from "prosemirror-commands"; import { redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { DOMOutputSpecArray, Fragment, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model"; import { bulletList, listItem, orderedList } from 'prosemirror-schema-list'; -import { EditorState, NodeSelection, TextSelection, Plugin } from "prosemirror-state"; +import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-state"; import { StepMap } from "prosemirror-transform"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, WidthSym, HeightSym, DataSym, Field } from "../../new_fields/Doc"; +import { Doc, Field, HeightSym, WidthSym } from "../../new_fields/Doc"; +import { Id } from "../../new_fields/FieldSymbols"; +import { ObjectField } from "../../new_fields/ObjectField"; +import { ComputedField } from "../../new_fields/ScriptField"; +import { BoolCast, NumCast, StrCast } from "../../new_fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { DocumentView } from "../views/nodes/DocumentView"; +import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { DocumentManager } from "./DocumentManager"; import ParagraphNodeSpec from "./ParagraphNodeSpec"; 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"; -import { ComputedField } from "../../new_fields/ScriptField"; -import { observer } from "mobx-react"; -import { Id } from "../../new_fields/FieldSymbols"; -import { OnChangeHandler } from "react-color/lib/components/common/ColorWrap"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d772ace23..21c34d047 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,25 +4,25 @@ import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import Switch from 'rc-switch'; -import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc"; +import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types"; -import { emptyFunction, Utils } from "../../../Utils"; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; +import { TraceMobx } from "../../../new_fields/util"; +import { Utils } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; +import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { CollectionSubView } from "./CollectionSubView"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; -import { TraceMobx } from "../../../new_fields/util"; import { CollectionViewType } from "./CollectionView"; @observer @@ -55,7 +55,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { this._docXfs.length = 0; return docs.map((d, i) => { const height = () => this.getDocHeight(d); - const width = () => this.widthScale * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); + const width = () => Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); const dref = React.createRef(); const dxf = () => this.getDocTransform(d, dref.current!); this._docXfs.push({ dxf: dxf, width: width, height: height }); @@ -376,16 +376,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1])); } - @computed get contentScale() { - const heightExtra = this.heightPercent > 1 ? this.heightPercent : 1; - return Math.min(this.props.Document[WidthSym]() / this.props.PanelWidth(), heightExtra * this.props.Document[HeightSym]() / this.props.PanelHeight()); - } - @computed get widthScale() { - return this.heightPercent < 1 ? Math.max(1, this.contentScale) : 1; - } - @computed get heightPercent() { - return this.props.PanelHeight() / this.layoutDoc[HeightSym](); - } + + @computed get scaling() { return !this.props.Document._nativeWidth ? 1 : this.props.PanelHeight() / NumCast(this.props.Document._nativeHeight); } + render() { TraceMobx(); const editableViewProps = { @@ -399,9 +392,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ref={this.createRef} style={{ overflowY: this.props.active() ? "auto" : "hidden", - transform: `scale(${Math.min(1, this.heightPercent)})`, - height: `${100 * Math.max(1, this.contentScale)}%`, - width: `${100 * this.widthScale}%`, + transform: `scale(${this.scaling}`, + height: `${1 / this.scaling * 100}%`, + width: `${1 / this.scaling * 100}%`, transformOrigin: "top left", }} onScroll={action((e: React.UIEvent) => this._scroll = e.currentTarget.scrollTop)} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 62b9e8380..d71bad647 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,7 +1,7 @@ import { action, computed, IReactionDisposer, reaction, trace } from "mobx"; import * as rp from 'request-promise'; import CursorField from "../../../new_fields/CursorField"; -import { Doc, DocListCast, Opt } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; @@ -167,6 +167,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { return true; } let added = false; + if (this.props.Document._freezeOnDrop) { + de.complete.docDragData?.droppedDocuments.forEach(drop => Doc.freezeNativeDimensions(drop, drop[WidthSym](), drop[HeightSym]())); + } if (docDragData.dropAction || docDragData.userDropAction) { added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); } else if (docDragData.moveDocument) { diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 6058f4e1d..db176d0bc 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -2,7 +2,7 @@ import { faEdit } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, Field } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Field, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { RichTextField } from "../../../new_fields/RichTextField"; @@ -31,6 +31,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @observable _layoutEngine = "pivot"; componentDidMount() { + this.props.Document._freezeOnDrop = true; const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked; if (!this.props.Document._facetCollection) { const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true, treeViewHideHeaderFields: true }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2f27e5273..c081649cc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -7,7 +7,7 @@ import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app import { DateField } from '../../../new_fields/DateField'; -import { Doc, DocListCast } from '../../../new_fields/Doc'; +import { Doc, DocListCast, DataSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { listSpec } from '../../../new_fields/Schema'; import { BoolCast, Cast, StrCast, NumCast } from '../../../new_fields/Types'; @@ -133,7 +133,7 @@ export class CollectionView extends Touchable { @action.bound addDocument(doc: Doc): boolean { - const targetDataDoc = Doc.GetProto(this.props.DataDoc || this.props.Document); // bcz: shouldn't this be Doc.Layout(this.props.Document)? Right now, that causes problems with Buxton layout & adding things to a SLideView + const targetDataDoc = this.props.Document[DataSym]; Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); Doc.GetProto(doc).lastOpened = new DateField; @@ -144,7 +144,7 @@ export class CollectionView extends Touchable { removeDocument(doc: Doc): boolean { const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); - const value = Cast(Doc.GetProto(this.props.DataDoc || this.props.Document)[this.props.fieldKey], listSpec(Doc), []); + const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index baf09fe5b..da4dc0270 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -186,7 +186,7 @@ export function computePivotLayout( const maxColHeight = pivotAxisWidth * expander * Math.ceil(maxInColumn / numCols); const dividers = sortedPivotKeys.map((key, i) => - ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); + ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); groupNames.push(...dividers); return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childDocs.filter(c => !filterDocs.includes(c))); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c78a2a2cf..07a5a2c7b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,20 +1,22 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer, trace } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } from "../../../../new_fields/Doc"; +import { computedFn } from "mobx-utils"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc"; import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; -import { InkTool, InkField, InkData } from "../../../../new_fields/InkField"; -import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; +import { InkTool } from "../../../../new_fields/InkField"; +import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema"; import { ScriptField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../new_fields/Types"; +import { Cast, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types"; +import { TraceMobx } from "../../../../new_fields/util"; +import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; -import { aggregateBounds, emptyFunction, intersectRect, returnOne, Utils } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnOne, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; -import { Docs, DocUtils } from "../../../documents/Documents"; -import { DocumentType } from "../../../documents/DocumentTypes"; +import { Docs } from "../../../documents/Documents"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager } from "../../../util/DragManager"; import { HistoryUtil } from "../../../util/History"; @@ -32,15 +34,12 @@ import { FormattedTextBox } from "../../nodes/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; import { CollectionSubView } from "../CollectionSubView"; -import { computePivotLayout, ViewDefResult, computeTimelineLayout, PoolData, ViewDefBounds } from "./CollectionFreeFormLayoutEngines"; +import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { computedFn } from "mobx-utils"; -import { TraceMobx } from "../../../../new_fields/util"; -import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index 0c74b8ddb..821c8d804 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -1,8 +1,8 @@ .collectionMulticolumnView_contents { display: flex; + overflow: hidden; width: 100%; height: 100%; - overflow: hidden; .document-wrapper { display: flex; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss index 64f607680..a7e2c5707 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss @@ -1,8 +1,8 @@ .collectionMultirowView_contents { display: flex; + overflow: hidden; width: 100%; height: 100%; - overflow: hidden; flex-direction: column; .document-wrapper { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1199ed7ee..080b01df2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -610,13 +610,17 @@ export class DocumentView extends DocComponent(Docu } @undoBatch - @action - freezeNativeDimensions = (): void => { - this.layoutDoc._autoHeight = false; - this.layoutDoc.ignoreAspect = !this.layoutDoc.ignoreAspect; - if (!this.layoutDoc.ignoreAspect && !this.layoutDoc._nativeWidth) { - this.layoutDoc._nativeWidth = this.props.PanelWidth(); - this.layoutDoc._nativeHeight = this.props.PanelHeight(); + public static unfreezeNativeDimensions = action((layoutDoc: Doc): void => { + layoutDoc._nativeWidth = undefined; + layoutDoc._nativeHeight = undefined; + }); + + toggleNativeDimensions = () => { + if (this.Document._nativeWidth || this.Document._nativeHeight) { + DocumentView.unfreezeNativeDimensions(this.layoutDoc); + } + else { + Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight()); } } @@ -730,7 +734,7 @@ export class DocumentView extends DocComponent(Docu layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - layoutItems.push({ description: this.Document.ignoreAspect || !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); + layoutItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 3baab119f..a28c6f58f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -14,7 +14,7 @@ import { ComputedField, ScriptField } from "./ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; import { intersectRect } from "../Utils"; -import { UndoManager } from "../client/util/UndoManager"; +import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { computedFn } from "mobx-utils"; import { RichTextField } from "./RichTextField"; import { Script } from "vm"; @@ -178,7 +178,7 @@ export class Doc extends RefField { private [SelfProxy]: any; public [WidthSym] = () => NumCast(this[SelfProxy]._width); public [HeightSym] = () => NumCast(this[SelfProxy]._height); - public get [DataSym]() { return Cast(this[SelfProxy].resolvedDataDoc, Doc, null) || this[SelfProxy]; } + public get [DataSym]() { return Cast(Doc.Layout(this[SelfProxy]).resolvedDataDoc, Doc, null) || this[SelfProxy]; } public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } @computed get __LAYOUT__() { const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null); @@ -842,6 +842,17 @@ export namespace Doc { } } } + + @undoBatch + @action + export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void { + layoutDoc._autoHeight = false; + layoutDoc.ignoreAspect = false; + if (!layoutDoc.ignoreAspect && !layoutDoc._nativeWidth) { + layoutDoc._nativeWidth = NumCast(layoutDoc._width, width); + layoutDoc._nativeHeight = NumCast(layoutDoc._height, height); + } + } } Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); @@ -867,4 +878,4 @@ Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: bo return docs.length ? new List(docs) : prevValue; }); Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: string) { Doc.setDocFilter(container, key, value, modifiers); }); -Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file +Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index efee42f63..ea7a4999c 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -234,12 +234,12 @@ export class CurrentUserUtils { /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window static setupExpandingButtons(doc: Doc) { - const slideTemplate = Docs.Create.StackingDocument( + const slideTemplate = Docs.Create.MultirowDocument( [ - Docs.Create.MulticolumnDocument([], { title: "images", _height: 200, _xMargin: 10, _yMargin: 10 }), + Docs.Create.MulticolumnDocument([], { title: "images", _height: 200 }), Docs.Create.TextDocument("", { title: "contents", _height: 100 }) ], - { _width: 400, _height: 300, title: "slide", _chromeStatus: "disabled", backgroundColor: "lightGray", _autoHeight: true }); + { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, backgroundColor: "lightGray", _autoHeight: true }); slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); -- cgit v1.2.3-70-g09d2 From b8b58e1285bea8b03afb23e7abf1bbdd73f9b698 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 10 Feb 2020 16:44:49 -0500 Subject: fixed nesting layouts of 'layout' key in text boxes. --- src/client/util/RichTextSchema.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 043b277de..269a045a0 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -766,7 +766,7 @@ export class DashDocView { alias && DocServer.GetRefField(docid).then(async dashDocBase => { if (dashDocBase instanceof Doc) { const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); - aliasedDoc.layoutKey = "layout" + (node.attrs.fieldKey ? "_" + node.attrs.fieldKey : ""); + aliasedDoc.layoutKey = node.attrs.fieldKey === "layout" ? "layout" : "layout" + (node.attrs.fieldKey ? "_" + node.attrs.fieldKey : ""); self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); -- cgit v1.2.3-70-g09d2 From ed947b320de772d63e7b462e78910db11c0a8fd3 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 11 Feb 2020 12:57:34 -0500 Subject: goole docs fixed except for uploading embedded images --- src/client/apis/google_docs/GoogleApiClientUtils.ts | 2 +- src/client/util/RichTextSchema.tsx | 2 +- src/new_fields/RichTextUtils.ts | 6 ++++-- src/server/ApiManagers/GooglePhotosManager.ts | 2 +- src/server/DashUploadUtils.ts | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts index d2a79f189..0d44ee8e0 100644 --- a/src/client/apis/google_docs/GoogleApiClientUtils.ts +++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts @@ -248,7 +248,7 @@ export namespace GoogleApiClientUtils { return undefined; } requests.push(...options.content.requests); - const replies: any = await update({ documentId: documentId, requests }); + const replies: any = await update({ documentId, requests }); if ("errors" in replies) { console.log("Write operation failed:"); console.log(replies.errors.map((error: any) => error.message)); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 269a045a0..f12b3632c 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -883,7 +883,7 @@ export class DashFieldView { e.stopPropagation(); if ((e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { if (window.getSelection) { - var range = document.createRange(); + const range = document.createRange(); range.selectNodeContents(self._fieldSpan); window.getSelection()!.removeAllRanges(); window.getSelection()!.addRange(range); diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index 2fedac53e..016bcc4ca 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -1,5 +1,5 @@ import { EditorState, Transaction, TextSelection } from "prosemirror-state"; -import { Node, Fragment, Mark, MarkType } from "prosemirror-model"; +import { Node, Fragment, Mark } from "prosemirror-model"; import { RichTextField } from "./RichTextField"; import { docs_v1 } from "googleapis"; import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils"; @@ -17,6 +17,7 @@ import { Id } from "./FieldSymbols"; import { DocumentView } from "../client/views/nodes/DocumentView"; import { AssertionError } from "assert"; import { Networking } from "../client/Network"; +import { extname } from "path"; export namespace RichTextUtils { @@ -138,7 +139,8 @@ export namespace RichTextUtils { const embeddedObject = object.inlineObjectProperties!.embeddedObject!; const size = embeddedObject.size!; const width = size.width!.magnitude!; - const url = Utils.prepend(clientAccessPath); + const ext = extname(clientAccessPath); + const url = Utils.prepend(clientAccessPath.replace(ext, "_m" + ext)); inlineObjectMap.set(object.objectId!, { title: embeddedObject.title || `Imported Image from ${document.title}`, diff --git a/src/server/ApiManagers/GooglePhotosManager.ts b/src/server/ApiManagers/GooglePhotosManager.ts index 157f6bdca..3236d1ee2 100644 --- a/src/server/ApiManagers/GooglePhotosManager.ts +++ b/src/server/ApiManagers/GooglePhotosManager.ts @@ -95,7 +95,7 @@ export default class GooglePhotosManager extends ApiManager { const { contentSize, ...attributes } = results; const found: Opt = await Database.Auxiliary.QueryUploadHistory(contentSize); if (!found) { - const upload = await DashUploadUtils.UploadInspectedImage({ contentSize, ...attributes }, undefined, prefix).catch(error => _error(res, downloadError, error)); + const upload = await DashUploadUtils.UploadInspectedImage({ contentSize, ...attributes }, undefined, prefix, false).catch(error => _error(res, downloadError, error)); if (upload) { completed.push(upload); await Database.Auxiliary.LogUpload(upload); diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 4e6bbaa3f..83a0064e8 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -223,7 +223,7 @@ export namespace DashUploadUtils { }); } - export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, prefix = ""): Promise => { + export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, prefix = "", cleanUp = true): Promise => { const { requestable, source, ...remaining } = metadata; const extension = `.${remaining.contentType.split("/")[1].toLowerCase()}`; const resolved = filename || `${prefix}upload_${Utils.GenerateGuid()}${extension}`; @@ -237,7 +237,7 @@ export namespace DashUploadUtils { for (const suffix of Object.keys(writtenFiles)) { information.serverAccessPaths[suffix] = serverPathToFile(Directory.images, writtenFiles[suffix]); } - if (isLocal().test(source)) { + if (isLocal().test(source) && cleanUp) { unlinkSync(source); } return information; -- cgit v1.2.3-70-g09d2 From ec5c878fb4c5f7e03fdd214c0841cf2ebf983e8c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 11 Feb 2020 15:48:06 -0500 Subject: refactored image upload data response format, google docs working for specific interactions --- .../util/Import & Export/DirectoryImportBox.tsx | 4 +- src/client/util/RichTextSchema.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 8 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 4 +- src/new_fields/RichTextUtils.ts | 30 ++--- src/scraping/buxton/final/json/buxton.json | 130 ++++++++++----------- src/server/ApiManagers/DownloadManager.ts | 2 +- src/server/DashUploadUtils.ts | 37 ++++-- src/server/apis/google/GooglePhotosUploadUtils.ts | 3 +- 10 files changed, 121 insertions(+), 102 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 071015193..d04f56e57 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -120,8 +120,8 @@ export default class DirectoryImportBox extends React.Component runInAction(() => this.completed += batch.length); }); - await Promise.all(uploads.map(async ({ name, type, clientAccessPath, exifData }) => { - const path = Utils.prepend(clientAccessPath); + await Promise.all(uploads.map(async ({ name, type, accessPaths, exifData }) => { + const path = Utils.prepend(accessPaths.agnostic.client); const document = await Docs.Get.DocumentFromType(type, path, { _width: 300, title: name }); const { data, error } = exifData; if (document) { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index f12b3632c..3cf0561dc 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -133,6 +133,7 @@ export const nodes: { [index: string]: NodeSpec } = { inline: true, attrs: { src: {}, + agnostic: { default: null }, width: { default: 100 }, alt: { default: null }, title: { default: null }, diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 293a8491a..20941493f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -232,8 +232,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const split = img.split("src=\"")[1].split("\"")[0]; let source = split; if (split.startsWith("data:image") && split.includes("base64")) { - const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] }); - source = Utils.prepend(clientAccessPath); + const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] }); + source = Utils.prepend(accessPaths.agnostic.client); } const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); ImageUtils.ExtractExif(doc); @@ -312,9 +312,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const dropFileName = file ? file.name : "-empty-"; promises.push(Networking.PostFormDataToServer("/uploadFormData", formData).then(results => { results.map(action((result: any) => { - const { clientAccessPath, nativeWidth, nativeHeight, contentSize } = result; + const { accessPaths, nativeWidth, nativeHeight, contentSize } = result; const full = { ...options, _width: 300, title: dropFileName }; - const pathname = Utils.prepend(clientAccessPath); + const pathname = Utils.prepend(accessPaths.agnostic.client); Docs.Get.DocumentFromType(type, pathname, full).then(doc => { if (doc) { const proto = Doc.GetProto(doc); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e4ab3e746..5c5a87cb9 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -277,7 +277,7 @@ export class DocumentView extends DocComponent(Docu } preventDefault && e.preventDefault(); } - }) + }); buttonClick = async (altKey: boolean, ctrlKey: boolean) => { const linkDocs = DocListCast(this.props.Document.links); @@ -636,7 +636,7 @@ export class DocumentView extends DocComponent(Docu if (StrCast(tempDoc.title) === layout) { foundLayout = tempDoc; } - }) + }); DocumentView. makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); } else { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index db9800de4..c0e102195 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -321,12 +321,12 @@ export class ImageBox extends DocAnnotatableComponent this.uploadIcon = loading); - const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); + const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); dataDoc.originalUrl = primary; let succeeded = true; let data: ImageField | undefined; try { - data = new ImageField(Utils.prepend(clientAccessPath)); + data = new ImageField(Utils.prepend(accessPaths.agnostic.client)); } catch { succeeded = false; } diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index 016bcc4ca..7c1fc39d8 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -114,6 +114,7 @@ export namespace RichTextUtils { width: number; title: string; url: string; + agnostic: string; } const parseInlineObjects = async (document: docs_v1.Schema$Document): Promise> => { @@ -135,17 +136,17 @@ export namespace RichTextUtils { for (let i = 0; i < objects.length; i++) { const object = objects[i]; - const { clientAccessPath } = uploads[i]; + const { accessPaths } = uploads[i]; + const { agnostic, _m } = accessPaths; const embeddedObject = object.inlineObjectProperties!.embeddedObject!; const size = embeddedObject.size!; const width = size.width!.magnitude!; - const ext = extname(clientAccessPath); - const url = Utils.prepend(clientAccessPath.replace(ext, "_m" + ext)); inlineObjectMap.set(object.objectId!, { title: embeddedObject.title || `Imported Image from ${document.title}`, width, - url + url: Utils.prepend(_m.client), + agnostic: Utils.prepend(agnostic.client) }); } } @@ -267,19 +268,19 @@ export namespace RichTextUtils { }; const imageNode = (schema: any, image: ImageTemplate, textNote: Doc) => { - const { url: src, width } = image; + const { url: src, width, agnostic } = image; let docid: string; - const guid = Utils.GenerateDeterministicGuid(src); + const guid = Utils.GenerateDeterministicGuid(agnostic); const backingDocId = StrCast(textNote[guid]); if (!backingDocId) { - const backingDoc = Docs.Create.ImageDocument(src, { _width: 300, _height: 300 }); + const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 }); DocumentView.makeCustomViewClicked(backingDoc, undefined, Docs.Create.FreeformDocument); docid = backingDoc[Id]; textNote[guid] = docid; } else { docid = backingDocId; } - return schema.node("image", { src, width, docid, float: null, location: "onRight" }); + return schema.node("image", { src, agnostic, width, docid, float: null, location: "onRight" }); }; const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { @@ -435,7 +436,7 @@ export namespace RichTextUtils { const width = attrs.width; requests.push(await EncodeImage({ startIndex: position + nodeSize - 1, - uri: attrs.src, + uri: attrs.agnostic, width: Number(typeof width === "string" ? width.replace("px", "") : width) })); } @@ -498,15 +499,18 @@ export namespace RichTextUtils { }; }; - const EncodeImage = async (information: ImageInformation) => { - const source = [Docs.Create.ImageDocument(information.uri)]; + const EncodeImage = async ({ uri, width, startIndex }: ImageInformation) => { + if (!uri) { + return {}; + } + const source = [Docs.Create.ImageDocument(uri)]; const baseUrls = await GooglePhotos.Transactions.UploadThenFetch(source); if (baseUrls) { return { insertInlineImage: { uri: baseUrls[0], - objectSize: { width: { magnitude: information.width, unit: "PT" } }, - location: { index: information.startIndex } + objectSize: { width: { magnitude: width, unit: "PT" } }, + location: { index: startIndex } } }; } diff --git a/src/scraping/buxton/final/json/buxton.json b/src/scraping/buxton/final/json/buxton.json index 5c2e2c90c..16b28916b 100644 --- a/src/scraping/buxton/final/json/buxton.json +++ b/src/scraping/buxton/final/json/buxton.json @@ -18,9 +18,9 @@ "3DCad_Brochure.jpg" ], "__images": [ - "/files/images/buxton/upload_19ce4ebd-f207-4724-b8bf-610c8e1cf322.png", - "/files/images/buxton/upload_4dde8de0-f1ec-4ffb-b7cc-57b8c4ae6c94.png", - "/files/images/buxton/upload_825e8ed8-063c-428b-917d-eb62ea218f05.png" + "/files/images/buxton/upload_793981b0-d7da-45d1-a643-596cc3834166.png", + "/files/images/buxton/upload_6259e28a-055e-4b02-b547-e72c5e6fa3c0.png", + "/files/images/buxton/upload_4f4fb80f-467a-41e7-9bf5-1b1f377b2ec4.png" ], "title": "3Dconnexion CadMan 3D Motion Controller", "company": "3Dconnexion", @@ -63,11 +63,11 @@ "SpaceMouse_Plus_Info_Sheet.jpg" ], "__images": [ - "/files/images/buxton/upload_f84cb54e-9bdb-4fbc-9503-6cfa8ddd65be.jpg", - "/files/images/buxton/upload_506b5361-a9fd-4440-a19b-5b4af461878a.png", - "/files/images/buxton/upload_60380383-3603-4624-98cf-50a0d4afe4c9.png", - "/files/images/buxton/upload_2fad6fb2-f1e1-4fe3-915b-33586f05fcad.png", - "/files/images/buxton/upload_effcd815-49eb-4cd4-82cf-2519e58eb729.png" + "/files/images/buxton/upload_4a6cbfa8-964b-41d3-9f24-7d1aed22cd79.jpg", + "/files/images/buxton/upload_8c33d572-07da-4599-944c-eb2370b16a63.png", + "/files/images/buxton/upload_9afc5cca-6208-4944-a0f6-1c3fcd41fdcf.png", + "/files/images/buxton/upload_74e79798-9c9e-4c54-b42f-5813f218bc63.png", + "/files/images/buxton/upload_2bea6876-dc4e-4681-a1d3-433caec163c1.png" ], "title": "3Dconnexion Magellan/SpaceMouse Plus", "company": "3Dconnexion", @@ -114,13 +114,13 @@ "SpaceBall_5000_Data_Sheet.jpg" ], "__images": [ - "/files/images/buxton/upload_81972990-8cad-4299-926a-fe5d49711a80.jpg", - "/files/images/buxton/upload_04103620-72e4-431f-b34f-61d0f158277a.png", - "/files/images/buxton/upload_9bfe7c5a-1c5e-46e3-8f8d-4e0eec3e38e3.png", - "/files/images/buxton/upload_77da85f5-6575-4a8d-acb6-52f2df3307b0.png", - "/files/images/buxton/upload_1c041a33-b258-42d1-b9f2-d610a4838fb3.jpg", - "/files/images/buxton/upload_841f0d98-27d7-4298-a71d-c5cba72a262a.jpg", - "/files/images/buxton/upload_0e0eaf99-f8bb-4f02-ad46-651cd67c13b1.jpg" + "/files/images/buxton/upload_94e39580-5cca-46e9-ae49-ab6cd2fe3cad.jpg", + "/files/images/buxton/upload_eacee8a5-9849-4401-9c38-aa46fc0f517b.png", + "/files/images/buxton/upload_9b0b1f35-ac7c-4160-8806-8d243223872b.png", + "/files/images/buxton/upload_cf0c6e39-9ae6-48ce-90bd-d9f335503439.png", + "/files/images/buxton/upload_b4285b9f-26cd-4de5-8e37-c4e563c3e7f6.jpg", + "/files/images/buxton/upload_5b6ff31b-81b2-4a74-8591-27730c24225b.jpg", + "/files/images/buxton/upload_64dcea06-3b35-4979-bf40-5dfa5d4668b1.jpg" ], "title": "3Dconnexion Spaceball 5000", "company": "3Dconnexion", @@ -171,13 +171,13 @@ "SpaceNavigator_Press_Release.jpg" ], "__images": [ - "/files/images/buxton/upload_b44ec511-334e-46c0-a315-63d90fac8117.jpg", - "/files/images/buxton/upload_734ae360-faaf-4c78-89b4-a3f120fe233e.png", - "/files/images/buxton/upload_d20bbf6a-7310-407a-8b85-c607e9cf7f73.png", - "/files/images/buxton/upload_e9236600-dd5f-4805-92ca-805d5a301aa1.jpg", - "/files/images/buxton/upload_c85c977d-ef99-44be-b55c-8e8dde124e83.png", - "/files/images/buxton/upload_a6034d66-7de6-4d4b-bd64-ea95cc00ae8a.png", - "/files/images/buxton/upload_07415a65-964a-4936-aa6e-79861e8ebcbf.png" + "/files/images/buxton/upload_73511beb-f2bf-4f28-a1ea-64ef52a00426.jpg", + "/files/images/buxton/upload_4e088fb4-e5ff-4a1b-ba88-5f4575c86fe3.png", + "/files/images/buxton/upload_876a9921-3eb1-4c35-99e3-b82924fb88c4.png", + "/files/images/buxton/upload_d23c2886-c2b9-4558-9bfb-966aca7be20e.jpg", + "/files/images/buxton/upload_aef9171b-2e19-4fcb-b2dc-2281e89d498b.png", + "/files/images/buxton/upload_bbdaf252-1689-4680-8b19-ec5e79088e44.png", + "/files/images/buxton/upload_4cf49440-cf6b-484d-8391-3a2b0fae2b7e.png" ], "title": "3Dconnexion SpaceNavigator ", "company": "3Dconnexion", @@ -222,12 +222,12 @@ "3M_2006_Catalogue_p18.jpg" ], "__images": [ - "/files/images/buxton/upload_52b83c2a-5fe4-42aa-a488-5667b0a5beae.jpg", - "/files/images/buxton/upload_e05d8710-d82b-4f3b-8940-3745db1c855c.jpg", - "/files/images/buxton/upload_557c6fc7-04a3-4698-acde-4e53ceb6793c.jpg", - "/files/images/buxton/upload_d9723beb-bfe3-4556-b17d-aedf2db59777.jpg", - "/files/images/buxton/upload_5cb15815-3cab-406f-bf95-f9410997b4f4.jpg", - "/files/images/buxton/upload_a7fc91e0-7672-4f81-a8f3-66072997bd44.jpg" + "/files/images/buxton/upload_02df5121-8eff-452c-a52b-a44238afc06d.jpg", + "/files/images/buxton/upload_169aa4ee-4c34-43a2-8302-48bb3b7a01b6.jpg", + "/files/images/buxton/upload_a4d11c27-e4fa-4912-96da-3d971ec49ca0.jpg", + "/files/images/buxton/upload_7e9e1862-72e7-4f0d-8451-36de8c1bbe9c.jpg", + "/files/images/buxton/upload_76fa705f-2470-439c-acf6-03482d7a9570.jpg", + "/files/images/buxton/upload_7b6dd2c9-b88f-4958-a4d0-94bb42172e26.jpg" ], "title": "3M EM500 Ergonomic Mouse", "company": "3M", @@ -268,13 +268,13 @@ "Abaton_ProPoint_Brochure.jpg" ], "__images": [ - "/files/images/buxton/upload_f6f038a9-3583-4d21-9a43-f762e1df0b52.jpg", - "/files/images/buxton/upload_ad5f2bbd-66be-4dde-afe4-60e353a63f74.jpg", - "/files/images/buxton/upload_2e384260-5d2b-47a4-9508-028462a5a1e7.jpg", - "/files/images/buxton/upload_4dfcd3af-f06d-4c3e-8dff-7c43acd79a16.jpg", - "/files/images/buxton/upload_19eea9af-abec-4617-8b8d-fcb6637420de.jpg", - "/files/images/buxton/upload_89702b8a-fcb5-426d-b5af-c58e62d1c8ff.jpg", - "/files/images/buxton/upload_44419996-994e-471c-8dc7-cda22b00ac24.jpg" + "/files/images/buxton/upload_37169968-d329-40c5-9483-6bc198edc43c.jpg", + "/files/images/buxton/upload_64731ea4-a3aa-43ec-a56d-d4f6ecba7cf0.jpg", + "/files/images/buxton/upload_c41feac8-3b98-4d85-b9c7-79b3482a0695.jpg", + "/files/images/buxton/upload_5f67807b-f61b-4816-b93f-6d88c95b2418.jpg", + "/files/images/buxton/upload_a3e3cab8-48ab-43c2-bed9-5cc0ce68928d.jpg", + "/files/images/buxton/upload_4c3ac379-6703-4c87-a4a0-ca450a1151d2.jpg", + "/files/images/buxton/upload_8df14dc0-d75d-41f0-9e70-a221598d3df3.jpg" ], "title": "Abaton ProPoint Optical Trackball", "company": "Abaton", @@ -305,8 +305,8 @@ "Active_Book_Brochure_p1.jpg" ], "__images": [ - "/files/images/buxton/upload_2159da7b-9ebd-41ed-8b60-9eb36a6c6685.jpg", - "/files/images/buxton/upload_6d470914-fc41-4151-858b-f945807e62a2.png" + "/files/images/buxton/upload_9c8aa6a2-570f-4915-b840-504c8531c341.jpg", + "/files/images/buxton/upload_fbb7ad12-2a5d-4f76-89a9-ec30d7260031.png" ], "title": "Active Book Company Active Book Prototype", "company": "Active Book Company", @@ -342,11 +342,11 @@ "Adesso_ACK-540PW_June 21_2003.jpg" ], "__images": [ - "/files/images/buxton/upload_189469a3-1133-4a4f-8720-19c04f29684e.jpg", - "/files/images/buxton/upload_73f5d066-f9b5-41ce-9ce3-e27253ef51e7.jpg", - "/files/images/buxton/upload_498e5cbd-d65e-4b01-bed2-bcb2723ffee5.jpg", - "/files/images/buxton/upload_97ee9d03-07e0-448c-89f6-6ac61948de68.jpg", - "/files/images/buxton/upload_661e7387-dcd7-4ca1-8493-2e94f8803ef7.jpg" + "/files/images/buxton/upload_967656ff-44d7-4693-bcb0-dc0eab204413.jpg", + "/files/images/buxton/upload_9ffd4ccb-8ca5-4926-8fa2-38277b2ccfb6.jpg", + "/files/images/buxton/upload_22399981-f8c0-46e0-953c-89f7eb043ad2.jpg", + "/files/images/buxton/upload_15ad02a9-123f-4e7e-94c5-d959076520f0.jpg", + "/files/images/buxton/upload_8905097a-3568-4d37-9ad3-126a0e429f12.jpg" ], "title": "Adesso ACK-540PB PS/2 Mini PS/2 Touchpad Keyboard", "company": "Adesso", @@ -405,17 +405,17 @@ "Adesso_KP_Mouse_11_Product.JPG" ], "__images": [ - "/files/images/buxton/upload_0a127e30-9014-4300-bade-07945fba940f.jpg", - "/files/images/buxton/upload_ca20611c-9061-4e56-9d72-4c4a3c798d3f.jpg", - "/files/images/buxton/upload_12b46021-eeef-47f0-9e55-ca9e9b76f9e4.jpg", - "/files/images/buxton/upload_5e86ad07-77af-4d3e-a82e-eaa9cafdbbe4.jpg", - "/files/images/buxton/upload_4be64833-53e9-4216-b7ec-d521e0b87933.jpg", - "/files/images/buxton/upload_7cb731b5-5c52-47e0-a33b-c113530478f2.jpg", - "/files/images/buxton/upload_b20407b3-3578-4fa5-8f16-e0bf729e4daa.jpg", - "/files/images/buxton/upload_bee2fcb8-702a-46aa-9ec3-eb9b50ef1ba7.jpg", - "/files/images/buxton/upload_0ee0f6d5-34fc-41f3-9c8e-cf462dbcc40b.jpg", - "/files/images/buxton/upload_8f442582-b901-4a38-8df6-5a9b3195df9f.jpg", - "/files/images/buxton/upload_3f96763c-c3af-46a7-8831-3206c8bc460e.jpg" + "/files/images/buxton/upload_5bc99192-0935-4f6d-8d6c-a2218d55b359.jpg", + "/files/images/buxton/upload_52a6212e-c79d-4ec6-86a0-a3ca4ea54387.jpg", + "/files/images/buxton/upload_997acb64-0e08-4af2-b0e3-0b86a18bace5.jpg", + "/files/images/buxton/upload_00586980-0a08-43e1-9721-c2f5dcd1079e.jpg", + "/files/images/buxton/upload_3f695b11-dc1d-4d54-abec-eacfac80bdc7.jpg", + "/files/images/buxton/upload_161f1420-9594-4dca-ba62-1ca32e9a2028.jpg", + "/files/images/buxton/upload_a8b4ea6e-f1f8-47db-a796-72f566e60e6f.jpg", + "/files/images/buxton/upload_b6365e4e-4656-4bbf-aec6-feb920be6df9.jpg", + "/files/images/buxton/upload_1a0e9061-39e1-4dec-8add-5cc1abd110b5.jpg", + "/files/images/buxton/upload_d9bba544-f2b1-4a15-81e5-0d10e60d7881.jpg", + "/files/images/buxton/upload_56d486df-d7bb-44b0-80ad-c41c63590bae.jpg" ], "title": "Adesso 2-in-1 Optical Keypad Calculator Mouse AKP-170", "company": "Adesso Inc", @@ -477,18 +477,18 @@ "NB75D_Mouse_Manual.jpg" ], "__images": [ - "/files/images/buxton/upload_dae8f950-38bf-4fdf-8db0-153e3cae9cae.jpg", - "/files/images/buxton/upload_3e054d83-d01f-4d3d-aad2-fa8ee1d22a97.jpg", - "/files/images/buxton/upload_e9c2ddb0-0684-4bb4-a88c-5ee8074e456e.jpg", - "/files/images/buxton/upload_9c829a69-7d45-4d25-b906-98153aa03001.jpg", - "/files/images/buxton/upload_4faa425c-a100-4ce4-869c-a6c6705779ee.jpg", - "/files/images/buxton/upload_ed20ac31-69f6-45b8-b8e0-b8ad829ba002.jpg", - "/files/images/buxton/upload_f3d3d8f5-01cf-4cd1-9d1c-0a11a8c3e239.jpg", - "/files/images/buxton/upload_af1fa3b6-4537-416a-b626-34bed1154f35.jpg", - "/files/images/buxton/upload_5127f377-b697-4ad7-9fb3-fd6f82017c3c.jpg", - "/files/images/buxton/upload_061ae6a2-e083-492a-bc8a-826c4be00790.jpg", - "/files/images/buxton/upload_32e91966-7f1b-4cd7-858b-9cdb63affd13.jpg", - "/files/images/buxton/upload_ccc9de21-b047-4f9c-89c6-08fb3d206c7a.jpg" + "/files/images/buxton/upload_2db5c520-b370-4f03-8481-908e42428466.jpg", + "/files/images/buxton/upload_b28643eb-57a0-4602-b7cc-c41d553628b9.jpg", + "/files/images/buxton/upload_2478a89a-4eea-4e4c-af83-ecd292f44f3d.jpg", + "/files/images/buxton/upload_113d7356-f550-4491-849d-f69087c73918.jpg", + "/files/images/buxton/upload_44c40c44-ade6-499d-951c-4b436131e66e.jpg", + "/files/images/buxton/upload_d91f9756-09bc-447f-8f04-dc78344a5f11.jpg", + "/files/images/buxton/upload_b8c51011-5f93-43f3-85aa-b611a3b3cf93.jpg", + "/files/images/buxton/upload_483544a3-c3f7-4c8f-a236-def10d32f4f0.jpg", + "/files/images/buxton/upload_ea048294-3f57-42c3-b5b4-27062a5755dc.jpg", + "/files/images/buxton/upload_8eb1b9b1-9ca3-49c8-9bd4-7302a9c1f07e.jpg", + "/files/images/buxton/upload_029aa1d6-056d-4cf0-8eaf-b23b3d0e4317.jpg", + "/files/images/buxton/upload_3acc0955-da14-4a53-ac58-2e494e04ca78.jpg" ], "title": "A4 Tech BatteryFREE Wireless Optical Mouse Model NB-75D", "company": "A4Tech", diff --git a/src/server/ApiManagers/DownloadManager.ts b/src/server/ApiManagers/DownloadManager.ts index fad5e6789..01d2dfcad 100644 --- a/src/server/ApiManagers/DownloadManager.ts +++ b/src/server/ApiManagers/DownloadManager.ts @@ -254,7 +254,7 @@ async function writeHierarchyRecursive(file: Archiver.Archiver, hierarchy: Hiera // and dropped in the browser and thus hosted remotely) so we upload it // to our server and point the zip file to it, so it can bundle up the bytes const information = await DashUploadUtils.UploadImage(result); - path = information instanceof Error ? "" : information.serverAccessPaths[SizeSuffix.Original]; + path = information instanceof Error ? "" : information.accessPaths[SizeSuffix.Original].server; } // write the file specified by the path to the directory in the // zip file given by the prefix. diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 83a0064e8..0f1758c26 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -61,13 +61,16 @@ export namespace DashUploadUtils { const type = "content-type"; export interface ImageUploadInformation { - clientAccessPath: string; - serverAccessPaths: { [key: string]: string }; + accessPaths: AccessPathInfo; exifData: EnrichedExifData; contentSize?: number; contentType?: string; } + export interface AccessPathInfo { + [suffix: string]: { client: string, server: string }; + } + const { imageFormats, videoFormats, applicationFormats } = AcceptibleMedia; export async function upload(file: File): Promise { @@ -94,7 +97,7 @@ export namespace DashUploadUtils { } console.log(red(`Ignoring unsupported file (${name}) with upload type (${type}).`)); - return { clientAccessPath: undefined }; + return { accessPaths: undefined }; } async function UploadPdf(absolutePath: string) { @@ -213,29 +216,40 @@ export namespace DashUploadUtils { }; }; - export async function MoveParsedFile(absolutePath: string, destination: Directory): Promise<{ clientAccessPath: Opt }> { - return new Promise<{ clientAccessPath: Opt }>(resolve => { + export async function MoveParsedFile(absolutePath: string, destination: Directory): Promise> { + return new Promise>(resolve => { const filename = basename(absolutePath); const destinationPath = serverPathToFile(destination, filename); rename(absolutePath, destinationPath, error => { - resolve({ clientAccessPath: error ? undefined : clientPathToFile(destination, filename) }); + resolve(error ? undefined : { + agnostic: getAccessPaths(destination, filename) + }); }); }); } + function getAccessPaths(directory: Directory, fileName: string) { + return { + client: clientPathToFile(directory, fileName), + server: serverPathToFile(directory, fileName) + }; + } + export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, prefix = "", cleanUp = true): Promise => { const { requestable, source, ...remaining } = metadata; const extension = `.${remaining.contentType.split("/")[1].toLowerCase()}`; const resolved = filename || `${prefix}upload_${Utils.GenerateGuid()}${extension}`; + const { images } = Directory; const information: ImageUploadInformation = { - clientAccessPath: clientPathToFile(Directory.images, resolved), - serverAccessPaths: {}, + accessPaths: { + agnostic: getAccessPaths(images, resolved) + }, ...remaining }; const outputPath = pathToDirectory(Directory.images); const writtenFiles = await outputResizedImages(() => request(requestable), outputPath, resolved, extension); for (const suffix of Object.keys(writtenFiles)) { - information.serverAccessPaths[suffix] = serverPathToFile(Directory.images, writtenFiles[suffix]); + information.accessPaths[suffix] = getAccessPaths(images, writtenFiles[suffix]); } if (isLocal().test(source) && cleanUp) { unlinkSync(source); @@ -270,10 +284,9 @@ export namespace DashUploadUtils { export async function outputResizedImages(readStreamSource: () => ReadStreamLike | Promise, outputPath: string, fileName: string, ext: string) { const writtenFiles: { [suffix: string]: string } = {}; for (const { resizer, suffix } of resizers(ext)) { - const resizedPath = path.resolve(outputPath, InjectSize(fileName, suffix)); - writtenFiles[suffix] = resizedPath; + const resolved = writtenFiles[suffix] = InjectSize(fileName, suffix); await new Promise(async (resolve, reject) => { - const writeStream = createWriteStream(resizedPath); + const writeStream = createWriteStream(path.resolve(outputPath, resolved)); let readStream: ReadStreamLike; const source = readStreamSource(); if (source instanceof Promise) { diff --git a/src/server/apis/google/GooglePhotosUploadUtils.ts b/src/server/apis/google/GooglePhotosUploadUtils.ts index 8ae63caa3..d305eed0a 100644 --- a/src/server/apis/google/GooglePhotosUploadUtils.ts +++ b/src/server/apis/google/GooglePhotosUploadUtils.ts @@ -84,6 +84,7 @@ export namespace GooglePhotosUploadUtils { if (!DashUploadUtils.validateExtension(url)) { return undefined; } + const body = await request(url, { encoding: null }); // returns a readable stream with the unencoded binary image data const parameters = { method: 'POST', uri: prepend('uploads'), @@ -92,7 +93,7 @@ export namespace GooglePhotosUploadUtils { 'X-Goog-Upload-File-Name': filename || path.basename(url), 'X-Goog-Upload-Protocol': 'raw' }, - body: await request(url, { encoding: null }) // returns a readable stream with the unencoded binary image data + body }; return new Promise((resolve, reject) => request(parameters, (error, _response, body) => { if (error) { -- cgit v1.2.3-70-g09d2 From 96e78c3fc0975a2e21c356f01fdaad631a04ff82 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 12 Feb 2020 14:53:24 -0500 Subject: fixed summary stuff --- src/client/util/RichTextSchema.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 3cf0561dc..80bd75771 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1136,7 +1136,7 @@ const fromJson = schema.nodeFromJSON; schema.nodeFromJSON = (json: any) => { const node = fromJson(json); - if (json.type === schema.marks.summarize.name) { + if (json.type === schema.nodes.summary.name) { node.attrs.text = Slice.fromJSON(schema, node.attrs.textslice); } return node; -- cgit v1.2.3-70-g09d2 From 8cdee98fc23997753a4ec389802115be552b0db2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 15 Feb 2020 22:57:59 -0500 Subject: fixed infinite render loop --- src/client/util/RichTextSchema.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 80bd75771..3a3bcd1ad 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -824,7 +824,7 @@ export class DashDocView { ScreenToLocalTransform={this.getDocTransform} addDocTab={this._textBox.props.addDocTab} pinToPres={returnFalse} - renderDepth={1} + renderDepth={self._textBox.props.renderDepth + 1} PanelWidth={finalLayout[WidthSym]} PanelHeight={finalLayout[HeightSym]} focus={this.outerFocus} -- cgit v1.2.3-70-g09d2 From 2ae91501a3195da9dcbc02e180b108983cd1d8af Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 16 Feb 2020 21:47:28 -0500 Subject: got rid of unneeded ignoreAspect field. other cleanup. --- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 9 ++------- src/client/views/collections/CollectionDockingView.tsx | 8 ++++---- .../views/collections/CollectionMasonryViewFieldRow.tsx | 3 ++- src/client/views/collections/CollectionStackingView.tsx | 6 +++--- src/client/views/collections/CollectionView.tsx | 17 ----------------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 15 +++++---------- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 4 ++-- src/new_fields/Doc.ts | 3 +-- src/new_fields/documentSchemas.ts | 1 - 12 files changed, 22 insertions(+), 50 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 3a3bcd1ad..656215368 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -723,7 +723,7 @@ export class DashDocView { const { scale, translateX, translateY } = Utils.GetScreenTransform(this._outer); return new Transform(-translateX, -translateY, 1).scale(1 / this.contentScaling() / scale); } - contentScaling = () => NumCast(this._dashDoc!._nativeWidth) > 0 && !this._dashDoc!.ignoreAspect ? this._dashDoc![WidthSym]() / NumCast(this._dashDoc!._nativeWidth) : 1; + contentScaling = () => NumCast(this._dashDoc!._nativeWidth) > 0 ? this._dashDoc![WidthSym]() / NumCast(this._dashDoc!._nativeWidth) : 1; outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document); // ideally, this would scroll to show the focus target constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { this._textBox = tbox; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5fc14e716..cc7388a61 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -283,17 +283,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); - const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); - if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { - layoutDoc.ignoreAspect = false; - layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; - layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; - } + const fixedAspect = e.ctrlKey || (nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; } - if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { + if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6abfb59c3..bf0333d55 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -678,8 +678,8 @@ export class DockedFrameRenderer extends React.Component { panelWidth = () => this.layoutDoc && this.layoutDoc.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : this._panelWidth; panelHeight = () => this._panelHeight; - nativeWidth = () => !this.layoutDoc!.ignoreAspect && !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0; - nativeHeight = () => !this.layoutDoc!.ignoreAspect && !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0; + nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0; + nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0; contentScaling = () => { if (this.layoutDoc!.type === DocumentType.PDF) { @@ -705,8 +705,8 @@ export class DockedFrameRenderer extends React.Component { } return Transform.Identity(); } - get previewPanelCenteringOffset() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } - get widthpercent() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } + get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } + get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } addDocTab = (doc: Doc, dataDoc: Opt, location: string, libraryPath?: Doc[]) => { SelectionManager.DeselectAll(); diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index f3dd7c733..c9b7ca221 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -259,7 +259,8 @@ export class CollectionMasonryViewFieldRow extends React.Component "", diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a9cefae6a..ad9dc8f7c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -185,7 +185,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (!d) return 0; const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); const nw = NumCast(layoutDoc._nativeWidth); - return Math.min(nw && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); + return Math.min(nw && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); } getDocHeight(d?: Doc) { if (!d) return 0; @@ -193,9 +193,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const nw = NumCast(layoutDoc._nativeWidth); const nh = NumCast(layoutDoc._nativeHeight); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); - if (!layoutDoc.ignoreAspect && !layoutDoc._fitWidth && nw && nh) { + if (!layoutDoc._fitWidth && nw && nh) { const aspect = nw && nh ? nh / nw : 1; - if (!(!layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid); + if (!(this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid); return wid * aspect; } return layoutDoc._fitWidth ? !nh ? this.props.PanelHeight() - 2 * this.yMargin : diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 48294f9c2..52a18fb99 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -90,11 +90,9 @@ export interface CollectionRenderProps { export class CollectionView extends Touchable { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } - private _reactionDisposer: IReactionDisposer | undefined; private _isChildActive = false; //TODO should this be observable? @observable private _isLightboxOpen = false; @observable private _curLightboxImg = 0; - @observable private _collapsed = true; @observable private static _safeMode = false; public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; } @@ -111,20 +109,6 @@ export class CollectionView extends Touchable { return viewField; } - componentDidMount = () => { - this._reactionDisposer = reaction(() => StrCast(this.props.Document._chromeStatus), - () => { - // chrome status is one of disabled, collapsed, or visible. this determines initial state from document - // chrome status may also be view-mode, in reference to stacking view's toggle mode. it is essentially disabled mode, but prevents the toggle button from showing up on the left sidebar. - const chromeStatus = this.props.Document._chromeStatus; - if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed" || chromeStatus === "replaced")) { - runInAction(() => this._collapsed = true); - } - }); - } - - componentWillUnmount = () => this._reactionDisposer && this._reactionDisposer(); - // bcz: Argh? What's the height of the collection chromes?? chromeHeight = () => (this.props.Document._chromeStatus === "enabled" ? -60 : 0); @@ -198,7 +182,6 @@ export class CollectionView extends Touchable { @action private collapse = (value: boolean) => { - this._collapsed = value; this.props.Document._chromeStatus = value ? "collapsed" : "enabled"; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 53d17b580..eaab4086c 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -60,7 +60,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 && !this.props.Document.ignoreAspect && !this.props.fitToBox ? this.width / this.nativeWidth : 1; + contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox ? this.width / this.nativeWidth : 1; panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth()); panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight()); getTransform = (): Transform => this.props.ScreenToLocalTransform() diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b4ec09aee..330410a92 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -364,18 +364,12 @@ export class DocumentView extends DocComponent(Docu const actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); - const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); - if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { - layoutDoc.ignoreAspect = false; - - layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; - layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; - } + const fixedAspect = e.ctrlKey || (nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; } - if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { + if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0); @@ -546,10 +540,11 @@ export class DocumentView extends DocComponent(Docu } @undoBatch - public static unfreezeNativeDimensions = action((layoutDoc: Doc): void => { + @action + public static unfreezeNativeDimensions(layoutDoc: Doc) { layoutDoc._nativeWidth = undefined; layoutDoc._nativeHeight = undefined; - }); + } toggleNativeDimensions = () => { if (this.Document._nativeWidth || this.Document._nativeHeight) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 364bce7a8..5b5768d54 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -375,7 +375,7 @@ export class ImageBox extends DocAnnotatableComponent
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index e1c5fd27f..a2aec699f 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -52,7 +52,7 @@ export class PDFBox extends DocAnnotatableComponent this._initialScale = this.props.ScreenToLocalTransform().Scale; const nw = this.Document._nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"], NumCast(this.Document._nativeWidth, 927)); const nh = this.Document._nativeHeight = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"], NumCast(this.Document._nativeHeight, 1200)); - !this.Document._fitWidth && !this.Document.ignoreAspect && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); + !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); const backup = "oldPath"; const { Document } = this.props; @@ -93,7 +93,7 @@ export class PDFBox extends DocAnnotatableComponent this.dataDoc[this.props.fieldKey + "-numPages"] = np; this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = nw * 96 / 72; this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = nh * 96 / 72; - !this.Document._fitWidth && !this.Document.ignoreAspect && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); + !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); } public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a722f552e..48890ac8d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -840,8 +840,7 @@ export namespace Doc { export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void { layoutDoc._autoHeight = false; - layoutDoc.ignoreAspect = false; - if (!layoutDoc.ignoreAspect && !layoutDoc._nativeWidth) { + if (!layoutDoc._nativeWidth) { layoutDoc._nativeWidth = NumCast(layoutDoc._width, width); layoutDoc._nativeHeight = NumCast(layoutDoc._height, height); } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 3cc05d3d5..f3726cb5a 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -34,7 +34,6 @@ export const documentSchema = createSchema({ onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped - ignoreAspect: "boolean", // whether aspect ratio should be ignored when laying out or manipulating the document isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee) treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden -- cgit v1.2.3-70-g09d2 From 66cfe6c5fab54c970ac51a4cd29ce1db50e464b3 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 18 Feb 2020 13:24:03 -0500 Subject: fixed titling. added border for embedded docs in text boxes. --- src/client/util/RichTextSchema.tsx | 8 +++++--- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.scss | 6 +++++- src/client/views/DocumentDecorations.tsx | 11 ++++------- src/client/views/collections/ParentDocumentSelector.tsx | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 656215368..23b0a56a8 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -12,7 +12,7 @@ import { Doc, Field, HeightSym, WidthSym } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; import { ObjectField } from "../../new_fields/ObjectField"; import { ComputedField } from "../../new_fields/ScriptField"; -import { BoolCast, NumCast, StrCast } from "../../new_fields/Types"; +import { BoolCast, NumCast, StrCast, Cast } from "../../new_fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { DocumentView } from "../views/nodes/DocumentView"; @@ -731,6 +731,7 @@ export class DashDocView { this._outer = document.createElement("span"); this._outer.style.position = "relative"; this._outer.style.textIndent = "0"; + this._outer.style.border = "1px solid " + StrCast(tbox.Document.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray")); this._outer.style.width = node.attrs.width; this._outer.style.height = node.attrs.height; this._outer.style.display = node.attrs.hidden ? "none" : "inline-block"; @@ -810,9 +811,10 @@ export class DashDocView { } } this._reactionDisposer?.(); - this._reactionDisposer = reaction(() => [finalLayout[WidthSym](), finalLayout[HeightSym]()], (dim) => { + this._reactionDisposer = reaction(() => ({ dim: [finalLayout[WidthSym](), finalLayout[HeightSym]()], color: finalLayout.color }), ({ dim, color }) => { this._dashSpan.style.width = this._outer.style.width = Math.max(20, dim[0]) + "px"; this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px"; + this._outer.style.border = "1px solid " + StrCast(finalLayout.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray")); }, { fireImmediately: true }); ReactDOM.render( = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean))); - return !view0 ? (null) :
+ return !view0 ? (null) :
v).map(v => v as DocumentView)} templates={templates} />}>
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 4bf7e5ec4..202174097 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -90,7 +90,7 @@ $linkGap : 3px; cursor: ew-resize; } - .title { + .documentDecorations-title { background: $alt-accent; opacity: 1; grid-column-start: 3; @@ -99,6 +99,10 @@ $linkGap : 3px; overflow: hidden; text-align: center; display:flex; + .documentDecorations-contextMenu { + width: 25px; + height: calc(100% + 8px); // 8px for the height of the top resizer bar + } } .publishBox { width: 20px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2d49a13b6..8e4598339 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -106,13 +106,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } else if (this._titleControlString.startsWith("#")) { const selectionTitleFieldKey = this._titleControlString.substring(1); selectionTitleFieldKey === "title" && (SelectionManager.SelectedDocuments()[0].props.Document.customTitle = !this._accumulatedTitle.startsWith("-")); - let didAnything = false; UndoManager.RunInBatch(() => selectionTitleFieldKey && SelectionManager.SelectedDocuments().forEach(d => { const value = typeof d.props.Document[selectionTitleFieldKey] === "number" ? +this._accumulatedTitle : this._accumulatedTitle; - didAnything = didAnything || d.props.Document[selectionTitleFieldKey] !== value; Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, value, true); }), "title blur"); - if (!didAnything) UndoManager.Undo(); } } }); @@ -402,22 +399,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return (null); } const minimizeIcon = ( -
+
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/} {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
); const titleArea = this._edtingTitle ? <> - this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} />
DocUtils.Publish(seldoc.props.Document, this._accumulatedTitle, seldoc.props.addDocument, seldoc.props.removeDocument)}>
: -
-
+
+
{`${this.selectionTitle}`} diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 41b9e821c..027ac5a0e 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -82,7 +82,7 @@ export class ParentDocSelector extends React.Component {
); - return
e.stopPropagation()} className="parentDocumentSelector-linkFlyout"> + return
e.stopPropagation()} className="parentDocumentSelector-linkFlyout"> -- cgit v1.2.3-70-g09d2 From d53ae2d90e7d7de8135ff19e18535cccd7a90ed0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 19 Feb 2020 00:45:23 -0500 Subject: getting rid of data docs from many places --- src/client/documents/Documents.ts | 2 +- src/client/util/DictationManager.ts | 4 +- src/client/util/DocumentManager.ts | 6 +-- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/DocComponent.tsx | 4 +- src/client/views/DocumentButtonBar.tsx | 8 +-- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/MainView.tsx | 6 +-- src/client/views/MainViewNotifs.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 60 +++++++++------------- .../views/collections/CollectionSchemaCells.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 6 +-- .../views/collections/CollectionTreeView.tsx | 12 ++--- src/client/views/collections/CollectionView.tsx | 4 +- .../views/collections/ParentDocumentSelector.tsx | 4 +- src/client/views/linking/LinkFollowBox.tsx | 16 +++--- src/client/views/linking/LinkMenu.tsx | 2 +- src/client/views/linking/LinkMenuGroup.tsx | 2 +- src/client/views/linking/LinkMenuItem.tsx | 2 +- .../views/nodes/ContentFittingDocumentView.tsx | 2 +- src/client/views/nodes/DocuLinkBox.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 22 ++++---- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FontIconBox.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/FormattedTextBoxComment.tsx | 4 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/PresBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/pdf/Annotation.tsx | 6 +-- src/client/views/pdf/PDFViewer.tsx | 2 +- .../views/presentationview/PresElementBox.tsx | 3 +- src/client/views/search/SearchItem.tsx | 6 +-- src/new_fields/Doc.ts | 4 +- 36 files changed, 105 insertions(+), 112 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 669aa97b5..650538e93 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -654,7 +654,7 @@ export namespace Docs { { type: type, content: [ - ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, undefined, config.initialWidth, config.path)) + ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, config.initialWidth, config.path)) ] } ] diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 3394cb93d..569c1ef6d 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -326,7 +326,7 @@ export namespace DictationManager { ["open fields", { action: (target: DocumentView) => { const kvp = Docs.Create.KVPDocument(target.props.Document, { _width: 300, _height: 300 }); - target.props.addDocTab(kvp, target.props.DataDoc, "onRight"); + target.props.addDocTab(kvp, "onRight"); } }], @@ -340,7 +340,7 @@ export namespace DictationManager { const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`; proto.data = new RichTextField(proseMirrorState); proto.backgroundColor = "#eeffff"; - target.props.addDocTab(newBox, proto, "onRight"); + target.props.addDocTab(newBox, "onRight"); } }] diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index bfda8e75b..c639f07f5 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -148,7 +148,7 @@ export class DocumentManager { const targetDocContext = (annotatedDoc ? annotatedDoc : contextDoc); if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default - (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined); + (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc))); highlight(); } else { const targetDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext); @@ -164,12 +164,12 @@ export class DocumentManager { retryDocView.props.focus(targetDoc, willZoom); // focus on the target if it now exists in the context } else { if (closeContextIfNotFound && targetDocContextView.props.removeDocument) targetDocContextView.props.removeDocument(targetDocContextView.props.Document); - targetDoc.layout && (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined); // otherwise create a new view of the target + targetDoc.layout && (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc))); // otherwise create a new view of the target } highlight(); }, 0); } else { // there's no context view so we need to create one first and try again - (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext, undefined); + (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext); setTimeout(() => { const finalDocView = DocumentManager.Instance.getFirstDocumentView(targetDoc); const finalDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 23b0a56a8..cfbae5dca 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -613,7 +613,7 @@ export class ImageResizeView { DocServer.GetRefField(node.attrs.docid).then(async linkDoc => (linkDoc instanceof Doc) && DocumentManager.Instance.FollowLink(linkDoc, view.state.schema.Document, - document => addDocTab(document, undefined, node.attrs.location ? node.attrs.location : "inTab"), false)); + document => addDocTab(document, node.attrs.location ? node.attrs.location : "inTab"), false)); } }; this._handle.onpointerdown = function (e: any) { diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 0bf944f22..61b1f9e0f 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,4 +1,4 @@ -import { Doc, Opt } from '../../new_fields/Doc'; +import { Doc, Opt, DataSym } from '../../new_fields/Doc'; import { Touchable } from './Touchable'; import { computed, action, observable } from 'mobx'; import { Cast } from '../../new_fields/Types'; @@ -58,7 +58,7 @@ export function DocAnnotatableComponent

(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 : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; } + @computed get dataDoc() { return this.props.Document[DataSym]; } _annotationKey: string = "annotations"; public set annotationKey(val: string) { this._annotationKey = val; } diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index b530d8a42..c8ad78f47 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -251,10 +251,10 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | @computed get contextButton() { - return !this.view0 ? (null) : v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, data, where) => { - where === "onRight" ? CollectionDockingView.AddRightSplit(doc, data) : - this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc, data) : - this.view0?.props.addDocTab(doc, data, "onRight"); + return !this.view0 ? (null) : v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, where) => { + where === "onRight" ? CollectionDockingView.AddRightSplit(doc) : + this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc) : + this.view0?.props.addDocTab(doc, "onRight"); return true; }} />; } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 979687ffb..d0900251d 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -156,7 +156,7 @@ export default class KeyManager { return { stopPropagation: false, preventDefault: false }; } } - MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform, undefined); + MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform); break; case "arrowleft": if (document.activeElement) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 7948da3c5..1849ec250 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -185,7 +185,7 @@ export class MainView extends React.Component { reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized, initialized => initialized && received && DocServer.GetRefField(received).then(docField => { if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) { - CollectionDockingView.AddRightSplit(docField, undefined); + CollectionDockingView.AddRightSplit(docField); } }), ); @@ -379,10 +379,10 @@ export class MainView extends React.Component { document.removeEventListener("pointerup", this.onPointerUp); } flyoutWidthFunc = () => this.flyoutWidth; - addDocTabFunc = (doc: Doc, data: Opt, where: string, libraryPath?: Doc[]): boolean => { + addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => { return where === "close" ? CollectionDockingView.CloseRightSplit(doc) : doc.dockingConfig ? this.openWorkspace(doc) : - CollectionDockingView.AddRightSplit(doc, undefined, libraryPath); + CollectionDockingView.AddRightSplit(doc, libraryPath); } mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1); diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx index 09fa1cb0c..82e07c449 100644 --- a/src/client/views/MainViewNotifs.tsx +++ b/src/client/views/MainViewNotifs.tsx @@ -15,7 +15,7 @@ export class MainViewNotifs extends React.Component { @observable static NotifsCol: Opt; openNotifsCol = () => { if (MainViewNotifs.NotifsCol) { - CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol, undefined); + CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol); } } render() { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 26b65c898..6e1d522fc 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -8,7 +8,7 @@ import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import * as GoldenLayout from "../../../client/goldenLayout"; import { DateField } from '../../../new_fields/DateField'; -import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Field, Opt, DataSym } from "../../../new_fields/Doc"; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { FieldId } from "../../../new_fields/RefField"; @@ -38,7 +38,7 @@ const _global = (window /* browser */ || global /* node */) as any; export class CollectionDockingView extends React.Component { @observable public static Instances: CollectionDockingView[] = []; @computed public static get Instance() { return CollectionDockingView.Instances[0]; } - public static makeDocumentConfig(document: Doc, dataDoc: Doc | undefined, width?: number, libraryPath?: Doc[]) { + public static makeDocumentConfig(document: Doc, width?: number, libraryPath?: Doc[]) { return { type: 'react-component', component: 'DocumentFrameRenderer', @@ -46,8 +46,7 @@ export class CollectionDockingView extends React.Component d[Id]) : [] + libraryPath: libraryPath?.map(d => d[Id]) //collectionDockingView: CollectionDockingView.Instance } }; @@ -76,12 +75,12 @@ export class CollectionDockingView extends React.Component { - CollectionDockingView.makeDocumentConfig(doc, undefined); + CollectionDockingView.makeDocumentConfig(doc); }) }; } @@ -97,10 +96,9 @@ export class CollectionDockingView extends React.Component { if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" && DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)?.Document.isDisplayPanel) { - const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath); + const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath); child.addChild(newItemStackConfig, undefined); !addToSplit && child.contentItems[0].remove(); instance.layoutChanged(document); @@ -188,7 +186,7 @@ export class CollectionDockingView extends React.Component tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)?.Document.isDisplayPanel) { - const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath); + const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath); child.addChild(newItemStackConfig, undefined); !addToSplit && child.contentItems[j].remove(); instance.layoutChanged(document); @@ -210,12 +208,12 @@ export class CollectionDockingView extends React.Component { + public AddTab = (stack: any, document: Doc, libraryPath?: Doc[]) => { Doc.GetProto(document).lastOpened = new DateField; - const docContentConfig = CollectionDockingView.makeDocumentConfig(document, dataDocument, undefined, libraryPath); + const docContentConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath); if (stack === undefined) { let stack: any = this._goldenLayout.root; while (!stack.isStack) { @@ -427,7 +425,6 @@ export class CollectionDockingView extends React.Component`; tab.titleElement[0].onclick = (e: any) => tab.titleElement[0].focus(); @@ -507,7 +504,7 @@ export class CollectionDockingView extends React.Component { if (e.target === stack.header.element[0] && e.button === 1) { - this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" }), undefined); + this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" })); } }); @@ -580,7 +577,6 @@ export class CollectionDockingView extends React.Component string | undefined; @@ -593,7 +589,6 @@ export class DockedFrameRenderer extends React.Component { @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; - @observable private _dataDoc: Opt; @observable private _isActive: boolean = false; get _stack(): any { @@ -601,12 +596,7 @@ export class DockedFrameRenderer extends React.Component { } constructor(props: any) { super(props); - DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => { - this._document = f as Doc; - if (this.props.dataDocumentId && this.props.documentId !== this.props.dataDocumentId) { - DocServer.GetRefField(this.props.dataDocumentId).then(action((f: Opt) => this._dataDoc = f as Doc)); - } - })); + DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => this._document = f as Doc)); this.props.libraryPath && this.setupLibraryPath(); } @@ -630,7 +620,7 @@ export class DockedFrameRenderer extends React.Component { pinDoc.presentationTargetDoc = doc; Doc.AddDocToList(curPres, "data", pinDoc); if (!DocumentManager.Instance.getDocumentView(curPres)) { - CollectionDockingView.AddRightSplit(curPres, undefined); + CollectionDockingView.AddRightSplit(curPres); } } } @@ -708,16 +698,16 @@ export class DockedFrameRenderer extends React.Component { get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } - addDocTab = (doc: Doc, dataDoc: Opt, location: string, libraryPath?: Doc[]) => { + addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { SelectionManager.DeselectAll(); if (doc.dockingConfig) { return MainView.Instance.openWorkspace(doc); } else if (location === "onRight") { - return CollectionDockingView.AddRightSplit(doc, dataDoc, libraryPath); + return CollectionDockingView.AddRightSplit(doc, libraryPath); } else if (location === "close") { return CollectionDockingView.CloseRightSplit(doc); } else { - return CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc, libraryPath); + return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath); } } @@ -725,7 +715,7 @@ export class DockedFrameRenderer extends React.Component { TraceMobx(); if (!this._document) return (null); const document = this._document; - const resolvedDataDoc = document.layout instanceof Doc ? document : this._dataDoc; + const resolvedDataDoc = this._document[DataSym] !== this._document && this._document[DataSym];// document.layout instanceof Doc ? document : this._dataDoc; return {

); } } -Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc, undefined); }); -Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, undefined, shiftKey); }); +Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc); }); +Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, shiftKey); }); diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index a3b1b5ec0..851fded71 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -35,7 +35,7 @@ export interface CellProps { Document: Doc; fieldKey: string; renderDepth: number; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index c422c38f1..7dee7f18f 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -224,7 +224,7 @@ export interface SchemaTableProps { ScreenToLocalTransform: () => Transform; active: (outsideReaction: boolean) => boolean; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; isSelected: (outsideReaction?: boolean) => boolean; isFocused: (document: Doc) => boolean; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index ad9dc8f7c..0d5d3e449 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,7 +4,7 @@ import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import Switch from 'rc-switch'; -import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; +import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; @@ -62,7 +62,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); const style = this.isStackingView ? { width: width(), marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; return
- {this.getDisplayDoc(d, Cast(d.resolvedDataDoc, Doc, null) || this.props.DataDoc, dxf, width)} + {this.getDisplayDoc(d, this.props.DataDoc, dxf, width)}
; }); } @@ -158,7 +158,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const height = () => this.getDocHeight(doc); return boolean; moveDocument: DragManager.MoveFunction; dropAction: "alias" | "copy" | undefined; - addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean; + addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean; pinToPres: (document: Doc) => void; panelWidth: () => number; panelHeight: () => number; @@ -128,7 +128,7 @@ class TreeView extends React.Component { } @undoBatch delete = () => this.props.deleteDoc(this.props.document); - @undoBatch openRight = () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight", this.props.libraryPath); + @undoBatch openRight = () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath); @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete(); @undoBatch move = (doc: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => { return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc); @@ -201,8 +201,8 @@ class TreeView extends React.Component { ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List(), icon: "plus" }); } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) { ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" }); - ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "inTab", this.props.libraryPath), icon: "folder" }); - ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight", this.props.libraryPath), icon: "caret-square-right" }); + ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab", this.props.libraryPath), icon: "folder" }); + ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath), icon: "caret-square-right" }); if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) { ContextMenu.Instance.addItem({ description: "Focus", event: () => (view => view && view.props.focus(this.props.document, true))(DocumentManager.Instance.getFirstDocumentView(this.props.document)), icon: "camera" }); } @@ -212,7 +212,7 @@ class TreeView extends React.Component { ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" }); } ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" }); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" }); + ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, "onRight"); }, icon: "layer-group" }); ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" }); ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15); e.stopPropagation(); @@ -457,7 +457,7 @@ class TreeView extends React.Component { remove: ((doc: Doc) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, - addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean, + addDocTab: (doc: Doc, where: string) => boolean, pinToPres: (document: Doc) => void, backgroundColor: undefined | ((document: Doc) => string | undefined), screenToLocalXf: () => Transform, diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 79fd7d792..95f9fa62f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -229,10 +229,10 @@ export class CollectionView extends Touchable { const layoutItems = existing && "subitems" in existing ? existing.subitems : []; layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); if (this.props.Document.childLayout instanceof Doc) { - layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, undefined, "onRight"), icon: "project-diagram" }); + layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" }); } if (this.props.Document.childDetailed instanceof Doc) { - layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, undefined, "onRight"), icon: "project-diagram" }); + layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" }); } !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 027ac5a0e..43ba5c614 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -24,7 +24,7 @@ type SelectorProps = { Document: Doc, Views: DocumentView[], Stack?: any, - addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void + addDocTab(doc: Doc, location: string): void }; @observer @@ -60,7 +60,7 @@ export class SelectorContextMenu extends React.Component { col._panX = newPanX; col._panY = newPanY; } - this.props.addDocTab(col, undefined, "inTab"); // bcz: dataDoc? + this.props.addDocTab(col, "inTab"); // bcz: dataDoc? }; } diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx index 325c92413..b47464517 100644 --- a/src/client/views/linking/LinkFollowBox.tsx +++ b/src/client/views/linking/LinkFollowBox.tsx @@ -183,9 +183,9 @@ export class LinkFollowBox extends React.Component { } - static _addDocTab: (undefined | ((doc: Doc, dataDoc: Opt, where: string) => boolean)); + static _addDocTab: (undefined | ((doc: Doc, where: string) => boolean)); - static setAddDocTab = (addFunc: (doc: Doc, dataDoc: Opt, where: string) => boolean) => { + static setAddDocTab = (addFunc: (doc: Doc, where: string) => boolean) => { LinkFollowBox._addDocTab = addFunc; } @@ -199,7 +199,7 @@ export class LinkFollowBox extends React.Component { options.context._panX = newPanX; options.context._panY = newPanY; } - (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "onRight"); + (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "onRight"); if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom }); @@ -212,7 +212,7 @@ export class LinkFollowBox extends React.Component { openLinkRight = () => { if (LinkFollowBox.destinationDoc) { const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc); - (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, undefined, "onRight"); + (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, "onRight"); this.highlightDoc(); SelectionManager.DeselectAll(); } @@ -222,8 +222,8 @@ export class LinkFollowBox extends React.Component { @undoBatch jumpToLink = async (options: { shouldZoom: boolean }) => { if (LinkFollowBox.sourceDoc && LinkFollowBox.linkDoc) { - const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); }; - //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)); + const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, "inTab"); SelectionManager.DeselectAll(); }; + //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, maxLocation)); DocumentManager.Instance.FollowLink(LinkFollowBox.linkDoc, LinkFollowBox.sourceDoc, focus, options && options.shouldZoom, false, undefined); } @@ -234,7 +234,7 @@ export class LinkFollowBox extends React.Component { if (LinkFollowBox.destinationDoc) { const fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc); // this.prosp.addDocTab is empty -- use the link source's addDocTab - (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, undefined, "inTab"); + (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, "inTab"); this.highlightDoc(); SelectionManager.DeselectAll(); @@ -251,7 +251,7 @@ export class LinkFollowBox extends React.Component { options.context._panX = newPanX; options.context._panY = newPanY; } - (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "inTab"); + (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "inTab"); if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom }); this.highlightDoc(); diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 1a40f0c55..a8aa01306 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -16,7 +16,7 @@ library.add(faTrash); interface Props { docView: DocumentView; changeFlyout: () => void; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; } @observer diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 0c38ff45c..78c77e106 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -17,7 +17,7 @@ interface LinkMenuGroupProps { group: Doc[]; groupType: string; showEditor: (linkDoc: Doc) => void; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; docView: DocumentView; } diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index b7d27ee30..54f5636e4 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -20,7 +20,7 @@ interface LinkMenuItemProps { sourceDoc: Doc; destinationDoc: Doc; showEditor: (linkDoc: Doc) => void; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; } @observer diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 73fe4fb5d..36233a7e6 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -34,7 +34,7 @@ interface ContentFittingDocumentViewProps { removeDocument?: (document: Doc) => boolean; active: (outsideReaction: boolean) => boolean; whenActiveChanged: (isActive: boolean) => void; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; dontRegisterView?: boolean; } diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx index 156b16ec8..a0b5cd8ec 100644 --- a/src/client/views/nodes/DocuLinkBox.tsx +++ b/src/client/views/nodes/DocuLinkBox.tsx @@ -61,7 +61,7 @@ export class DocuLinkBox extends DocComponent(Doc onClick = (e: React.MouseEvent) => { if (!this.props.Document.onClick) { if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button !== 2 && !e.ctrlKey && this.props.Document.isButton)) { - DocumentManager.Instance.FollowLink(this.props.Document, this.props.ContainingCollectionDoc as Doc, document => this.props.addDocTab(document, undefined, "inTab"), false); + DocumentManager.Instance.FollowLink(this.props.Document, this.props.ContainingCollectionDoc as Doc, document => this.props.addDocTab(document, "inTab"), false); } e.stopPropagation(); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 11a33b70a..c0f603171 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -82,7 +82,7 @@ export class DocumentContentsView extends React.Component boolean; whenActiveChanged: (isActive: boolean) => void; bringToFront: (doc: Doc, sendToBack?: boolean) => void; - addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean; + addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean; pinToPres: (document: Doc) => void; zoomToScale: (scale: number) => void; backgroundHalo?: () => boolean; @@ -152,9 +152,9 @@ export class DocumentView extends DocComponent(Docu // RadialMenu.Instance.openMenu(); - // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"), icon: "layer-group", selected: -1 }); // RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 }); - // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "folder", selected: -1 }); // RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 }); // RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15); @@ -253,7 +253,7 @@ export class DocumentView extends DocComponent(Docu if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { fullScreenAlias.layoutKey = "layout_fullScreen"; } - UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, undefined, "inTab"), "double tap"); + UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap"); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else if (this.onClickHandler && this.onClickHandler.script) { @@ -277,7 +277,7 @@ export class DocumentView extends DocComponent(Docu if (linkDocs.length) { DocumentManager.Instance.FollowLink(undefined, this.props.Document, // open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards - (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)), + (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, maxLocation)), ctrlKey, altKey, this.props.ContainingCollectionDoc); } } @@ -644,12 +644,12 @@ export class DocumentView extends DocComponent(Docu const open = ContextMenu.Instance.findByDescription("Open..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" }); - openItems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab", this.props.LibraryPath), icon: "folder" }); - openItems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight", this.props.LibraryPath), icon: "caret-square-right" }); - openItems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" }); - openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" }); - openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" }); - templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, undefined, "onRight"), icon: "eye" }); + openItems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, "inTab", this.props.LibraryPath), icon: "folder" }); + openItems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, "onRight", this.props.LibraryPath), icon: "caret-square-right" }); + openItems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" }); + openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); + openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); + templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" }); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 00f00dd52..f5c85e143 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -29,7 +29,7 @@ export interface FieldViewProps { select: (isCtrlPressed: boolean) => void; renderDepth: number; addDocument?: (document: Doc) => boolean; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; removeDocument?: (document: Doc) => boolean; moveDocument?: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index a191ac4f4..d4da21239 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -36,7 +36,7 @@ export class FontIconBox extends DocComponent( showTemplate = (): void => { const dragFactory = Cast(this.props.Document.dragFactory, Doc, null); - dragFactory && this.props.addDocTab(dragFactory, undefined, "onRight"); + dragFactory && this.props.addDocTab(dragFactory, "onRight"); } specificContextMenu = (): void => { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index fd288f720..842ccdd7b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -916,7 +916,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & // if (linkClicked) { // DocServer.GetRefField(linkClicked).then(async linkDoc => { // (linkDoc instanceof Doc) && - // DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false); + // DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, location ? location : "inTab"), false); // }); // } // } else { diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx index fda3e3285..1174110e7 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/FormattedTextBoxComment.tsx @@ -84,9 +84,9 @@ export class FormattedTextBoxComment { const textBox = FormattedTextBoxComment.textBox; if (FormattedTextBoxComment.linkDoc && !keep && textBox) { DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, - (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight")); + (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : "onRight")); } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { - textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), undefined, "onRight"); + textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), "onRight"); } keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation( FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index e6b512adf..93bda6d02 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -22,7 +22,7 @@ export interface KeyValuePairProps { keyWidth: number; PanelHeight: () => number; PanelWidth: () => number; - addDocTab: (doc: Doc, data: Opt, where: string) => boolean; + addDocTab: (doc: Doc, where: string) => boolean; } @observer export class KeyValuePair extends React.Component { @@ -46,7 +46,7 @@ export class KeyValuePair extends React.Component { if (value instanceof Doc) { e.stopPropagation(); e.preventDefault(); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" }); + ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index d4a47c159..8d20bbe59 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -327,12 +327,12 @@ export class PresBox extends React.Component { if (toggle) { if (this.props.Document.inOverlay) { Doc.RemoveDocFromList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document); - CollectionDockingView.AddRightSplit(this.props.Document, this.props.DataDoc); + CollectionDockingView.AddRightSplit(this.props.Document); this.props.Document.inOverlay = false; } else { this.props.Document.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25; this.props.Document.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25; - this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close"); + this.props.addDocTab?.(this.props.Document, "close"); Doc.AddDocToList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document); } } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 6695e04c3..69c6f2617 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -90,7 +90,7 @@ export class VideoBox extends DocAnnotatableComponent, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; focus: (doc: Doc) => void; dataDoc: Doc; @@ -30,7 +30,7 @@ interface IRegionAnnotationProps { y: number; width: number; height: number; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; document: Doc; dataDoc: Doc; @@ -98,7 +98,7 @@ class RegionAnnotation extends React.Component { const annoGroup = await Cast(this.props.document.group, Doc); if (annoGroup) { DocumentManager.Instance.FollowLink(undefined, annoGroup, - (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"), + (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : "onRight"), false, false, undefined); e.stopPropagation(); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a9b8c6bbe..198aeb856 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -65,7 +65,7 @@ interface IViewerProps { loaded: (nw: number, nh: number, np: number) => void; active: (outsideReaction?: boolean) => boolean; isChildActive: (outsideReaction?: boolean) => boolean; - addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; + addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; addDocument?: (doc: Doc) => boolean; setPdfViewer: (view: PDFViewer) => void; diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 888707ee3..8d62c34c5 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -4,7 +4,7 @@ import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocation import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, DataSym } from "../../../new_fields/Doc"; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from "../../../new_fields/FieldSymbols"; import { createSchema, makeInterface } from '../../../new_fields/Schema'; @@ -173,6 +173,7 @@ export class PresElementBox extends DocExtendableComponent { col._panX = newPanX; col._panY = newPanY; } - CollectionDockingView.AddRightSplit(col, undefined); + CollectionDockingView.AddRightSplit(col); }; } render() { @@ -108,7 +108,7 @@ export class LinkContextMenu extends React.Component { unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc); - getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col, undefined); + getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col); render() { return ( @@ -272,7 +272,7 @@ export class SearchItem extends React.Component { @computed get contextButton() { - return CollectionDockingView.AddRightSplit(doc, data)} />; + return CollectionDockingView.AddRightSplit(doc)} />; } render() { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 43bbea623..1f2dd1c8f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -17,6 +17,7 @@ import { listSpec } from "./Schema"; import { ComputedField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; +import { DatasetAbout } from "../client/northstar/model/idea/idea"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -495,7 +496,8 @@ export namespace Doc { // if the childDoc is a template for a field, then this will return the expanded layout with its data doc. // otherwise, it just returns the childDoc export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt, childDoc: Doc) { - const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc; + const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; + const resolvedDataDoc = existingResolvedDataDoc || (containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { -- cgit v1.2.3-70-g09d2 From 05399b3916df7311d07e7c375f90261e9c8ead80 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 25 Feb 2020 00:57:37 -0500 Subject: added optional display templates for metadata field values --- src/client/documents/Documents.ts | 10 ++++--- src/client/util/RichTextSchema.tsx | 32 ++++++++++++++-------- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 4 +-- src/new_fields/Doc.ts | 19 +++++++++---- src/new_fields/RichTextField.ts | 4 +++ .../authentication/models/current_user_utils.ts | 18 ++++++++---- 8 files changed, 60 insertions(+), 31 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ff64489bb..ff152ec6c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -97,7 +97,10 @@ export interface DocumentOptions { isTemplateForField?: string; // the field key for which the containing document is a rendering template isTemplateDoc?: boolean; templates?: List; - backgroundColor?: string | ScriptField; + backgroundColor?: string | ScriptField; // background color for data doc + _backgroundColor?: string | ScriptField; // background color for each template layout doc ( overrides backgroundColor ) + color?: string; // foreground color data doc + _color?: string; // foreground color for each template layout doc (overrides color) ignoreClick?: boolean; lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed @@ -133,7 +136,6 @@ export interface DocumentOptions { sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script strokeWidth?: number; - color?: string; treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view treeViewHideTitle?: boolean; // whether to hide the title of a tree view treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. @@ -405,8 +407,8 @@ export namespace Docs { Scripting.addGlobal(Buxton); const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn", - "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", - "isButton", "isBackground", "removeDropProperties", "treeViewOpen"]; + "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor", + "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"]; /** * This function receives the relevant document prototype and uses diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index cfbae5dca..ae3f4e731 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -8,7 +8,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-s import { StepMap } from "prosemirror-transform"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, Field, HeightSym, WidthSym } from "../../new_fields/Doc"; +import { Doc, Field, HeightSym, WidthSym, DocListCast } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; import { ObjectField } from "../../new_fields/ObjectField"; import { ComputedField } from "../../new_fields/ScriptField"; @@ -850,17 +850,19 @@ export class DashDocView { export class DashFieldView { - _fieldWrapper: HTMLDivElement; - _labelSpan: HTMLSpanElement; - _fieldSpan: HTMLDivElement; + _fieldWrapper: HTMLDivElement; // container for label and value + _labelSpan: HTMLSpanElement; // field label + _fieldSpan: HTMLDivElement; // field value _reactionDisposer: IReactionDisposer | undefined; _textBoxDoc: Doc; @observable _dashDoc: Doc | undefined; _fieldKey: string; + _options: Doc[] = []; constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { this._fieldKey = node.attrs.fieldKey; this._textBoxDoc = tbox.props.Document; + this._options = DocListCast(tbox.props.Document[node.attrs.fieldKey + "_options"]); this._fieldWrapper = document.createElement("div"); this._fieldWrapper.style.width = node.attrs.width; this._fieldWrapper.style.height = node.attrs.height; @@ -877,11 +879,15 @@ export class DashFieldView { this._fieldSpan.addEventListener("input", this.onchanged); this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; - this._fieldSpan.onmousedown = function (e: any) { - console.log(e); - e.stopPropagation(); - }; + this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); }; + const self = this; + const setDashDoc = (doc: Doc) => { + self._dashDoc = doc; + if (this._dashDoc && self._options?.length && !this._dashDoc[node.attrs.fieldKey]) { + this._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title); + } + } this._fieldSpan.onkeydown = function (e: any) { e.stopPropagation(); if ((e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { @@ -902,10 +908,9 @@ export class DashFieldView { this._labelSpan.style.fontSize = "larger"; this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `; if (node.attrs.docid) { - const self = this; - DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && runInAction(() => self._dashDoc = dashDoc)); + DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && runInAction(() => setDashDoc(dashDoc))); } else { - this._dashDoc = tbox.props.DataDoc || tbox.dataDoc; + setDashDoc(tbox.props.DataDoc || tbox.dataDoc); } this._reactionDisposer?.(); this._reactionDisposer = reaction(() => this._dashDoc?.[node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true }); @@ -916,7 +921,10 @@ export class DashFieldView { } onchanged = () => { this._reactionDisposer?.(); - this._dashDoc![this._fieldKey] = this._fieldSpan.innerText; + + let newText = this._fieldSpan.innerText; + this._options?.forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); + this._dashDoc![this._fieldKey] = newText; this._reactionDisposer = reaction(() => this._dashDoc?.[this._fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)"); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 83dbb4263..1e38a8927 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -715,7 +715,7 @@ export class DockedFrameRenderer extends React.Component { TraceMobx(); if (!this._document) return (null); const document = this._document; - const resolvedDataDoc = !Doc.AreProtosEqual(this._document[DataSym], this._document) && this._document[DataSym];// document.layout instanceof Doc ? document : this._dataDoc; + const resolvedDataDoc = !Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined;// document.layout instanceof Doc ? document : this._dataDoc; return (Docu render() { if (!(this.props.Document instanceof Doc)) return (null); - const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor?.(this.Document); + const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.layoutDoc.borderRounding; const localScale = fullDegree; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index eac495082..5a664f31c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -192,10 +192,10 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); if (!curTemp || curText) { // if no template, or there's text, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), curText); - this.dataDoc[this.props.fieldKey + "-noTemplate"] = curTemp?.Text !== 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 } else { // if we've deleted all the text in a note driven by a template, then restore the template data this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(curTemp.Data))); - this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; + this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; // mark the data field as not being split from any template it might have } this._applyingChange = false; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 6142ebb36..10f4309be 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -17,7 +17,6 @@ import { listSpec } from "./Schema"; import { ComputedField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; -import { DocumentManager } from "../client/util/DocumentManager"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -612,15 +611,16 @@ export namespace Doc { templateField.isTemplateForField = metadataFieldKey; templateField.title = metadataFieldKey; + const templateFieldValue = templateField[metadataFieldKey]; // move any data that the template field had been rendering over to the template doc so that things will still be rendered // when the template field is adjusted to point to the new metadatafield key. // note 1: if the template field contained a list of documents, each of those documents will be converted to templates as well. // note 2: this will not overwrite any field that already exists on the template doc at the field key - if (!templateDoc?.[metadataFieldKey] && templateField.data instanceof ObjectField) { - Cast(templateField.data, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); - (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateField.data)); + if (!templateDoc?.[metadataFieldKey] && templateFieldValue instanceof ObjectField) { + Cast(templateFieldValue, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); + (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateFieldValue)); } - if (templateField.data instanceof RichTextField && (templateField.data.Text || templateField.data.Data.toString().includes("dashField"))) { + if (templateFieldValue instanceof RichTextField && (templateFieldValue.Text || templateFieldValue.Data.toString().includes("dashField"))) { templateField._textTemplate = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name }); } @@ -838,6 +838,15 @@ export namespace Doc { DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout)); return id; } + + export function enumeratedTextTemplate(doc: Doc, layoutString: string, dataKey: string, optionKey: string, modes: Doc[]) { + doc[dataKey] = RichTextField.DashField(optionKey); + doc.layout = layoutString; + const optionsField = `${optionKey}_options`; + doc[optionsField] = new List(modes); + doc.backgroundColor = ComputedField.MakeFunction(`this['${optionsField}'].find(doc => doc.title === this.expandedTemplate.${optionKey})?._backgroundColor || "white"`); + doc.color = ComputedField.MakeFunction(`this['${optionsField}'].find(doc => doc.title === this.expandedTemplate.${optionKey}).color || "black"`); + } } Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index a0f21f45e..712f3e76b 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -30,4 +30,8 @@ export class RichTextField extends ObjectField { return this.Text; } + public static DashField(fieldKey:string) { + return new RichTextField(`{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"${fieldKey}","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}`, ""); + } + } \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 8fe2257fc..aaf3a3eb6 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -37,13 +37,19 @@ export class CurrentUserUtils { static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) { const noteTemplates = [ - Docs.Create.TextDocument("", { title: "Note", backgroundColor: "yellow", isTemplateDoc: true }), - Docs.Create.TextDocument("", { title: "Idea", backgroundColor: "pink", isTemplateDoc: true }), - Docs.Create.TextDocument("", { title: "Topic", backgroundColor: "lightBlue", isTemplateDoc: true }), - Docs.Create.TextDocument("", { title: "Person", backgroundColor: "lightGreen", isTemplateDoc: true }), - Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange", isTemplateDoc: true }) + Docs.Create.TextDocument("", { title: "Note", backgroundColor: "yellow" }), + Docs.Create.TextDocument("", { title: "Idea", backgroundColor: "pink" }), + Docs.Create.TextDocument("", { title: "Topic", backgroundColor: "lightBlue" }), + Docs.Create.TextDocument("", { title: "Person", backgroundColor: "lightGreen" }), + Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange" }) ]; - doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates, { title: "Note Types", _height: 75 })); + const modes = [ + Docs.Create.TextDocument("", { title: "todo", _backgroundColor: "blue", color: "white" }), + Docs.Create.TextDocument("", { title: "in progress", _backgroundColor: "yellow", color: "black" }), + Docs.Create.TextDocument("", { title: "completed", _backgroundColor: "green", color: "white" }) + ] + Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "Todo", "taskStatus", modes); + doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt) ? nt : nt), { title: "Note Types", _height: 75 })); } // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools -- cgit v1.2.3-70-g09d2 From 9399d2a44261ffce3f33cf1ea2dac032a8d3fdc8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 25 Feb 2020 02:53:23 -0500 Subject: improved text templates to work better with captions --- src/client/documents/Documents.ts | 3 +-- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 23 ++++++++++++++++++++-- src/client/views/nodes/FormattedTextBox.tsx | 12 +++++------ src/new_fields/Doc.ts | 15 +++++++++----- .../authentication/models/current_user_utils.ts | 4 ++-- 6 files changed, 41 insertions(+), 18 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ff152ec6c..6d5fd5677 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -77,7 +77,6 @@ export interface DocumentOptions { _gridGap?: number; // gap between items in masonry view _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts - _textTemplate?: RichTextField; // template used by a formattedTextBox to create a text box to render _itemIndex?: number; // which item index the carousel viewer is showing _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts x?: number; @@ -911,7 +910,7 @@ export namespace DocUtils { description: "Add Note ...", subitems: DocListCast((Doc.UserDoc().noteTypes as Doc).data).map((note, i) => ({ description: ":" + StrCast(note.title), - event: (args: { x: number, y: number }) => docTextAdder(Docs.Create.TextDocument("", { _width: 200, x, y, _autoHeight: true, layout: note, title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1) })), + event: (args: { x: number, y: number }) => docTextAdder(Docs.Create.TextDocument("", { _width: 200, x, y, _autoHeight: note._autoHeight !== false, layout: note, title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1) })), icon: "eye" })) as ContextMenuProps[], icon: "eye" diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index ae3f4e731..626d9d75d 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -807,7 +807,7 @@ export class DashDocView { if (finalLayout !== dashDoc && finalKey) { const finalLayoutField = finalLayout[finalKey]; if (finalLayoutField instanceof ObjectField) { - finalLayout._textTemplate = ComputedField.MakeFunction(`copyField(this.${finalKey})`, { this: Doc.name }); + finalLayout[finalKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${finalKey})`, { this: Doc.name }); } } this._reactionDisposer?.(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index aec18ecbb..3660c327a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -813,6 +813,25 @@ export class DocumentView extends DocComponent(Docu return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true; } + // bcz: ARGH! these two are the same as in DocumentContentsView (without the _). They should be reconciled to be the same functions... + get _dataDoc() { + if (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string") { + // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), + // then we render the layout document as a template and use this document as the data context for the template layout. + const proto = Doc.GetProto(this.props.Document); + return proto instanceof Promise ? undefined : proto; + } + return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc; + } + get _layoutDoc() { + if (this.props.LayoutDoc || (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string")) { + // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), + // then we render the layout document as a template and use this document as the data context for the template layout. + return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document); + } + return Doc.Layout(this.props.Document); + } + @computed get innards() { TraceMobx(); const showTitle = StrCast(this.layoutDoc._showTitle); @@ -825,8 +844,8 @@ export class DocumentView extends DocComponent(Docu
); const captionView = (!showCaption ? (null) :
- diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5a664f31c..a320cff75 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -186,13 +186,13 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & 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 * 5000 - 1000))); const curText = state.doc.textBetween(0, state.doc.content.size, "\n\n"); - const curTemp = Cast(this.props.Document._textTemplate, RichTextField); + const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField); if (!this._applyingChange) { this._applyingChange = true; this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); if (!curTemp || curText) { // if no template, or there's text, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), 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 + this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited } else { // if we've deleted all the text in a note driven by a template, then restore the template data this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(curTemp.Data))); this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; // mark the data field as not being split from any template it might have @@ -504,10 +504,10 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this._reactionDisposer = reaction( () => { - if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document._textTemplate) { + if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document[this.props.fieldKey + "-textTemplate"]) { return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data; } - return Cast(this.props.Document._textTemplate, RichTextField, null)?.Data; + return Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField, null)?.Data; }, incomingValue => { if (incomingValue !== undefined && this._editorView && !this._applyingChange) { @@ -752,8 +752,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & private setupEditor(config: any, fieldKey: string) { const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null); - const useTemplate = !curText?.Text && this.props.Document._textTemplate; - const rtfField = Cast((useTemplate && this.props.Document._textTemplate) || this.dataDoc[fieldKey], RichTextField); + 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); if (this.ProseRef) { const self = this; this._editorView?.destroy(); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 10f4309be..8e28a1e00 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -47,7 +47,7 @@ export namespace Field { } else if (field instanceof RefField) { return field[ToString](); } - return "(null)"; + return ""; } export function IsField(field: any): field is Field; export function IsField(field: any, includeUndefined: true): field is Field | undefined; @@ -611,7 +611,8 @@ export namespace Doc { templateField.isTemplateForField = metadataFieldKey; templateField.title = metadataFieldKey; - const templateFieldValue = templateField[metadataFieldKey]; + const templateFieldValue = templateField[metadataFieldKey] || templateField.data; + const templateCaptionValue = templateField.caption; // move any data that the template field had been rendering over to the template doc so that things will still be rendered // when the template field is adjusted to point to the new metadatafield key. // note 1: if the template field contained a list of documents, each of those documents will be converted to templates as well. @@ -620,8 +621,11 @@ export namespace Doc { Cast(templateFieldValue, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateFieldValue)); } + if (templateCaptionValue instanceof RichTextField && (templateCaptionValue.Text || templateCaptionValue.Data.toString().includes("dashField"))) { + templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`, { this: Doc.name }); + } if (templateFieldValue instanceof RichTextField && (templateFieldValue.Text || templateFieldValue.Data.toString().includes("dashField"))) { - templateField._textTemplate = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name }); + templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name }); } // get the layout string that the template uses to specify its layout @@ -839,8 +843,9 @@ export namespace Doc { return id; } - export function enumeratedTextTemplate(doc: Doc, layoutString: string, dataKey: string, optionKey: string, modes: Doc[]) { - doc[dataKey] = RichTextField.DashField(optionKey); + export function enumeratedTextTemplate(doc: Doc, layoutString: string, captionKey: string, optionKey: string, modes: Doc[]) { + doc.caption = RichTextField.DashField(optionKey); + doc._showCaption = captionKey; doc.layout = layoutString; const optionsField = `${optionKey}_options`; doc[optionsField] = new List(modes); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index aaf3a3eb6..36259f513 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -41,14 +41,14 @@ export class CurrentUserUtils { Docs.Create.TextDocument("", { title: "Idea", backgroundColor: "pink" }), Docs.Create.TextDocument("", { title: "Topic", backgroundColor: "lightBlue" }), Docs.Create.TextDocument("", { title: "Person", backgroundColor: "lightGreen" }), - Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange" }) + Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption" }) ]; const modes = [ Docs.Create.TextDocument("", { title: "todo", _backgroundColor: "blue", color: "white" }), Docs.Create.TextDocument("", { title: "in progress", _backgroundColor: "yellow", color: "black" }), Docs.Create.TextDocument("", { title: "completed", _backgroundColor: "green", color: "white" }) ] - Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "Todo", "taskStatus", modes); + Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "caption", "taskStatus", modes); doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt) ? nt : nt), { title: "Note Types", _height: 75 })); } -- cgit v1.2.3-70-g09d2 From c5c8c99151de576548dab215b82d44132b06f9a4 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 25 Feb 2020 12:45:33 -0500 Subject: added inheritable computations to template fields --- src/client/util/RichTextSchema.tsx | 27 ++++++++++++++++----------- src/new_fields/ScriptField.ts | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 626d9d75d..cc6b035d7 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -21,6 +21,7 @@ import { DocumentManager } from "./DocumentManager"; import ParagraphNodeSpec from "./ParagraphNodeSpec"; import { Transform } from "./Transform"; import React = require("react"); +import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSchemaCells"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -869,6 +870,16 @@ export class DashFieldView { this._fieldWrapper.style.position = "relative"; this._fieldWrapper.style.display = "inline-block"; + const onchanged = (e: any) => { + this._reactionDisposer?.(); + let newText = this._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : this._fieldSpan.innerText; + this._options?.forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); + this._dashDoc![this._fieldKey] = newText; + if (newText.startsWith(":=") && this._dashDoc && e.data === null && !e.inputType.includes("delete")) { + Doc.Layout(tbox.props.Document)[this._fieldKey] = ComputedField.MakeFunction(this._fieldSpan.innerText.substring(2)); + } + } + this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); this._fieldSpan.contentEditable = "true"; @@ -876,7 +887,7 @@ export class DashFieldView { this._fieldSpan.style.display = "inline-block"; this._fieldSpan.style.minWidth = "50px"; this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; - this._fieldSpan.addEventListener("input", this.onchanged); + this._fieldSpan.addEventListener("input", onchanged); this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); }; @@ -913,21 +924,15 @@ export class DashFieldView { setDashDoc(tbox.props.DataDoc || tbox.dataDoc); } this._reactionDisposer?.(); - this._reactionDisposer = reaction(() => this._dashDoc?.[node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true }); + this._reactionDisposer = reaction(() => { + const dashVal = this._dashDoc?.[node.attrs.fieldKey]; + return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[this._fieldKey] : dashVal; + }, fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true }); this._fieldWrapper.appendChild(this._labelSpan); this._fieldWrapper.appendChild(this._fieldSpan); (this as any).dom = this._fieldWrapper; } - onchanged = () => { - this._reactionDisposer?.(); - - let newText = this._fieldSpan.innerText; - this._options?.forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); - this._dashDoc![this._fieldKey] = newText; - this._reactionDisposer = reaction(() => this._dashDoc?.[this._fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)"); - - } destroy() { this._reactionDisposer?.(); } diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index 4c78ea3aa..131e1f339 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -130,7 +130,7 @@ export class ScriptField extends ObjectField { export class ComputedField extends ScriptField { _lastComputedResult: any; //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc - value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, _last_: this._lastComputedResult }, console.log).result); + value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ source: doc.expandedTemplate || doc, this: doc, _last_: this._lastComputedResult }, console.log).result); public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; -- cgit v1.2.3-70-g09d2 From 3c48667061fb417e3a7657a1951659d25b453a9f Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 27 Feb 2020 15:10:14 -0500 Subject: streamlined setting enumerations for fields in text boxes. --- src/client/documents/Documents.ts | 8 ++-- src/client/util/RichTextSchema.tsx | 47 +++++++++++++++------- .../views/collections/CollectionTimeView.scss | 4 +- src/new_fields/Doc.ts | 32 +++++++++++---- .../authentication/models/current_user_utils.ts | 15 +++---- 5 files changed, 73 insertions(+), 33 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6d5fd5677..a0b8a6382 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -622,12 +622,12 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List(schemaColumns), ...options, _viewType: CollectionViewType.Schema }); } - export function TreeDocument(documents: Array, options: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Tree }); + export function TreeDocument(documents: Array, options: DocumentOptions, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Tree }, id); } - export function StackingDocument(documents: Array, options: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Stacking }); + export function StackingDocument(documents: Array, options: DocumentOptions, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Stacking }, id); } export function MulticolumnDocument(documents: Array, options: DocumentOptions) { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index cc6b035d7..a56aac9b1 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -22,6 +22,10 @@ import ParagraphNodeSpec from "./ParagraphNodeSpec"; import { Transform } from "./Transform"; import React = require("react"); import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSchemaCells"; +import { ContextMenu } from "../views/ContextMenu"; +import { ContextMenuProps } from "../views/ContextMenuItem"; +import { Docs } from "../documents/Documents"; +import { CollectionView } from "../views/collections/CollectionView"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -863,23 +867,13 @@ export class DashFieldView { constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { this._fieldKey = node.attrs.fieldKey; this._textBoxDoc = tbox.props.Document; - this._options = DocListCast(tbox.props.Document[node.attrs.fieldKey + "_options"]); this._fieldWrapper = document.createElement("div"); this._fieldWrapper.style.width = node.attrs.width; this._fieldWrapper.style.height = node.attrs.height; this._fieldWrapper.style.position = "relative"; this._fieldWrapper.style.display = "inline-block"; - const onchanged = (e: any) => { - this._reactionDisposer?.(); - let newText = this._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : this._fieldSpan.innerText; - this._options?.forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); - this._dashDoc![this._fieldKey] = newText; - if (newText.startsWith(":=") && this._dashDoc && e.data === null && !e.inputType.includes("delete")) { - Doc.Layout(tbox.props.Document)[this._fieldKey] = ComputedField.MakeFunction(this._fieldSpan.innerText.substring(2)); - } - } - + const self = this; this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); this._fieldSpan.contentEditable = "true"; @@ -887,12 +881,18 @@ export class DashFieldView { this._fieldSpan.style.display = "inline-block"; this._fieldSpan.style.minWidth = "50px"; this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; - this._fieldSpan.addEventListener("input", onchanged); this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); }; + this._fieldSpan.oncontextmenu = function (e: any) { + ContextMenu.Instance.addItem({ + description: "Show Enumeration Templates", event: () => { + e.stopPropagation(); + DocServer.GetRefField(node.attrs.fieldKey).then(collview => collview instanceof Doc && tbox.props.addDocTab(collview, "onRight")); + }, icon: "expand-arrows-alt" + }); + }; - const self = this; const setDashDoc = (doc: Doc) => { self._dashDoc = doc; if (this._dashDoc && self._options?.length && !this._dashDoc[node.attrs.fieldKey]) { @@ -910,6 +910,25 @@ export class DashFieldView { } e.preventDefault(); } + if (e.key === "Enter" && e.ctrlKey) { + Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); + e.preventDefault(); + } else if (e.key === "Enter") { + e.preventDefault(); + let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; + // look for a document whose id === the fieldKey being displayed. If there's a match, then that document + // holds the different enumerated values for the field in the titles of its collected documents. + // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. + + // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key + DocServer.GetRefField(node.attrs.fieldKey).then(options => { + (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); + self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText; + if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) { + Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); + } + }); + } }; this._labelSpan = document.createElement("span"); @@ -924,7 +943,7 @@ export class DashFieldView { setDashDoc(tbox.props.DataDoc || tbox.dataDoc); } this._reactionDisposer?.(); - this._reactionDisposer = reaction(() => { + this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes const dashVal = this._dashDoc?.[node.attrs.fieldKey]; return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[this._fieldKey] : dashVal; }, fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true }); diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss index 6ea5e6908..865fc3cd2 100644 --- a/src/client/views/collections/CollectionTimeView.scss +++ b/src/client/views/collections/CollectionTimeView.scss @@ -10,7 +10,6 @@ .collectionTimeView-backBtn { background: green; display: inline; - margin-right: 20px; } .collectionFreeform-customText { @@ -68,6 +67,9 @@ padding: 5px; border: 1px solid black; display:none; + span { + margin-left : 10px; + } } .collectionTimeView-treeView { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 8e28a1e00..8ea347ec3 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -17,6 +17,7 @@ import { listSpec } from "./Schema"; import { ComputedField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; +import { Docs } from "../client/documents/Documents"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -571,7 +572,7 @@ export namespace Doc { export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), "layout", templateDoc.title + "(..." + _applyCount++ + ")"); - applied && (Doc.GetProto(applied).layout = applied.layout); + applied && (Doc.GetProto(applied).type = templateDoc.type); return applied; } return undefined; @@ -843,14 +844,31 @@ export namespace Doc { return id; } - export function enumeratedTextTemplate(doc: Doc, layoutString: string, captionKey: string, optionKey: string, modes: Doc[]) { - doc.caption = RichTextField.DashField(optionKey); + // setup a document to use enumerated values for a specified field name: + // doc: text document + // layoutString: species which text field receives the document's main text (e.g., FormattedTextBox.LayoutString("Todo") ) + // enumeratedFieldKey : specifies which enumerated field of the document is displayed in the caption (e.g., taskStatus) + // captionKey: specifies which field holds the caption template (e.g., caption) -- ideally this wouldn't be needed but would be derived from the layoutString's target field key + // + export function enumeratedTextTemplate(doc: Doc, layoutString: string, enumeratedFieldKey: string, enumeratedDocs: Doc[], captionKey: string = "caption") { + doc.caption = RichTextField.DashField(enumeratedFieldKey); doc._showCaption = captionKey; doc.layout = layoutString; - const optionsField = `${optionKey}_options`; - doc[optionsField] = new List(modes); - doc.backgroundColor = ComputedField.MakeFunction(`this['${optionsField}'].find(doc => doc.title === this.expandedTemplate.${optionKey})?._backgroundColor || "white"`); - doc.color = ComputedField.MakeFunction(`this['${optionsField}'].find(doc => doc.title === this.expandedTemplate.${optionKey}).color || "black"`); + + Doc.addEnumerationToTextField(doc, enumeratedFieldKey, enumeratedDocs); + } + + export function addEnumerationToTextField(doc: Doc, enumeratedFieldKey: string, enumeratedDocs: Doc[]) { + DocServer.GetRefField(enumeratedFieldKey).then(optionsCollection => { + if (!(optionsCollection instanceof Doc)) { + optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey); + Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); + } + const options = optionsCollection as Doc; + doc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }); + doc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }); + enumeratedDocs.map(enumeratedDoc => !DocListCast(options.data).find(d => d.title === enumeratedDoc.title) && Doc.AddDocToList(options, "data", enumeratedDoc)); + }); } } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 36259f513..ea19d9da8 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -36,6 +36,11 @@ export class CurrentUserUtils { @observable public static GuestMobile: Doc | undefined; static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) { + const taskStatusValues = [ + Docs.Create.TextDocument("todo", { title: "todo", _backgroundColor: "blue", color: "white" }), + Docs.Create.TextDocument("in progress", { title: "in progress", _backgroundColor: "yellow", color: "black" }), + Docs.Create.TextDocument("completed", { title: "completed", _backgroundColor: "green", color: "white" }) + ]; const noteTemplates = [ Docs.Create.TextDocument("", { title: "Note", backgroundColor: "yellow" }), Docs.Create.TextDocument("", { title: "Idea", backgroundColor: "pink" }), @@ -43,12 +48,8 @@ export class CurrentUserUtils { Docs.Create.TextDocument("", { title: "Person", backgroundColor: "lightGreen" }), Docs.Create.TextDocument("", { title: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption" }) ]; - const modes = [ - Docs.Create.TextDocument("", { title: "todo", _backgroundColor: "blue", color: "white" }), - Docs.Create.TextDocument("", { title: "in progress", _backgroundColor: "yellow", color: "black" }), - Docs.Create.TextDocument("", { title: "completed", _backgroundColor: "green", color: "white" }) - ] - Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "caption", "taskStatus", modes); + doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); + Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "taskStatus", taskStatusValues); doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt) ? nt : nt), { title: "Note Types", _height: 75 })); } @@ -196,7 +197,7 @@ export class CurrentUserUtils { return Docs.Create.ButtonDocument({ _width: 50, _height: 25, title: "Library", fontSize: 10, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc.recentlyClosed as Doc], { + sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], { title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0", }), targetContainer: sidebarContainer, -- cgit v1.2.3-70-g09d2 From 5c139f0001cd10e5699a716c1e64d2c2c0b2d800 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 28 Feb 2020 12:17:03 -0500 Subject: allowing different text templates to be the default. fixing transparency. removing audio by default from notes. --- src/client/documents/Documents.ts | 5 +++- src/client/util/Import & Export/ImageUtils.ts | 2 +- src/client/util/RichTextSchema.tsx | 8 ++--- src/client/views/InkingControl.tsx | 3 +- src/client/views/TemplateMenu.tsx | 5 ++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +-- .../collections/collectionFreeForm/MarqueeView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 6 ++-- src/client/views/nodes/FormattedTextBox.scss | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 34 +++++++++++++--------- src/client/views/nodes/ImageBox.tsx | 19 ++++++------ src/new_fields/documentSchemas.ts | 13 +++++---- 12 files changed, 63 insertions(+), 41 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a0b8a6382..aab44f668 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -77,6 +77,8 @@ export interface DocumentOptions { _gridGap?: number; // gap between items in masonry view _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts + _xPadding?: number; + _yPadding?: number; _itemIndex?: number; // which item index the carousel viewer is showing _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts x?: number; @@ -174,7 +176,7 @@ export namespace Docs { const TemplateMap: TemplateMap = new Map([ [DocumentType.TEXT, { layout: { view: FormattedTextBox, dataField: data }, - options: { _height: 150 } + options: { _height: 150, _xMargin: 10, _yMargin: 10 } }], [DocumentType.HIST, { layout: { view: HistogramBox, dataField: data }, @@ -407,6 +409,7 @@ export namespace Docs { const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor", + "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"]; /** diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index ff909cc6b..ab8c73d15 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -24,7 +24,7 @@ export namespace ImageUtils { const proto = Doc.GetProto(document); proto["data-nativeWidth"] = nativeWidth; proto["data-nativeHeight"] = nativeHeight; - proto.contentSize = contentSize; + proto.contentSize = contentSize ? contentSize : undefined; return data !== undefined; }; diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a56aac9b1..4a80a1af8 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -910,11 +910,11 @@ export class DashFieldView { } e.preventDefault(); } - if (e.key === "Enter" && e.ctrlKey) { - Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); - e.preventDefault(); - } else if (e.key === "Enter") { + if (e.key === "Enter") { e.preventDefault(); + if (e.ctrlKey) { + Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); + } let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 374c2df27..5cd3c265d 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -29,8 +29,7 @@ export class InkingControl { if (number < 0) { number = 0xFFFFFFFF + number + 1; } - - return number.toString(16).toUpperCase(); + return (number < 16 ? "0" : "") + number.toString(16).toUpperCase(); } @undoBatch diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 595c3817e..5029b4074 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -61,6 +61,10 @@ export class TemplateMenu extends React.Component { DocumentView.FloatDoc(topDocView, ex, ey); } + toggleAudio = (e: React.ChangeEvent): void => { + this.props.docViews.map(dv => dv.props.Document._showAudio = e.target.checked); + } + @undoBatch @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { @@ -102,6 +106,7 @@ export class TemplateMenu extends React.Component { const templateMenu: Array = []; this.props.templates.forEach((checked, template) => templateMenu.push()); + templateMenu.push(); templateMenu.push(); templateMenu.push(); this._addedKeys && Array.from(this._addedKeys).map(layout => diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4458c7dcf..ca8d5e18b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -51,8 +51,8 @@ export const panZoomSchema = createSchema({ arrangeInit: ScriptField, useClusters: "boolean", fitToBox: "boolean", - xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set panTransformType: "string", scrollHeight: "number", fitX: "number", diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b1cca027d..b8e9acf85 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -18,6 +18,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); import { CollectionView } from "../CollectionView"; +import { FormattedTextBox } from "../../nodes/FormattedTextBox"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -104,7 +105,7 @@ export class MarqueeView extends React.Component 48 && e.keyCode <= 57) { const notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data); const text = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 06ca9b5f4..7683ad269 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -909,17 +909,19 @@ export class DocumentView extends DocComponent(Docu render() { if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); + const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.layoutDoc.borderRounding; const localScale = fullDegree; + console.log("Background = " + this.props.Document.title + " " + finalColor); const highlightColors = Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] : ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"]; const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way - return
Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)} style={{ @@ -931,7 +933,7 @@ export class DocumentView extends DocComponent(Docu outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, - background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor, + background: finalColor, width: "100%", height: "100%", opacity: this.Document.opacity diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index c203ca0c3..db2bb751f 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -95,8 +95,8 @@ .formattedTextBox-inner-rounded, .formattedTextBox-inner { - padding: 10px 10px; height: 100%; + white-space: pre-wrap; } // .menuicon { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a320cff75..3567dbbd5 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -375,12 +375,15 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & toggleSidebar = () => this._sidebarMovement < 5 && (this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"); + public static DefaultLayout: Doc | string | undefined; specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; + this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => FormattedTextBox.DefaultLayout = this.props.Document.proto as Doc, icon: "eye" }); + funcs.push({ description: "Reset Default Layout", event: () => FormattedTextBox.DefaultLayout = undefined, icon: "eye" }); !this.props.Document.expandedTemplate && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = true; Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); }, icon: "eye" }); - funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar; }, icon: "expand-arrows-alt" }); - funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Menubar", event: () => { e.stopPropagation(); this.toggleMenubar(); }, 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: "Record Bullet", event: () => this.recordBullet(), icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { @@ -1125,7 +1128,11 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & onPointerLeave={action(() => this._entered = false)} >
-
+
{!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
this.toggleSidebar()} /> : @@ -1152,15 +1159,16 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.toggleSidebar()} />
} -
{ - this._recording ? this.stopDictation(true) : this.recordDictation(); - setTimeout(() => this._editorView!.focus(), 500); - e.stopPropagation(); - }} > - -
+ {!this.props.Document._showAudio ? (null) : +
{ + this._recording ? this.stopDictation(true) : this.recordDictation(); + setTimeout(() => this._editorView!.focus(), 500); + e.stopPropagation(); + }} > + +
}
); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 99000a0a9..c46191270 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -407,15 +407,16 @@ export class ImageBox extends DocAnnotatableComponent
}
-
- -
+ {!this.props.Document._showAudio ? (null) : +
+ +
} {this.considerDownloadIcon} {this.considerGooglePhotosLink()} diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index f3726cb5a..7006163e0 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -15,9 +15,14 @@ export const documentSchema = createSchema({ _nativeHeight: "number", // " _width: "number", // width of document in its container's coordinate system _height: "number", // " - _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document - _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document - _showTitleHover: "string", // the showTitle should be shown only on hover + _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitToBox is set + _xMargin: "number", // margin added on left/right of most documents to add separation from their container + _yMargin: "number", // margin added on top/bottom of most documents to add separation from their container + _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document + _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document + _showTitleHover: "string", // the showTitle should be shown only on hover + _showAudio: "boolean", // whether to show the audio record icon on documents _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews _pivotField: "string", // specifies which field should be used as the timeline/pivot axis @@ -53,8 +58,6 @@ export const documentSchema = createSchema({ strokeWidth: "number", fontSize: "string", fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view - xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set letterSpacing: "string", textTransform: "string" }); -- cgit v1.2.3-70-g09d2 From cad4ca15ec12808915b7aa901859e349144d8a50 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 2 Mar 2020 14:42:23 -0500 Subject: fixed pdfs to sort of support region clippings. --- package-lock.json | 79 +++++++++++++--------- src/client/documents/Documents.ts | 3 +- src/client/util/DocumentManager.ts | 2 +- src/client/util/DragManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 17 ++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 7 +- src/client/views/nodes/PDFBox.tsx | 18 +++-- src/client/views/pdf/PDFViewer.tsx | 50 ++++++++------ 9 files changed, 103 insertions(+), 79 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/package-lock.json b/package-lock.json index 375b41a01..827fb05b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2226,7 +2226,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -2846,7 +2846,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -2880,7 +2880,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -3051,7 +3051,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { "camelcase": "^2.0.0", @@ -3844,7 +3844,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -3856,7 +3856,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -4398,7 +4398,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", @@ -5697,7 +5697,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5734,7 +5735,8 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -5743,7 +5745,8 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5846,7 +5849,8 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5856,6 +5860,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5881,6 +5886,7 @@ "minipass": { "version": "2.9.0", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5897,6 +5903,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5988,6 +5995,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -6063,7 +6071,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6093,6 +6102,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6110,6 +6120,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6148,11 +6159,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.1.1", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -7370,7 +7383,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -7425,7 +7438,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -8156,7 +8169,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -8493,7 +8506,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -8525,7 +8538,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { "camelcase-keys": "^2.0.0", @@ -8700,7 +8713,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -9038,7 +9051,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "nice-try": { @@ -9121,7 +9134,7 @@ }, "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, "tar": { @@ -12772,7 +12785,7 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { @@ -12785,7 +12798,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { @@ -13025,7 +13038,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -14451,7 +14464,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -14893,7 +14906,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -15173,7 +15186,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -16035,7 +16048,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -16065,7 +16078,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -16081,7 +16094,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-indent": { @@ -16898,7 +16911,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -18370,7 +18383,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d0385918c..abef72f21 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -75,6 +75,7 @@ export interface DocumentOptions { _showTitleHover?: string; // _showTitle?: string; // which field to display in the title area. leave empty to have no title _showCaption?: string; // which field to display in the caption area. leave empty to have no caption + _scrollTop?: number; // scroll location for pdfs _chromeStatus?: string; _viewType?: number; _gridGap?: number; // gap between items in masonry view @@ -420,7 +421,7 @@ export namespace Docs { const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor", - "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", + "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", "_scrollTop", "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"]; /** diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index c639f07f5..4f721cb77 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -195,7 +195,7 @@ export class DocumentManager { const linkFollowDocContexts = first.length ? [await first[0].anchor2Context as Doc, await first[0].anchor1Context as Doc] : second.length ? [await second[0].anchor1Context as Doc, await second[0].anchor2Context as Doc] : [undefined, undefined]; const linkFollowTimecodes = first.length ? [NumCast(first[0].anchor2Timecode), NumCast(first[0].anchor1Timecode)] : second.length ? [NumCast(second[0].anchor1Timecode), NumCast(second[0].anchor2Timecode)] : [undefined, undefined]; if (linkFollowDocs && linkDoc) { - const maxLocation = StrCast(linkFollowDocs[0].maximizeLocation, "inTab"); + const maxLocation = StrCast(linkDoc.maximizeLocation, "inTab"); const targetContext = !Doc.AreProtosEqual(linkFollowDocContexts[reverse ? 1 : 0], currentContext) ? linkFollowDocContexts[reverse ? 1 : 0] : undefined; const target = linkFollowDocs[reverse ? 1 : 0]; target.currentTimecode !== undefined && (target.currentTimecode = linkFollowTimecodes[reverse ? 1 : 0]); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 1cfebf414..42ae704dd 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -387,8 +387,8 @@ export namespace DragManager { hideDragShowOriginalElements(); dispatchDrag(eles, e, dragData, options, finishDrag); SelectionManager.SetIsDragging(false); - options?.dragComplete?.(new DragCompleteEvent(false, dragData)); endDrag(); + options?.dragComplete?.(new DragCompleteEvent(false, dragData)); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 4a80a1af8..b2ee7320a 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -796,15 +796,8 @@ export class DashDocView { } doRender(dashDoc: Doc, removeDoc: any, node: any, view: any, getPos: any) { this._dashDoc = dashDoc; - 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); + const finalLayout = this._textBox.props.Document instanceof Doc && (Doc.expandTemplateLayout(dashDoc, !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.props.Document) ? this._textBox.dataDoc : undefined)); if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc, node, view, getPos), 0); else { const layoutKey = StrCast(finalLayout.layoutKey); @@ -846,9 +839,17 @@ export class DashDocView { ContainingCollectionDoc={undefined} ContentScaling={this.contentScaling} />, this._dashSpan); + 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); + } + } } } destroy() { + ReactDOM.unmountComponentAtNode(this._dashSpan); this._reactionDisposer?.(); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a73e601fd..055be7f86 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -817,6 +817,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const offset = annotOn && (contextHgt / 2 * 96 / 72); this.props.Document.scrollY = NumCast(doc.y) - offset; } + + afterFocus && setTimeout(() => afterFocus?.(), 1000); } else { const layoutdoc = Doc.Layout(doc); const newPanX = NumCast(doc.x) + NumCast(layoutdoc._width) / 2; @@ -834,7 +836,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { Doc.linkFollowHighlight(doc); afterFocus && setTimeout(() => { - if (afterFocus && afterFocus()) { + if (afterFocus?.()) { this.Document._panX = savedState.px; this.Document._panY = savedState.py; this.Document.scale = savedState.s; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 850225652..64d85589f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -217,7 +217,10 @@ export class DocumentView extends DocComponent(Docu this.multiTouchDisposer && this.multiTouchDisposer(); this.holdDisposer && this.holdDisposer(); Doc.UnBrushDoc(this.props.Document); - !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); + if (!this.props.dontRegisterView) { + const index = DocumentManager.Instance.DocumentViews.indexOf(this); + index !== -1 && DocumentManager.Instance.DocumentViews.splice(index, 1); + } } startDragging(x: number, y: number, dropAction: dropActionType) { @@ -829,7 +832,7 @@ export class DocumentView extends DocComponent(Docu if (!this.topMost) { // DocumentViews should stop propagation of this event - me?.stopPropagation(); + e.stopPropagation(); } ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); if (!SelectionManager.IsSelected(this, true)) { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 593f40f10..7b545eee5 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -56,7 +56,7 @@ export class PDFBox extends DocAnnotatableComponent const backup = "oldPath"; const { Document } = this.props; - const { url: { href } } = Cast(Document[this.props.fieldKey], PdfField)!; + const { url: { href } } = Cast(this.dataDoc[this.props.fieldKey], PdfField)!; const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g; const matches = pathCorrectionTest.exec(href); console.log("\nHere's the { url } being fed into the outer regex:"); @@ -78,9 +78,7 @@ export class PDFBox extends DocAnnotatableComponent } } - componentWillUnmount() { - this._selectReactionDisposer && this._selectReactionDisposer(); - } + componentWillUnmount() { this._selectReactionDisposer?.(); } componentDidMount() { this._selectReactionDisposer = reaction(() => this.props.isSelected(), () => { @@ -96,11 +94,11 @@ export class PDFBox extends DocAnnotatableComponent !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); } - public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); } - public prevAnnotation() { this._pdfViewer && this._pdfViewer.prevAnnotation(); } - public nextAnnotation() { this._pdfViewer && this._pdfViewer.nextAnnotation(); } - public backPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); } - public forwardPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); } + public search = (string: string, fwd: boolean) => { this._pdfViewer?.search(string, fwd); } + public prevAnnotation = () => { this._pdfViewer?.prevAnnotation(); } + public nextAnnotation = () => { this._pdfViewer?.nextAnnotation(); } + public backPage = () => { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); } + public forwardPage = () => { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); } public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); }; @undoBatch @@ -233,7 +231,7 @@ export class PDFBox extends DocAnnotatableComponent isChildActive = (outsideReaction?: boolean) => this._isChildActive; @computed get renderPdfView() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); - return
+ return
= React.createRef(); @@ -126,7 +128,7 @@ export class PDFViewer extends DocAnnotatableComponent this._showWaiting = this._showCover = true); @@ -162,10 +164,11 @@ export class PDFViewer extends DocAnnotatableComponent { this._reactionDisposer && this._reactionDisposer(); - this._annotationReactionDisposer && this._annotationReactionDisposer(); - this._filterReactionDisposer && this._filterReactionDisposer(); - this._selectionReactionDisposer && this._selectionReactionDisposer(); - this._searchReactionDisposer && this._searchReactionDisposer(); + this._scrollTopReactionDisposer?.(); + this._annotationReactionDisposer?.(); + this._filterReactionDisposer?.(); + this._selectionReactionDisposer?.(); + this._searchReactionDisposer?.(); document.removeEventListener("copy", this.copy); } @@ -206,6 +209,13 @@ export class PDFViewer extends DocAnnotatableComponent Cast(this.props.Document._scrollTop, "number", null), + (stop) => { + if (stop !== undefined) { + const offset = this.visibleHeight() / 2 * 96 / 72; + this._mainCont.current && smoothScroll(500, this._mainCont.current, stop); + } + }, { fireImmediately: true }); this._annotationReactionDisposer = reaction( () => DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]), annotations => annotations?.length && (this._annotations = annotations), @@ -267,7 +277,7 @@ export class PDFViewer extends DocAnnotatableComponent !e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc && - DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument, ctx: e.annoDragData.targetContext }, `Annotation from ${this.Document.title}`, "link from PDF") + dragComplete: e => { + if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) { + const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument, ctx: e.annoDragData.targetContext }, `Annotation from ${this.Document.title}`, "link from PDF"); + if (link) link.maximizeLocation = "onRight"; + } + } }); } } - createSnippet = (marquee: { left: number, top: number, width: number, height: number }): void => { - const view = Doc.MakeAlias(this.props.Document); - const data = Doc.MakeDelegate(Doc.GetProto(this.props.Document)); - data.title = StrCast(data.title) + "_snippet"; - view.proto = data; - view._nativeHeight = marquee.height; - view._height = (this.Document[WidthSym]() / (this.Document._nativeWidth || 1)) * marquee.height; - view._nativeWidth = this.Document._nativeWidth; - view.startY = marquee.top; - view._width = this.Document[WidthSym](); - DragManager.StartDocumentDrag([], new DragManager.DocumentDragData([view]), 0, 0); - } - scrollXf = () => { return this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, this._scrollTop) : this.props.ScreenToLocalTransform(); } @@ -643,6 +648,7 @@ export class PDFViewer extends DocAnnotatableComponent Date: Tue, 3 Mar 2020 10:49:22 -0500 Subject: fixes to allow navigation from hashtag tag to pivot/schema/stacking views --- src/client/documents/Documents.ts | 2 +- src/client/util/RichTextRules.ts | 10 +++++ src/client/util/RichTextSchema.tsx | 52 +++++++++++++++------- .../collections/CollectionMasonryViewFieldRow.tsx | 12 ++--- .../views/collections/CollectionStackingView.tsx | 30 ++++++------- .../CollectionStackingViewFieldColumn.tsx | 15 +++---- .../views/collections/CollectionViewChromes.scss | 16 +++---- .../views/collections/CollectionViewChromes.tsx | 20 ++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 24 +++++----- .../authentication/models/current_user_utils.ts | 2 +- 10 files changed, 105 insertions(+), 78 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4df90ceb8..49e7520f2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -122,7 +122,7 @@ export interface DocumentOptions { displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) borderRounding?: string; boxShadow?: string; - sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views + _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views schemaColumns?: List; dockingConfig?: string; annotationOn?: Doc; diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index af3b1a81e..70a1a5154 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -100,6 +100,16 @@ export class RichTextRules { const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid }); return state.tr.deleteRange(start, end).insert(start, fieldView); }), + // create an inline view of a tag stored under the '#' field + new InputRule( + new RegExp(/#([a-zA-Z_\-0-9]+)\s$/), + (state, match, start, end) => { + const tag = match[1]; + if (!tag) return state.tr; + this.Document[DataSym]["#"] = tag; + const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" }); + return state.tr.deleteRange(start, end).insert(start, fieldView); + }), // create an inline view of a document {{ : }} // {{:Doc}} => show default view of document {{}} => show layout for this doc {{ : Doc}} => show layout for another doc new InputRule( new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(:[a-zA-Z_ \-0-9]+)?\}\}$/), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index b2ee7320a..c67b42766 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -25,7 +25,11 @@ import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSche import { ContextMenu } from "../views/ContextMenu"; import { ContextMenuProps } from "../views/ContextMenuItem"; import { Docs } from "../documents/Documents"; -import { CollectionView } from "../views/collections/CollectionView"; +import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; +import { toBlob } from "html-to-image"; +import { listSpec } from "../../new_fields/Schema"; +import { List } from "../../new_fields/List"; +import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -880,7 +884,7 @@ export class DashFieldView { this._fieldSpan.contentEditable = "true"; this._fieldSpan.style.position = "relative"; this._fieldSpan.style.display = "inline-block"; - this._fieldSpan.style.minWidth = "50px"; + this._fieldSpan.style.minWidth = "5px"; this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; @@ -893,6 +897,21 @@ export class DashFieldView { }, icon: "expand-arrows-alt" }); }; + this._fieldSpan.onblur = function (e: any) { + let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; + // look for a document whose id === the fieldKey being displayed. If there's a match, then that document + // holds the different enumerated values for the field in the titles of its collected documents. + // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. + + // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key + DocServer.GetRefField(node.attrs.fieldKey).then(options => { + (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); + self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText; + if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) { + Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); + } + }); + } const setDashDoc = (doc: Doc) => { self._dashDoc = doc; @@ -916,19 +935,7 @@ export class DashFieldView { if (e.ctrlKey) { Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); } - let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; - // look for a document whose id === the fieldKey being displayed. If there's a match, then that document - // holds the different enumerated values for the field in the titles of its collected documents. - // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - - // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key - DocServer.GetRefField(node.attrs.fieldKey).then(options => { - (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); - self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText; - if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) { - Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); - } - }); + self._fieldSpan.onblur?.(undefined as any); } }; @@ -937,6 +944,21 @@ export class DashFieldView { this._labelSpan.style.display = "inline"; this._labelSpan.style.fontWeight = "bold"; this._labelSpan.style.fontSize = "larger"; + this._labelSpan.onpointerdown = function (e: any) { + e.stopPropagation(); + if (tbox.props.ContainingCollectionDoc) { + const alias = Doc.MakeAlias(tbox.props.ContainingCollectionDoc); + alias.viewType = CollectionViewType.Time; + let list = Cast(alias.schemaColumns, listSpec(SchemaHeaderField)); + if (!list) { + alias.schemaColumns = list = new List(); + } + list.map(c => c.heading).indexOf("#") === -1 && list.push(new SchemaHeaderField("#", "#f1efeb")); + list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb")); + alias._pivotField = "#"; + tbox.props.addDocTab(alias, "onRight"); + } + } this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `; if (node.attrs.docid) { DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && runInAction(() => setDashDoc(dashDoc))); diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 3c2cbb5b0..6ebd3194d 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -80,7 +80,7 @@ export class CollectionMasonryViewFieldRow extends React.Component d[key] = castedValue); this.props.parent.onInternalDrop(e, de); @@ -99,7 +99,7 @@ export class CollectionMasonryViewFieldRow extends React.Component { this._createAliasSelected = false; - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); const castedValue = this.getValue(value); if (castedValue) { if (this.props.parent.sectionHeaders) { @@ -138,7 +138,7 @@ export class CollectionMasonryViewFieldRow extends React.Component { this._createAliasSelected = false; - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); const newDoc = Docs.Create.TextDocument("", { _height: 18, _width: 200, title: value }); newDoc[key] = this.getValue(this.props.heading); return this.props.parent.props.addDocument(newDoc); @@ -146,7 +146,7 @@ export class CollectionMasonryViewFieldRow extends React.Component { this._createAliasSelected = false; - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); this.props.docList.forEach(d => d[key] = undefined); if (this.props.parent.sectionHeaders && this.props.headingObject) { const index = this.props.parent.sectionHeaders.indexOf(this.props.headingObject); @@ -168,7 +168,7 @@ export class CollectionMasonryViewFieldRow extends React.Component this._sensitivity) { const alias = Doc.MakeAlias(this.props.parent.props.Document); - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); let value = this.getValue(this._heading); value = typeof value === "string" ? `"${value}"` : value; const script = `return doc.${key} === ${value}`; @@ -296,7 +296,7 @@ export class CollectionMasonryViewFieldRow extends React.Component evContents, diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d1f45af90..f84b0af20 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -31,21 +31,21 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _heightDisposer?: IReactionDisposer; - _sectionFilterDisposer?: IReactionDisposer; + _pivotFieldDisposer?: IReactionDisposer; _docXfs: any[] = []; _columnStart: number = 0; @observable _heightMap = new Map(); @observable _cursor: CursorProperty = "grab"; @observable _scroll = 0; // used to force the document decoration to update when scrolling @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } - @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); } + @computed get pivotField() { return StrCast(this.props.Document._pivotField); } @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); } @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); } @computed get yMargin() { return Math.max(this.props.Document._showTitle && !this.props.Document._showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); } @computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); } @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); } @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; } - @computed get showAddAGroup() { return (this.sectionFilter && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); } + @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); } @computed get columnWidth() { return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250)); @@ -73,7 +73,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } get Sections() { - if (!this.sectionFilter || this.sectionHeaders instanceof Promise) return new Map(); + if (!this.pivotField || this.sectionHeaders instanceof Promise) return new Map(); if (this.sectionHeaders === undefined) { setTimeout(() => this.props.Document.sectionHeaders = new List(), 0); @@ -83,18 +83,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const fields = new Map(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); let changed = false; this.filteredChildren.map(d => { - const sectionValue = (d[this.sectionFilter] ? d[this.sectionFilter] : `NO ${this.sectionFilter.toUpperCase()} VALUE`) as object; + const sectionValue = (d[this.pivotField] ? d[this.pivotField] : `NO ${this.pivotField.toUpperCase()} VALUE`) as object; // the next five lines ensures that floating point rounding errors don't create more than one section -syip const parsed = parseInt(sectionValue.toString()); const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue; // look for if header exists already - const existingHeader = sectionHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`)); + const existingHeader = sectionHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`)); if (existingHeader) { fields.get(existingHeader)!.push(d); } else { - const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`); + const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`); fields.set(newSchemaHeader, [d]); sectionHeaders.push(newSchemaHeader); changed = true; @@ -134,15 +134,15 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ); // reset section headers when a new filter is inputted - this._sectionFilterDisposer = reaction( - () => this.sectionFilter, + this._pivotFieldDisposer = reaction( + () => this.pivotField, () => this.props.Document.sectionHeaders = new List() ); } componentWillUnmount() { super.componentWillUnmount(); - this._heightDisposer && this._heightDisposer(); - this._sectionFilterDisposer && this._sectionFilterDisposer(); + this._heightDisposer?.(); + this._pivotFieldDisposer?.(); } @action @@ -278,7 +278,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } headings = () => Array.from(this.Sections.keys()); sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { - const key = this.sectionFilter; + const key = this.pivotField; let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { @@ -313,7 +313,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { - const key = this.sectionFilter; + const key = this.pivotField; let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { @@ -341,7 +341,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (value && this.sectionHeaders) { const schemaHdrField = new SchemaHeaderField(value); this.sectionHeaders.push(schemaHdrField); - Doc.addEnumerationToTextField(undefined, this.sectionFilter, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]); + Doc.addEnumerationToTextField(undefined, this.pivotField, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]); return true; } return false; @@ -370,7 +370,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get renderedSections() { TraceMobx(); let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]; - if (this.sectionFilter) { + if (this.pivotField) { const entries = Array.from(this.Sections.entries()); sections = entries.sort(this.sortFunc); } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 516e583d4..646b433bf 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -23,7 +23,6 @@ import { CollectionStackingView } from "./CollectionStackingView"; import { setupMoveUpEvents, emptyFunction } from "../../../Utils"; import "./CollectionStackingView.scss"; import { listSpec } from "../../../new_fields/Schema"; -import { Schema } from "prosemirror-model"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -62,7 +61,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { if (de.complete.docDragData) { - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); const castedValue = this.getValue(this._heading); de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, false)); this.props.parent.onInternalDrop(e, de); @@ -85,7 +84,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); const castedValue = this.getValue(value); if (castedValue) { if (this.props.parent.sectionHeaders) { @@ -126,7 +125,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { if (!value) return false; - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, title: value, _autoHeight: true }); newDoc[key] = this.getValue(this.props.heading); const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); @@ -137,7 +136,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { - const key = StrCast(this.props.parent.props.Document.sectionFilter); + const key = StrCast(this.props.parent.props.Document._pivotField); this.props.docList.forEach(d => d[key] = undefined); if (this.props.parent.sectionHeaders && this.props.headingObject) { const index = this.props.parent.sectionHeaders.indexOf(this.props.headingObject); @@ -161,8 +160,8 @@ export class CollectionStackingViewFieldColumn extends React.Component { const alias = Doc.MakeAlias(this.props.parent.props.Document); alias._width = this.props.parent.props.PanelWidth() / (Cast(this.props.parent.props.Document.sectionHeaders, listSpec(SchemaHeaderField))?.length || 1); - alias.sectionFilter = undefined; - const key = StrCast(this.props.parent.props.Document.sectionFilter); + alias._pivotField = undefined; + const key = StrCast(this.props.parent.props.Document._pivotField); let value = this.getValue(this._heading); value = typeof value === "string" ? `"${value}"` : value; alias.viewSpecScript = ScriptField.MakeFunction(`doc.${key} === ${value}`, { doc: Doc.name }); @@ -277,7 +276,7 @@ export class CollectionStackingViewFieldColumn extends React.Component c.title === this._currentKey).map(c => c.immediate(de.complete.docDragData ?.draggedDocuments || [])); + this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate(de.complete.docDragData?.draggedDocuments || [])); e.stopPropagation(); } return true; @@ -472,7 +472,7 @@ export class CollectionStackingViewChrome extends React.Component => { value = value.toLowerCase(); @@ -510,26 +510,26 @@ export class CollectionStackingViewChrome extends React.Component { - this.props.CollectionView.props.Document.sectionFilter = value; + this.props.CollectionView.props.Document._pivotField = value; return true; } @action toggleSort = () => { this.props.CollectionView.props.Document.stackingHeadersSortDescending = !this.props.CollectionView.props.Document.stackingHeadersSortDescending; }; - @action resetValue = () => { this._currentKey = this.sectionFilter; }; + @action resetValue = () => { this._currentKey = this.pivotField; }; render() { return (
-
-
+
+
GROUP ITEMS BY:
-
+
this.sectionFilter} + GetValue={() => this.pivotField} autosuggestProps={ { resetValue: this.resetValue, @@ -551,7 +551,7 @@ export class CollectionStackingViewChrome extends React.Component
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 055be7f86..ea86bff99 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,20 +1,22 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; -import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload, faTextHeight } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer } from "mobx"; +import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocCastAsync } from "../../../../new_fields/Doc"; +import { Doc, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc"; import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; -import { InkTool, InkField, InkData } from "../../../../new_fields/InkField"; +import { InkData, InkField, InkTool } from "../../../../new_fields/InkField"; +import { List } from "../../../../new_fields/List"; +import { RichTextField } from "../../../../new_fields/RichTextField"; import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema"; import { ScriptField } from "../../../../new_fields/ScriptField"; -import { Cast, NumCast, ScriptCast, BoolCast, StrCast, FieldValue } from "../../../../new_fields/Types"; +import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types"; import { TraceMobx } from "../../../../new_fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; import { aggregateBounds, intersectRect, returnOne, Utils } from "../../../../Utils"; +import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; import { DocumentManager } from "../../../util/DocumentManager"; @@ -29,10 +31,11 @@ import { ContextMenu } from "../../ContextMenu"; import { ContextMenuProps } from "../../ContextMenuItem"; import { InkingControl } from "../../InkingControl"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentContentsView } from "../../nodes/DocumentContentsView"; +import { DocumentViewProps } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; +import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; @@ -40,13 +43,6 @@ import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; -import { RichTextField } from "../../../../new_fields/RichTextField"; -import { List } from "../../../../new_fields/List"; -import { DocumentViewProps } from "../../nodes/DocumentView"; -import { CollectionDockingView } from "../CollectionDockingView"; -import { MainView } from "../../MainView"; -import { TouchScrollableMenuItem } from "../../TouchScrollableMenu"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 6216ab7e6..0f8d8fec8 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -254,7 +254,7 @@ export class CurrentUserUtils { // Finally, setup the list of buttons to display in the sidebar doc.sidebarButtons = Docs.Create.StackingDocument([doc.SearchBtn as Doc, doc.LibraryBtn as Doc, doc.ToolsBtn as Doc], { - _width: 500, _height: 80, boxShadow: "0 0", sectionFilter: "title", hideHeadings: true, ignoreClick: true, + _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "disabled", title: "library stack", backgroundColor: "dimGray", }); } -- cgit v1.2.3-70-g09d2 From 2721713f409045594fa9fbf1d23bc5e4d9a08641 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 3 Mar 2020 12:08:52 -0500 Subject: fixed opening of metadata from text box. fixed minimizing presentatino view. cleaned up closeRightSplit. --- src/client/util/DocumentManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 6 ++-- .../views/collections/CollectionDockingView.tsx | 42 ++++++++-------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 +------- src/client/views/nodes/PresBox.tsx | 3 +- 5 files changed, 22 insertions(+), 45 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 6bd2fd016..0ec1d23d9 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -55,7 +55,7 @@ export class DocumentManager { } public getDocumentViewById(id: string, preferredCollection?: CollectionView): DocumentView | undefined { - + if (!id) return undefined; let toReturn: DocumentView | undefined; const passes = preferredCollection ? [preferredCollection, undefined] : [undefined]; diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c67b42766..d66890cda 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -940,10 +940,12 @@ export class DashFieldView { }; this._labelSpan = document.createElement("span"); + this._labelSpan.style.backgroundColor = "rgba(155, 155, 155, 0.44)"; this._labelSpan.style.position = "relative"; this._labelSpan.style.display = "inline"; this._labelSpan.style.fontWeight = "bold"; this._labelSpan.style.fontSize = "larger"; + this._labelSpan.title = "click to see related tags"; this._labelSpan.onpointerdown = function (e: any) { e.stopPropagation(); if (tbox.props.ContainingCollectionDoc) { @@ -953,9 +955,9 @@ export class DashFieldView { if (!list) { alias.schemaColumns = list = new List(); } - list.map(c => c.heading).indexOf("#") === -1 && list.push(new SchemaHeaderField("#", "#f1efeb")); + list.map(c => c.heading).indexOf(self._fieldKey) === -1 && list.push(new SchemaHeaderField(self._fieldKey, "#f1efeb")); list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb")); - alias._pivotField = "#"; + alias._pivotField = self._fieldKey; tbox.props.addDocTab(alias, "onRight"); } } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index b85cc9b56..db8f7d5e4 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -127,36 +127,22 @@ export class CollectionDockingView extends React.Component): boolean { - if (!CollectionDockingView.Instance) return false; const instance = CollectionDockingView.Instance; - let retVal = false; - if (instance._goldenLayout.root.contentItems[0].isRow) { - retVal = Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => { - if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" && - DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId) && - ((!document && DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)!.Document.isDisplayPanel) || - (document && Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)!.Document, document)))) { - child.contentItems[0].remove(); + const tryClose = (childItem: any) => { + if (childItem.config?.component === "DocumentFrameRenderer") { + const docView = DocumentManager.Instance.getDocumentViewById(childItem.config.props.documentId); + if (docView && ((!document && docView.Document.isDisplayPanel) || (document && Doc.AreProtosEqual(docView.props.Document, document)))) { + childItem.remove(); instance.layoutChanged(document); return true; - } else { - Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { - if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId) && - ((!document && DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document.isDisplayPanel) || - (document && Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document, document)))) { - child.contentItems[j].remove(); - child.config.activeItemIndex = Math.max(child.contentItems.length - 1, 0); - return true; - } - return false; - }); } - return false; - }); - } - if (retVal) { - instance.stateChanged(); + } + return false; } + let retVal = !instance?._goldenLayout.root.contentItems[0].isRow ? false : + Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => Array.from(child.contentItems).some(tryClose)); + + retVal && instance.stateChanged(); return retVal; } @@ -240,16 +226,16 @@ export class CollectionDockingView extends React.Component { - switch (this._pullDirection) { - case "left": - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "left", undefined); - break; case "right": - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "right", undefined); - break; case "top": - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "top", undefined); - break; case "bottom": - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "bottom", undefined); - break; - default: - break; + CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), this._pullDirection); } - console.log(""); this._pullDirection = ""; this._pullCoords = [0, 0]; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 4180ee255..27c2d6957 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -340,7 +340,7 @@ export class PresBox extends React.Component { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Show as Slideshow", event: action(() => this.props.Document._viewType = CollectionViewType.Carousel), icon: "asterisk" }); funcs.push({ description: "Show as Timeline", event: action(() => this.props.Document._viewType = CollectionViewType.Time), icon: "asterisk" }); - funcs.push({ description: "Show as List", event: action(() => this.props.Document._viewType = CollectionViewType.Invalid), icon: "asterisk" }); + funcs.push({ description: "Show as List", event: action(() => { this.props.Document._viewType = CollectionViewType.Stacking; this.props.Document._pivotField = undefined; }), icon: "asterisk" }); ContextMenu.Instance.addItem({ description: "Presentation Funcs...", subitems: funcs, icon: "asterisk" }); } @@ -377,6 +377,7 @@ export class PresBox extends React.Component { viewChanged = action((e: React.ChangeEvent) => { //@ts-ignore this.props.Document._viewType = Number(e.target.selectedOptions[0].value); + this.props.Document._viewType === CollectionViewType.Stacking && (this.props.Document._pivotField = undefined); this.updateMinimize(e, Number(this.props.Document._viewType)); }); -- cgit v1.2.3-70-g09d2 From 1e2f97d1dcd3abb3be701462a43d166e9826edc3 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 3 Mar 2020 12:16:21 -0500 Subject: from last. --- src/client/util/RichTextSchema.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index d66890cda..2ef22b6a0 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -942,9 +942,8 @@ export class DashFieldView { this._labelSpan = document.createElement("span"); this._labelSpan.style.backgroundColor = "rgba(155, 155, 155, 0.44)"; this._labelSpan.style.position = "relative"; - this._labelSpan.style.display = "inline"; - this._labelSpan.style.fontWeight = "bold"; - this._labelSpan.style.fontSize = "larger"; + this._labelSpan.style.display = "inline-block"; + this._labelSpan.style.fontSize = "small"; this._labelSpan.title = "click to see related tags"; this._labelSpan.onpointerdown = function (e: any) { e.stopPropagation(); -- cgit v1.2.3-70-g09d2 From 8b71007c98f3c5f5092d15c6ce91142729bcec22 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 3 Mar 2020 14:02:17 -0500 Subject: fixed dragging from linear view because of screentransform. added [[key=value]] syntax. added button for seeing enumerated values. added step up button in DocDec for selecting parent collection --- src/client/util/RichTextRules.ts | 8 ++- src/client/util/RichTextSchema.tsx | 57 +++++++++++++++------- src/client/views/DocumentDecorations.scss | 11 +++++ src/client/views/DocumentDecorations.tsx | 16 +++++- .../views/collections/CollectionLinearView.tsx | 2 +- src/new_fields/Doc.ts | 34 ++++++------- 6 files changed, 89 insertions(+), 39 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 70a1a5154..7ffc2dd9c 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -81,10 +81,11 @@ export class RichTextRules { // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document [[ : ]] // [[:Doc]] => hyperlink [[fieldKey]] => show field [[fieldKey:Doc]] => show field of doc new InputRule( - new RegExp(/\[\[([a-zA-Z_#@\? \-0-9]*)(:[a-zA-Z_#@\? \-0-9]+)?\]\]$/), + new RegExp(/\[\[([a-zA-Z_#@\? \-0-9]*)(=[a-zA-Z_#@\? \-0-9]*)?(:[a-zA-Z_#@\? \-0-9]+)?\]\]$/), (state, match, start, end) => { const fieldKey = match[1]; - const docid = match[2]?.substring(1); + const docid = match[3]?.substring(1); + const value = match[2]?.substring(1); if (!fieldKey) { if (docid) { DocServer.GetRefField(docid).then(docx => { @@ -97,6 +98,9 @@ export class RichTextRules { } return state.tr; } + if (value !== "") { + this.Document[DataSym][fieldKey] = value; + } const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid }); return state.tr.deleteRange(start, end).insert(start, fieldView); }), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 2ef22b6a0..034f5d55a 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -8,28 +8,25 @@ import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-s import { StepMap } from "prosemirror-transform"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, Field, HeightSym, WidthSym, DocListCast } from "../../new_fields/Doc"; +import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; +import { List } from "../../new_fields/List"; import { ObjectField } from "../../new_fields/ObjectField"; +import { listSpec } from "../../new_fields/Schema"; +import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; import { ComputedField } from "../../new_fields/ScriptField"; -import { BoolCast, NumCast, StrCast, Cast } from "../../new_fields/Types"; +import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; +import { Docs } from "../documents/Documents"; +import { CollectionViewType } from "../views/collections/CollectionView"; +import { ContextMenu } from "../views/ContextMenu"; import { DocumentView } from "../views/nodes/DocumentView"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { DocumentManager } from "./DocumentManager"; import ParagraphNodeSpec from "./ParagraphNodeSpec"; import { Transform } from "./Transform"; import React = require("react"); -import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSchemaCells"; -import { ContextMenu } from "../views/ContextMenu"; -import { ContextMenuProps } from "../views/ContextMenuItem"; -import { Docs } from "../documents/Documents"; -import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; -import { toBlob } from "html-to-image"; -import { listSpec } from "../../new_fields/Schema"; -import { List } from "../../new_fields/List"; -import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -839,8 +836,8 @@ export class DashDocView { zoomToScale={emptyFunction} getScale={returnOne} dontRegisterView={false} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} + ContainingCollectionView={this._textBox.props.ContainingCollectionView} + ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc} ContentScaling={this.contentScaling} />, this._dashSpan); if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") { @@ -863,6 +860,7 @@ export class DashFieldView { _fieldWrapper: HTMLDivElement; // container for label and value _labelSpan: HTMLSpanElement; // field label _fieldSpan: HTMLDivElement; // field value + _enumerables: HTMLDivElement; // field value _reactionDisposer: IReactionDisposer | undefined; _textBoxDoc: Doc; @observable _dashDoc: Doc | undefined; @@ -879,6 +877,19 @@ export class DashFieldView { this._fieldWrapper.style.display = "inline-block"; const self = this; + this._enumerables = document.createElement("div"); + this._enumerables.style.width = "10px"; + this._enumerables.style.height = "10px"; + this._enumerables.style.position = "relative"; + this._enumerables.style.display = "none"; + this._enumerables.style.background = "dimGray"; + + this._enumerables.onpointerdown = async (e) => { + e.stopPropagation(); + const collview = await Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); + collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"); + } + this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); this._fieldSpan.contentEditable = "true"; @@ -888,7 +899,10 @@ export class DashFieldView { this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; - this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); }; + this._fieldSpan.onmousedown = function (e: any) { + e.stopPropagation(); + self._enumerables.style.display = "inline-block"; + }; this._fieldSpan.oncontextmenu = function (e: any) { ContextMenu.Instance.addItem({ description: "Show Enumeration Templates", event: () => { @@ -898,15 +912,17 @@ export class DashFieldView { }); }; this._fieldSpan.onblur = function (e: any) { + self._enumerables.style.display = "none"; let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; + // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - - // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key DocServer.GetRefField(node.attrs.fieldKey).then(options => { (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText; + + // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) { Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); } @@ -947,8 +963,12 @@ export class DashFieldView { this._labelSpan.title = "click to see related tags"; this._labelSpan.onpointerdown = function (e: any) { e.stopPropagation(); - if (tbox.props.ContainingCollectionDoc) { - const alias = Doc.MakeAlias(tbox.props.ContainingCollectionDoc); + let container = tbox.props.ContainingCollectionView; + while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) { + container = container.props.ContainingCollectionView; + } + if (container) { + const alias = Doc.MakeAlias(container.props.Document); alias.viewType = CollectionViewType.Time; let list = Cast(alias.schemaColumns, listSpec(SchemaHeaderField)); if (!list) { @@ -974,6 +994,7 @@ export class DashFieldView { this._fieldWrapper.appendChild(this._labelSpan); this._fieldWrapper.appendChild(this._fieldSpan); + this._fieldWrapper.appendChild(this._enumerables); (this as any).dom = this._fieldWrapper; } destroy() { diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 1992c5efa..fdf7c3f42 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -27,6 +27,17 @@ $linkGap : 3px; opacity: 1; } + .documentDecorations-selector { + pointer-events: auto; + height: 15px; + width: 15px; + left: -20px; + top: 20px; + display: inline-block; + position: absolute; + opacity: 0.5; + } + .documentDecorations-radius { pointer-events: auto; background: black; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 4922411e8..c98be0d4a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -8,7 +8,7 @@ import { PositionDocument } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; -import { Utils, setupMoveUpEvents } from "../../Utils"; +import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils"; import { DocUtils } from "../documents/Documents"; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from "../util/DragManager"; @@ -244,6 +244,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.DeselectAll(); } + @action + onSelectorUp = (e: React.PointerEvent): void => { + setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e) => { + const selDoc = SelectionManager.SelectedDocuments()?.[0]; + if (selDoc) { + selDoc.props.ContainingCollectionView?.props.select(false); + } + })); + } + @action onRadiusDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, this.onRadiusMove, (e) => this._resizeUndo?.end(), (e) => { }); @@ -496,6 +506,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}>
e.preventDefault()}>
+ {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) :
e.preventDefault()}> + +
}
e.preventDefault()}>
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index 9384eb381..79ec6d518 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -77,7 +77,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { getTransform = (ele: React.RefObject) => () => { if (!ele.current) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current); - return new Transform(-translateX, -translateY, 1 / scale); + return new Transform(-translateX, -translateY, 1); } render() { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 0f3896055..6d94f050c 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -865,25 +865,25 @@ export namespace Doc { return (await DocServer.GetRefField(enumeratedFieldKey)) as Doc; } - export function addEnumerationToTextField(doc: Opt, enumeratedFieldKey: string, enumeratedDocs: Doc[]) { - DocServer.GetRefField(enumeratedFieldKey).then(optionsCollection => { - if (!(optionsCollection instanceof Doc)) { - optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey); - Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); + export async function addEnumerationToTextField(doc: Opt, enumeratedFieldKey: string, enumeratedDocs: Doc[]) { + let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey); + if (!(optionsCollection instanceof Doc)) { + optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey); + Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); + } + const options = optionsCollection as Doc; + doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options })); + doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options })); + enumeratedDocs.map(enumeratedDoc => { + const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title); + if (found) { + found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor; + found._color = enumeratedDoc._color || found._color; + } else { + Doc.AddDocToList(options, "data", enumeratedDoc); } - const options = optionsCollection as Doc; - doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options })); - doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options })); - enumeratedDocs.map(enumeratedDoc => { - const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title); - if (found) { - found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor; - found._color = enumeratedDoc._color || found._color; - } else { - Doc.AddDocToList(options, "data", enumeratedDoc); - } - }); }); + return optionsCollection; } } -- cgit v1.2.3-70-g09d2 From ef58bdb2f6e9bffe377239d77b3360ed8b3132a1 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 3 Mar 2020 18:14:37 -0500 Subject: a bunch of small fixes to link naming and fixes to audio links. --- src/client/documents/Documents.ts | 8 ++++---- src/client/util/RichTextMenu.tsx | 2 +- src/client/util/RichTextRules.ts | 2 +- src/client/util/RichTextSchema.tsx | 3 ++- src/client/views/DocumentButtonBar.tsx | 4 +--- src/client/views/RecommendationsBox.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormLinkView.tsx | 4 ++-- .../views/collections/collectionFreeForm/MarqueeView.tsx | 11 ++++++----- src/client/views/nodes/AudioBox.scss | 3 ++- src/client/views/nodes/AudioBox.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 10 +++++----- src/client/views/nodes/FormattedTextBox.tsx | 4 ++-- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 4 ++-- 15 files changed, 32 insertions(+), 30 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 67e037286..6b25b3897 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -459,7 +459,7 @@ export namespace Docs { const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey); const viewDoc = Doc.MakeDelegate(dataDoc, delegId); - viewDoc.type !== DocumentType.LINK && AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "link to audio: " + d.title)); + viewDoc.type !== DocumentType.LINK && AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "audio timeline")); return Doc.assign(viewDoc, delegateProps, true); } @@ -914,13 +914,13 @@ export namespace DocUtils { }); } - export function MakeLink(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, title: string = "", linkRelationship: string = "", id?: string) { + export function MakeLink(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, linkRelationship: string = "", id?: string) { const sv = DocumentManager.Instance.getDocumentView(source.doc); if (sv && sv.props.ContainingCollectionDoc === target.doc) return; if (target.doc === CurrentUserUtils.UserDocument) return undefined; - const linkDoc = Docs.Create.LinkDocument(source, target, { title, linkRelationship }, id); - Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('this.anchor1.title +" " + (this.linkRelationship||"to") +" " + this.anchor2.title'); + const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship }, id); + Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('this.anchor1.title +" (" + (this.linkRelationship||"to") +") " + this.anchor2.title'); Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(this)"); Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(this)"); diff --git a/src/client/util/RichTextMenu.tsx b/src/client/util/RichTextMenu.tsx index 460f1fa37..3f0ec7aa5 100644 --- a/src/client/util/RichTextMenu.tsx +++ b/src/client/util/RichTextMenu.tsx @@ -146,7 +146,7 @@ export default class RichTextMenu extends AntimodeMenu { public MakeLinkToSelection = (linkDocId: string, title: string, location: string, targetDocId: string): string => { if (this.view) { - const link = this.view.state.schema.marks.link.create({ href: Utils.prepend("/doc/" + linkDocId), title: title, location: location, targetId: targetDocId }); + const link = this.view.state.schema.marks.link.create({ href: Utils.prepend("/doc/" + linkDocId), title: title, location: location, linkId: linkDocId, targetId: targetDocId }); this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link). addMark(this.view.state.selection.from, this.view.state.selection.to, link)); return this.view.state.selection.$from.nodeAfter?.text || ""; diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 7ffc2dd9c..e5b20a79b 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -91,7 +91,7 @@ export class RichTextRules { 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: this.Document }, { doc: target }, "portal link", ""); + DocUtils.MakeLink({ doc: this.Document }, { doc: target }, "portal to"); }); 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); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 034f5d55a..2c3714310 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -301,6 +301,7 @@ export const marks: { [index: string]: MarkSpec } = { attrs: { href: {}, targetId: { default: "" }, + linkId: { default: "" }, showPreview: { default: true }, location: { default: null }, title: { default: null }, @@ -315,7 +316,7 @@ export const marks: { [index: string]: MarkSpec } = { toDOM(node: any) { return node.attrs.docref && node.attrs.title ? ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, class: "prosemirror-attribution", title: `${node.attrs.title}` }, node.attrs.title], ["br"]] : - ["a", { ...node.attrs, id: node.attrs.targetId, title: `${node.attrs.title}` }, 0]; + ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0]; } }, diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a3d313224..52544d3c9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -122,13 +122,11 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | if (this.view0 && linkDoc) { const proto = Doc.GetProto(linkDoc); proto.anchor1Context = this.view0.props.ContainingCollectionDoc; + Doc.GetProto(linkDoc).linkRelationship = "hyperlink"; const anchor2Title = linkDoc.anchor2 instanceof Doc ? StrCast(linkDoc.anchor2.title) : "-untitled-"; const anchor2Id = linkDoc.anchor2 instanceof Doc ? linkDoc.anchor2[Id] : ""; const text = RichTextMenu.Instance.MakeLinkToSelection(linkDoc[Id], anchor2Title, e.ctrlKey ? "onRight" : "inTab", anchor2Id); - if (linkDoc.anchor2 instanceof Doc && !proto.title) { - proto.title = Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('this.anchor1.title +" " + (this.linkRelationship||"to") +" " + this.anchor2.title'); - } } linkDrag?.end(); }, diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx index 0e3cfd729..262226bac 100644 --- a/src/client/views/RecommendationsBox.tsx +++ b/src/client/views/RecommendationsBox.tsx @@ -167,7 +167,7 @@ export class RecommendationsBox extends React.Component {
DocumentManager.Instance.jumpToDocument(doc, false)}>
-
DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}> +
DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "Recommender", undefined)}>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7eeeb6ff1..28f620157 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -231,7 +231,7 @@ class TreeView extends React.Component { if (de.complete.linkDragData) { const sourceDoc = de.complete.linkDragData.linkSourceDocument; const destDoc = this.props.document; - DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree drop link"); + DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree link"); e.stopPropagation(); } if (de.complete.docDragData) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 1038347d4..a33146388 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -46,8 +46,8 @@ export class CollectionFreeFormLinkView extends React.Component(selected); - Doc.GetProto(summary).layout_portal = CollectionView.LayoutString("data-annotations"); + Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List(selected); + Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations"); summary._backgroundColor = "#e2ad32"; portal.layoutKey = "layout_portal"; - DocUtils.MakeLink({ doc: summary, ctx: this.props.ContainingCollectionDoc }, { doc: portal }, "portal link", "portal link"); + portal.title = "document collection"; + DocUtils.MakeLink({ doc: summary, ctx: this.props.ContainingCollectionDoc }, { doc: portal }, "summarizing"); this.props.addLiveTextDocument(summary); MarqueeOptionsMenu.Instance.fadeOut(true); diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 0c363f0c1..4516418a7 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -72,6 +72,7 @@ margin-left:-2.55px; background:gray; border-radius: 100%; + opacity:0.9; background-color: transparent; box-shadow: black 2px 2px 1px; .docuLinkBox-cont { @@ -98,7 +99,7 @@ } } .audiobox-linker:hover, .audiobox-linker-mini:hover { - transform:scale(1.5); + opacity:1; } .audiobox-marker-container, .audiobox-marker-minicontainer { position:absolute; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 862578e40..c4c6365e3 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -249,6 +249,7 @@ export class AudioBox extends DocExtendableComponent
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 64d85589f..782a9ce08 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -569,8 +569,7 @@ export class DocumentView extends DocComponent(Docu e.stopPropagation(); de.complete.annoDragData.linkedToDoc = true; - DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, - `Link from ${StrCast(de.complete.annoDragData.annotationDocument.title)}`); + DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, "link"); } if (de.complete.docDragData) { if (de.complete.docDragData.applyAsTemplate) { @@ -601,13 +600,14 @@ export class DocumentView extends DocComponent(Docu // const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); de.complete.linkDragData.linkSourceDocument !== this.props.Document && (de.complete.linkDragData.linkDocument = DocUtils.MakeLink({ doc: de.complete.linkDragData.linkSourceDocument }, - { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, `link from ${de.complete.linkDragData.linkSourceDocument.title} to ${this.props.Document.title}`)); // TODODO this is where in text links get passed + { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, `link`)); // TODODO this is where in text links get passed } } @undoBatch @action public static unfreezeNativeDimensions(layoutDoc: Doc) { + m layoutDoc._nativeWidth = undefined; layoutDoc._nativeHeight = undefined; } @@ -627,7 +627,7 @@ export class DocumentView extends DocComponent(Docu const portalLink = DocListCast(this.Document.links).find(d => d.anchor1 === this.props.Document); if (!portalLink) { const portal = Docs.Create.FreeformDocument([], { _width: (this.layoutDoc._width || 0) + 10, _height: this.layoutDoc._height || 0, title: StrCast(this.props.Document.title) + ".portal" }); - DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: portal }, "portal link", "portal link"); + DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: portal }, "portal to"); } this.Document.isButton = true; } @@ -1118,7 +1118,7 @@ export class DocumentView extends DocComponent(Docu const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way - return
Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)} style={{ diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7b434ebc1..8f4cefbf4 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -150,7 +150,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & 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.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: this.dataDoc[key] as Doc }, "Ref:" + value, "link to named target", id); + else DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: this.dataDoc[key] as Doc }, "link to named target", id); }); }); }); @@ -723,7 +723,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & targetAnnotations?.push(pdfRegion); }); - const link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "note on " + pdfDoc.title, "pasted PDF link"); + const link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "PDF pasted"); if (link) { cbe.clipboardData!.setData("dash/linkDoc", link[Id]); const linkId = link[Id]; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 69c6f2617..7ab650dc9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -134,7 +134,7 @@ export class VideoBox extends DocAnnotatableComponent Cast(this.props.Document._scrollTop, "number", null), - (stop) => (stop !== undefined) && this._mainCont.current && smoothScroll(500, this._mainCont.current, stop) , { fireImmediately: true }); + (stop) => (stop !== undefined) && this._mainCont.current && smoothScroll(500, this._mainCont.current, stop), { fireImmediately: true }); this._annotationReactionDisposer = reaction( () => DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]), annotations => annotations?.length && (this._annotations = annotations), @@ -582,7 +582,7 @@ export class PDFViewer extends DocAnnotatableComponent { if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) { - const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument, ctx: e.annoDragData.targetContext }, `Annotation from ${this.Document.title}`, "link from PDF"); + const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument, ctx: e.annoDragData.targetContext }, "Annotation"); if (link) link.maximizeLocation = "onRight"; } } -- cgit v1.2.3-70-g09d2 From a88608f33c15a79fecda08e3fddb5bc7690af127 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 3 Mar 2020 21:19:20 -0500 Subject: fixed enumerations a bit. --- src/client/documents/Documents.ts | 1 + src/client/util/RichTextSchema.tsx | 57 ++++++++++------------ .../views/collections/CollectionStackingView.tsx | 2 +- src/new_fields/Doc.ts | 35 ++++--------- .../authentication/models/current_user_utils.ts | 16 +++--- 5 files changed, 44 insertions(+), 67 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6b25b3897..b06ff5465 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -108,6 +108,7 @@ export interface DocumentOptions { _backgroundColor?: string | ScriptField; // background color for each template layout doc ( overrides backgroundColor ) color?: string; // foreground color data doc _color?: string; // foreground color for each template layout doc (overrides color) + caption?: RichTextField; ignoreClick?: boolean; lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 2c3714310..649908317 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -887,32 +887,10 @@ export class DashFieldView { this._enumerables.onpointerdown = async (e) => { e.stopPropagation(); - const collview = await Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); + const collview = await Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]); collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"); } - - this._fieldSpan = document.createElement("div"); - this._fieldSpan.id = Utils.GenerateGuid(); - this._fieldSpan.contentEditable = "true"; - this._fieldSpan.style.position = "relative"; - this._fieldSpan.style.display = "inline-block"; - this._fieldSpan.style.minWidth = "5px"; - this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; - this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; - this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; - this._fieldSpan.onmousedown = function (e: any) { - e.stopPropagation(); - self._enumerables.style.display = "inline-block"; - }; - this._fieldSpan.oncontextmenu = function (e: any) { - ContextMenu.Instance.addItem({ - description: "Show Enumeration Templates", event: () => { - e.stopPropagation(); - DocServer.GetRefField(node.attrs.fieldKey).then(collview => collview instanceof Doc && tbox.props.addDocTab(collview, "onRight")); - }, icon: "expand-arrows-alt" - }); - }; - this._fieldSpan.onblur = function (e: any) { + const updateText = (forceMatch: boolean) => { self._enumerables.style.display = "none"; let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; @@ -920,8 +898,12 @@ export class DashFieldView { // holds the different enumerated values for the field in the titles of its collected documents. // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. DocServer.GetRefField(node.attrs.fieldKey).then(options => { - (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title))); - self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText; + let modText = ""; + (options instanceof Doc) && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title))); + if (modText) { + self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = modText; + Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, []); + } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) { @@ -930,10 +912,22 @@ export class DashFieldView { }); } + this._fieldSpan = document.createElement("div"); + this._fieldSpan.id = Utils.GenerateGuid(); + this._fieldSpan.contentEditable = "true"; + this._fieldSpan.style.position = "relative"; + this._fieldSpan.style.display = "inline-block"; + this._fieldSpan.style.minWidth = "5px"; + this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; + this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; + this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; + this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); self._enumerables.style.display = "inline-block"; }; + this._fieldSpan.onblur = function (e: any) { updateText(false); } + const setDashDoc = (doc: Doc) => { self._dashDoc = doc; - if (this._dashDoc && self._options?.length && !this._dashDoc[node.attrs.fieldKey]) { - this._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title); + if (self._dashDoc && self._options?.length && !self._dashDoc[node.attrs.fieldKey]) { + self._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title); } } this._fieldSpan.onkeydown = function (e: any) { @@ -949,10 +943,8 @@ export class DashFieldView { } if (e.key === "Enter") { e.preventDefault(); - if (e.ctrlKey) { - Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); - } - self._fieldSpan.onblur?.(undefined as any); + e.ctrlKey && Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]); + updateText(true); } }; @@ -997,6 +989,7 @@ export class DashFieldView { this._fieldWrapper.appendChild(this._fieldSpan); this._fieldWrapper.appendChild(this._enumerables); (this as any).dom = this._fieldWrapper; + updateText(false); } destroy() { this._reactionDisposer?.(); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index f84b0af20..3f7f0a352 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -341,7 +341,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (value && this.sectionHeaders) { const schemaHdrField = new SchemaHeaderField(value); this.sectionHeaders.push(schemaHdrField); - Doc.addEnumerationToTextField(undefined, this.pivotField, [Docs.Create.TextDocument(value, { title: value, _backgroundColor: schemaHdrField.color })]); + Doc.addFieldEnumerations(undefined, this.pivotField, [{ title: value, _backgroundColor: schemaHdrField.color }]); return true; } return false; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 6d94f050c..ce69d95b7 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -847,40 +847,23 @@ export namespace Doc { return id; } - // setup a document to use enumerated values for a specified field name: - // doc: text document - // layoutString: species which text field receives the document's main text (e.g., FormattedTextBox.LayoutString("Todo") ) - // enumeratedFieldKey : specifies which enumerated field of the document is displayed in the caption (e.g., taskStatus) - // captionKey: specifies which field holds the caption template (e.g., caption) -- ideally this wouldn't be needed but would be derived from the layoutString's target field key - // - export function enumeratedTextTemplate(doc: Doc, layoutString: string, enumeratedFieldKey: string, enumeratedDocs: Doc[], captionKey: string = "caption") { - doc.caption = RichTextField.DashField(enumeratedFieldKey); - doc._showCaption = captionKey; - doc.layout = layoutString; - - Doc.addEnumerationToTextField(doc, enumeratedFieldKey, enumeratedDocs); - } - - export async function getEnumerationTextField(enumeratedFieldKey: string) { - return (await DocServer.GetRefField(enumeratedFieldKey)) as Doc; - } - - export async function addEnumerationToTextField(doc: Opt, enumeratedFieldKey: string, enumeratedDocs: Doc[]) { + export async function addFieldEnumerations(doc: Opt, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) { let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey); if (!(optionsCollection instanceof Doc)) { optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey); Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); } const options = optionsCollection as Doc; - doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options })); - doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options })); - enumeratedDocs.map(enumeratedDoc => { - const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title); + const targetDoc = doc && Doc.GetProto(Cast(doc.expandedTemplate, Doc, null) || doc); + targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"])?._backgroundColor || "white"`, undefined, { options })); + targetDoc && (targetDoc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"]).color || "black"`, undefined, { options })); + enumerations.map(enumeration => { + const found = DocListCast(options.data).find(d => d.title === enumeration.title); if (found) { - found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor; - found._color = enumeratedDoc._color || found._color; + found._backgroundColor = enumeration._backgroundColor || found._backgroundColor; + found._color = enumeration.color || found._color; } else { - Doc.AddDocToList(options, "data", enumeratedDoc); + Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, enumeration)); } }); return optionsCollection; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 0f8d8fec8..f672da085 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -37,20 +37,20 @@ export class CurrentUserUtils { @observable public static GuestMobile: Doc | undefined; static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) { - const taskStatusValues = [ - Docs.Create.TextDocument("todo", { title: "todo", _backgroundColor: "blue", color: "white" }), - Docs.Create.TextDocument("in progress", { title: "in progress", _backgroundColor: "yellow", color: "black" }), - Docs.Create.TextDocument("completed", { title: "completed", _backgroundColor: "green", color: "white" }) + const taskStatusValues = [ { title: "todo", _backgroundColor: "blue", color: "white" }, + { title: "in progress", _backgroundColor: "yellow", color: "black" }, + { title: "completed", _backgroundColor: "green", color: "white" } ]; const noteTemplates = [ Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }), Docs.Create.TextDocument("", { title: "text", style: "Idea", isTemplateDoc: true, backgroundColor: "pink" }), Docs.Create.TextDocument("", { title: "text", style: "Topic", isTemplateDoc: true, backgroundColor: "lightBlue" }), Docs.Create.TextDocument("", { title: "text", style: "Person", isTemplateDoc: true, backgroundColor: "lightGreen" }), - Docs.Create.TextDocument("", { title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption" }) + Docs.Create.TextDocument("", { title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange",_autoHeight: false, + layout:FormattedTextBox.LayoutString("Todo"), _height: 100, _showCaption: "caption",caption: RichTextField.DashField("taskStatus") }) ]; doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); - Doc.enumeratedTextTemplate(Doc.GetProto(noteTemplates[4]), FormattedTextBox.LayoutString("Todo"), "taskStatus", taskStatusValues); + Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues); doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Types", _height: 75 })); } @@ -268,9 +268,9 @@ export class CurrentUserUtils { ], { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false }); slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); - const descriptionTemplate = Docs.Create.TextDocument("", { title: "descriptionView", _height: 100, _showTitle: "title" }); + const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" }); Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); - descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate); + descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); Doc.GetProto(iconDoc).data = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); -- cgit v1.2.3-70-g09d2 From 85a95c5fdb5e34461ae9892b4f1cac426b7d667b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 4 Mar 2020 01:08:44 -0500 Subject: fixed some template stuff broken when changing data->text. fixed dashFieldViews --- src/client/util/DropConverter.ts | 2 +- src/client/util/RichTextSchema.tsx | 14 +++++++++----- src/new_fields/Doc.ts | 14 ++++++++------ 3 files changed, 18 insertions(+), 12 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 393e39687..861cde5de 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -41,7 +41,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { data && data.draggedDocuments.map((doc, i) => { let dbox = doc; // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant - if (!doc.onDragStart && !doc.onClick && !doc.isButtonBar) { + if (!doc.onDragStart && !doc.isButtonBar) { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; if (layoutDoc.type === DocumentType.COL || layoutDoc.type === DocumentType.TEXT || layoutDoc.type === DocumentType.IMG) { !layoutDoc.isTemplateDoc && makeTemplate(layoutDoc); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 649908317..a854406f4 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -892,7 +892,7 @@ export class DashFieldView { } const updateText = (forceMatch: boolean) => { self._enumerables.style.display = "none"; - let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; + let newText = self._fieldSpan.innerText.startsWith(":=") || self._fieldSpan.innerText.startsWith("=:=") ? ":=-computed-" : self._fieldSpan.innerText; // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. @@ -903,11 +903,15 @@ export class DashFieldView { if (modText) { self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = modText; Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, []); + } else if (!self._fieldSpan.innerText.startsWith(":=") && !self._fieldSpan.innerText.startsWith("=:=")) { + self._dashDoc![self._fieldKey] = newText; } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key - if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) { - Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); + if (self._fieldSpan.innerText.startsWith(":=") && self._dashDoc) { + self._dashDoc![self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); + } else if (self._fieldSpan.innerText.startsWith("=:=") && self._dashDoc) { + Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(3)); } }); } @@ -917,7 +921,7 @@ export class DashFieldView { this._fieldSpan.contentEditable = "true"; this._fieldSpan.style.position = "relative"; this._fieldSpan.style.display = "inline-block"; - this._fieldSpan.style.minWidth = "5px"; + this._fieldSpan.style.minWidth = "12px"; this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; @@ -983,7 +987,7 @@ export class DashFieldView { this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes const dashVal = this._dashDoc?.[node.attrs.fieldKey]; return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[this._fieldKey] : dashVal; - }, fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "(null)", { fireImmediately: true }); + }, fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "", { fireImmediately: true }); this._fieldWrapper.appendChild(this._labelSpan); this._fieldWrapper.appendChild(this._fieldSpan); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index ce69d95b7..e9fdf42b9 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -7,7 +7,7 @@ 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 { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update } from "./FieldSymbols"; +import { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update, Copy } from "./FieldSymbols"; import { List } from "./List"; import { ObjectField } from "./ObjectField"; import { PrefetchProxy, ProxyField } from "./Proxy"; @@ -15,7 +15,7 @@ import { FieldId, RefField } from "./RefField"; import { RichTextField } from "./RichTextField"; import { listSpec } from "./Schema"; import { ComputedField } from "./ScriptField"; -import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; +import { Cast, FieldValue, NumCast, StrCast, ToConstructor, ScriptCast } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; import { Docs } from "../client/documents/Documents"; @@ -574,7 +574,7 @@ export namespace Doc { let _applyCount: number = 0; export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { - const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), "layout", templateDoc.title + "(..." + _applyCount++ + ")"); + const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), StrCast(templateDoc.layoutKey, "layout"), templateDoc.title + "(..." + _applyCount++ + ")"); applied && (Doc.GetProto(applied).type = templateDoc.type); return applied; } @@ -585,8 +585,8 @@ export namespace Doc { target.layout = undefined; target._nativeWidth = undefined; target._nativeHeight = undefined; - target.onClick = undefined; target.type = undefined; + target.onClick = undefined; return; } @@ -597,6 +597,8 @@ export namespace Doc { titleTarget && (Doc.GetProto(target).title = titleTarget); Doc.GetProto(target)[targetKey] = new PrefetchProxy(templateDoc); } + const scriptField = ScriptCast(templateDoc.onClick); + scriptField && (target.onClick = scriptField[Copy]()); } target.layoutKey = targetKey; return target; @@ -615,7 +617,7 @@ export namespace Doc { templateField.isTemplateForField = metadataFieldKey; templateField.title = metadataFieldKey; - const templateFieldValue = templateField[metadataFieldKey] || templateField.data; + const templateFieldValue = templateField[metadataFieldKey] || templateField[Doc.LayoutFieldKey(templateField)]; const templateCaptionValue = templateField.caption; // move any data that the template field had been rendering over to the template doc so that things will still be rendered // when the template field is adjusted to point to the new metadatafield key. @@ -635,7 +637,7 @@ export namespace Doc { // get the layout string that the template uses to specify its layout const templateFieldLayoutString = StrCast(Doc.LayoutField(Doc.Layout(templateField))); - // change itto render the target metadata field instead of what it was rendering before and assign it to the template field layout document. + // change it to render the target metadata field instead of what it was rendering before and assign it to the template field layout document. Doc.Layout(templateField).layout = templateFieldLayoutString.replace(/fieldKey={'[^']*'}/, `fieldKey={'${metadataFieldKey}'}`); // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino) -- cgit v1.2.3-70-g09d2 From 26c973ecb47de86d94c39d71ad00ece38a85d623 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 4 Mar 2020 18:20:46 -0500 Subject: changed text sampling to marking every second to get audio to synchronize better --- src/client/util/InteractionUtils.tsx | 1 - src/client/util/RichTextSchema.tsx | 4 +- src/client/views/nodes/AudioBox.scss | 2 + src/client/views/nodes/AudioBox.tsx | 66 +++++++++++++++------- src/client/views/nodes/FormattedTextBox.tsx | 85 ++++++++++++++++++++--------- src/client/views/nodes/PresBox.tsx | 3 +- src/new_fields/Doc.ts | 1 + 7 files changed, 112 insertions(+), 50 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index cf51b8e89..2eec02a42 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -108,7 +108,6 @@ export namespace InteractionUtils { } export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean { - console.log(e.button); switch (type) { // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2 case PENTYPE: diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a854406f4..0adf060ec 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -511,7 +511,7 @@ export const marks: { [index: string]: MarkSpec } = { user_mark: { attrs: { userid: { default: "" }, - modified: { default: "when?" }, // 5 second intervals since 1970 + modified: { default: "when?" }, // 1 second intervals since 1970 }, group: "inline", toDOM(node: any) { @@ -527,7 +527,7 @@ export const marks: { [index: string]: MarkSpec } = { user_tag: { attrs: { userid: { default: "" }, - modified: { default: "when?" }, // 5 second intervals since 1970 + modified: { default: "when?" }, // 1 second intervals since 1970 tag: { default: "" } }, group: "inline", diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 4516418a7..83cdf3574 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -29,6 +29,8 @@ } .audiobox-record-interactive { pointer-events: all; + width:100%; + height:100%; } .audiobox-controls { width:100%; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index c4c6365e3..e2002a596 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -17,6 +17,8 @@ import { ContextMenu } from "../ContextMenu"; import { Id } from "../../../new_fields/FieldSymbols"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { DocumentView } from "./DocumentView"; +import { Docs } from "../../documents/Documents"; +import { ComputedField } from "../../../new_fields/ScriptField"; interface Window { MediaRecorder: MediaRecorder; @@ -45,12 +47,15 @@ export class AudioBox extends DocExtendableComponent AudioBox._scrubTime = timeInMillisFrom1970); + @computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); } + set audioState(value) { this.dataDoc.audioState = value; } + public static SetScrubTime = (timeInMillisFrom1970: number) => { runInAction(() => AudioBox._scrubTime = 0); runInAction(() => AudioBox._scrubTime = timeInMillisFrom1970); }; public static ActiveRecordings: Doc[] = []; @computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); } + async slideTemplate() { return (await Cast((await Cast(Doc.UserDoc().slidesBtn, Doc) as Doc).dragFactory, Doc) as Doc); } componentWillUnmount() { this._reactionDisposer?.(); @@ -58,7 +63,7 @@ export class AudioBox extends DocExtendableComponent this._audioState = this.path ? "recorded" : "unrecorded"); + runInAction(() => this.audioState = this.path ? "paused" : undefined); this._linkPlayDisposer = reaction(() => this.layoutDoc.scrollToLinkID, scrollLinkId => { if (scrollLinkId) { @@ -73,13 +78,14 @@ export class AudioBox extends DocExtendableComponent { const sel = selected.length ? selected[0].props.Document : undefined; this.Document.playOnSelect && this.recordingStart && sel && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime()); + this.Document.playOnSelect && this.recordingStart && !sel && this.pause(); }); this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.Document.playOnSelect && this.playFromTime(AudioBox._scrubTime)); } timecodeChanged = () => { const htmlEle = this._ele; - if (this._audioState === "recorded" && htmlEle) { + if (this.audioState !== "recording" && htmlEle) { htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration); DocListCast(this.dataDoc.links).map(l => { let la1 = l.anchor1 as Doc; @@ -98,7 +104,7 @@ export class AudioBox extends DocExtendableComponent { this._ele!.pause(); - this.props.Document._audioState = "paused"; + this.audioState = "paused"; }); playFromTime = (absoluteTime: number) => { @@ -107,11 +113,15 @@ export class AudioBox extends DocExtendableComponent { if (this._ele && AudioBox.Enabled) { if (seekTimeInSeconds < 0) { - this.pause(); + if (seekTimeInSeconds > -1) { + setTimeout(() => this.playFrom(0), -seekTimeInSeconds * 1000); + } else { + this.pause(); + } } else if (seekTimeInSeconds <= this._ele.duration) { this._ele.currentTime = seekTimeInSeconds; this._ele.play(); - runInAction(() => this.props.Document._audioState = "playing"); + runInAction(() => this.audioState = "playing"); } else { this.pause(); } @@ -120,7 +130,7 @@ export class AudioBox extends DocExtendableComponent { - if (this._audioState === "recording") { + if (this.audioState === "recording") { setTimeout(this.updateRecordTime, 30); this.Document.currentTimecode = (new Date().getTime() - this._recordStart) / 1000; } @@ -135,6 +145,7 @@ export class AudioBox extends DocExtendableComponent self._audioState = "recording"); self._recordStart = new Date().getTime(); + console.log("RECORD START = " + self._recordStart); + runInAction(() => self.audioState = "recording"); setTimeout(self.updateRecordTime, 0); self._recorder.start(); setTimeout(() => { @@ -172,7 +184,7 @@ export class AudioBox extends DocExtendableComponent { this._recorder.stop(); this.dataDoc.duration = (new Date().getTime() - this._recordStart) / 1000; - this._audioState = "recorded"; + this.audioState = "paused"; const ind = AudioBox.ActiveRecordings.indexOf(this.props.Document); ind !== -1 && (AudioBox.ActiveRecordings.splice(ind, 1)); }); @@ -189,8 +201,19 @@ export class AudioBox extends DocExtendableComponent { - this.pause(); - this._ele!.currentTime = 0; + this.Document.playOnSelect = !this.Document.playOnSelect; + e.stopPropagation(); + } + onFile = (e: any) => { + const newDoc = Docs.Create.TextDocument("", { + title: "", _chromeStatus: "disabled", + x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document._height) + 10, + _width: NumCast(this.props.Document._width), _height: 3 * NumCast(this.props.Document._height) + }); + Doc.GetProto(newDoc).recordingSource = this.dataDoc; + Doc.GetProto(newDoc).recordingStart = 0; + Doc.GetProto(newDoc).audioState = ComputedField.MakeFunction("this.recordingSource.audioState"); + this.props.addDocument?.(newDoc); e.stopPropagation(); } @@ -218,21 +241,26 @@ export class AudioBox extends DocExtendableComponent -
{!this.path ? - : +
+
+ +
+ +
:
-
-
+
+
e.stopPropagation()} onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { const rect = (e.target as any).getBoundingClientRect(); + const wasPaused = this.audioState === "paused"; this._ele!.currentTime = this.Document.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); - this.pause(); + wasPaused && this.pause(); e.stopPropagation(); } }} > diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8f4cefbf4..f18183600 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -20,7 +20,7 @@ import { InkTool } from '../../../new_fields/InkField'; import { RichTextField } from "../../../new_fields/RichTextField"; import { RichTextUtils } from '../../../new_fields/RichTextUtils'; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { TraceMobx } from '../../../new_fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils } from '../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils'; @@ -82,6 +82,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & private _lastY = 0; private _undoTyping?: UndoManager.Batch; private _searchReactionDisposer?: Lambda; + private _recordReactionDisposer: Opt; private _scrollToRegionReactionDisposer: Opt; private _reactionDisposer: Opt; private _heightReactionDisposer: Opt; @@ -92,6 +93,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & private _scrollDisposer: Opt; private dropDisposer?: DragManager.DragDropDisposer; + @computed get _recording() { return this.dataDoc.audioState === "recording"; } + set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; } + @observable private _entered = false; public static FocusedBox: FormattedTextBox | undefined; @@ -186,7 +190,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & (tx.storedMarks && !this._editorView.state.storedMarks) && (this._editorView.state.storedMarks = tx.storedMarks); 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 * 5000 - 1000))); + 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\n"); const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField); if (!this._applyingChange) { @@ -387,7 +391,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & !this.props.Document.expandedTemplate && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = true; Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); }, 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: "Record Bullet", event: () => this.recordBullet(), icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ @@ -405,12 +409,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: funcs, icon: "asterisk" }); } - @observable _recording = false; - recordDictation = () => { - //this._editorView!.focus(); - if (this._recording) return; - runInAction(() => this._recording = true); DictationManager.Controls.listen({ interimHandler: this.setCurrentBulletContent, continuous: { indefinite: false }, @@ -418,13 +417,10 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & if (results && [DictationManager.Controls.Infringed].includes(results)) { DictationManager.Controls.stop(); } - this._editorView!.focus(); + //this._editorView!.focus(); }); } - stopDictation = (abort: boolean) => { - runInAction(() => this._recording = false); - DictationManager.Controls.stop(!abort); - } + stopDictation = (abort: boolean) => { DictationManager.Controls.stop(!abort); } @action toggleMenubar = () => { @@ -449,12 +445,28 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & setCurrentBulletContent = (value: string) => { if (this._editorView) { let state = this._editorView.state; + let now = Date.now(); + if (NumCast(this.props.Document.recordingStart, -1) === 0) { + this.props.Document.recordingStart = now = AudioBox.START; + } + console.log("NOW = " + (now - AudioBox.START) / 1000); + let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) }); + if (!this._break && state.selection.to !== state.selection.from) { + for (let i = state.selection.from; i <= state.selection.to; i++) { + const pos = state.doc.resolve(i); + const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark); + if (um) { + mark = um; + break; + } + } + } + this._break = false; + console.log("start = " + (mark.attrs.modified * 1000 - AudioBox.START) / 1000); + value = "" + (mark.attrs.modified * 1000 - AudioBox.START) / 1000 + value; const from = state.selection.from; - const to = state.selection.to; - this._editorView.dispatch(state.tr.insertText(value, from, to)); - state = this._editorView.state; - const updated = TextSelection.create(state.doc, from, from + value.length); - this._editorView.dispatch(state.tr.setSelection(updated)); + const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark); + this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1))); } } @@ -558,6 +570,17 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(), { fireImmediately: true }); + this._recordReactionDisposer = reaction(() => this._recording, + () => { + if (this._recording) { + setTimeout(action(() => { + this.stopDictation(true); + setTimeout(() => this.recordDictation(), 500); + }), 500); + } else setTimeout(() => this.stopDictation(true), 0); + } + ); + this._scrollToRegionReactionDisposer = reaction( () => StrCast(this.layoutDoc.scrollToLinkID), async (scrollToLinkID) => { @@ -807,7 +830,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } (selectOnLoad /* || !rtfField?.Text*/) && this._editorView!.focus(); // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet. - this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.round(Date.now() / 1000 / 5) })]; + this._editorView!.state.storedMarks = [...(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) { @@ -831,6 +854,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this._pullReactionDisposer?.(); this._heightReactionDisposer?.(); this._searchReactionDisposer?.(); + this._recordReactionDisposer?.(); this._buttonBarReactionDisposer?.(); this._editorView?.destroy(); } @@ -838,7 +862,19 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & static _downEvent: any; _downX = 0; _downY = 0; + _break = false; onPointerDown = (e: React.PointerEvent): void => { + if (this._recording && !e.ctrlKey && e.button === 0) { + this.stopDictation(true); + this._break = true; + let state = this._editorView!.state; + const to = state.selection.to; + const updated = TextSelection.create(state.doc, to, to); + this._editorView!.dispatch(this._editorView!.state.tr.setSelection(updated).insertText("\n", to)); + e.preventDefault(); + e.stopPropagation(); + if (this._recording) setTimeout(() => this.recordDictation(), 500); + } this._downX = e.clientX; this._downY = e.clientY; this.doLinkOnDeselect(); @@ -955,7 +991,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this.props.select(e.ctrlKey); this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); } - if (this._recording) setTimeout(() => { this.stopDictation(true); setTimeout(() => this.recordDictation(), 500); }, 500); } // 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. @@ -1062,17 +1097,13 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & if (e.key === "Tab" || e.key === "Enter") { e.preventDefault(); } - const mark = e.key !== " " && this._lastTimedMark ? this._lastTimedMark : schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.round(Date.now() / 1000 / 5) }); + const mark = e.key !== " " && this._lastTimedMark ? this._lastTimedMark : schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }); this._lastTimedMark = mark; this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark)); if (!this._undoTyping) { this._undoTyping = UndoManager.StartBatch("undoTyping"); } - if (this._recording) { - this.stopDictation(true); - setTimeout(() => this.recordDictation(), 250); - } } onscrolled = (ev: React.UIEvent) => { @@ -1169,8 +1200,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
} {!this.props.Document._showAudio ? (null) :
{ - this._recording ? this.stopDictation(true) : this.recordDictation(); + onPointerDown={e => { + runInAction(() => this._recording = !this._recording); setTimeout(() => this._editorView!.focus(), 500); e.stopPropagation(); }} > diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 27c2d6957..d43df0bfb 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons'; +import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faHandPointLeft, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -24,6 +24,7 @@ library.add(faArrowLeft); library.add(faArrowRight); library.add(faPlay); library.add(faStop); +library.add(faHandPointLeft); library.add(faPlus); library.add(faTimes); library.add(faMinus); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index e9fdf42b9..141a01ed2 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -859,6 +859,7 @@ export namespace Doc { const targetDoc = doc && Doc.GetProto(Cast(doc.expandedTemplate, Doc, null) || doc); targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"])?._backgroundColor || "white"`, undefined, { options })); targetDoc && (targetDoc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"]).color || "black"`, undefined, { options })); + targetDoc && (targetDoc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"]).borderRounding`, undefined, { options })); enumerations.map(enumeration => { const found = DocListCast(options.data).find(d => d.title === enumeration.title); if (found) { -- cgit v1.2.3-70-g09d2 From 636e6880a52d3a1a3e24437f47194a902731401d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 9 Mar 2020 16:39:42 -0400 Subject: cleanup of warnings --- src/client/cognitive_services/CognitiveServices.ts | 8 ++++---- src/client/util/DocumentManager.ts | 2 +- src/client/util/DragManager.ts | 2 +- src/client/util/ProsemirrorExampleTransfer.ts | 2 +- src/client/util/RichTextSchema.tsx | 14 +++++++------- src/client/util/SearchUtil.ts | 4 ++-- src/client/views/KeyphraseQueryView.tsx | 4 ++-- .../views/collections/CollectionDockingView.tsx | 4 ++-- src/client/views/collections/CollectionSubView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 2 +- src/client/views/linking/LinkEditor.tsx | 4 ++-- src/client/views/nodes/AudioBox.tsx | 6 ++---- src/client/views/nodes/DocuLinkBox.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 14 +++++++------- src/client/views/nodes/FormattedTextBox.tsx | 20 ++++++++------------ src/client/views/nodes/PDFBox.tsx | 10 +++++----- 17 files changed, 49 insertions(+), 55 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index ce829eb1e..542ccf04d 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -371,9 +371,9 @@ export namespace CognitiveServices { let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true }; await requestPromise.post(args).then(async (wordvecs) => { if (wordvecs) { - let indices = Object.keys(wordvecs); + const indices = Object.keys(wordvecs); console.log("successful vectorization!"); - var vectorValues = new List(); + const vectorValues = new List(); indices.forEach((ind: any) => { //console.log(wordvec.word); vectorValues.push(wordvecs[ind]); @@ -389,9 +389,9 @@ export namespace CognitiveServices { } export const analyzer = async (dataDoc: Doc, target: Doc, keys: string[], data: string, converter: TextConverter, isMainDoc: boolean = false, isInternal: boolean = true) => { - let results = await ExecuteQuery(Service.Text, Manager, data); + const results = await ExecuteQuery(Service.Text, Manager, data); console.log("Cognitive Services keyphrases: ", results); - let { keyterms, external_recommendations, kp_string } = await converter(results, data); + const { keyterms, external_recommendations, kp_string } = await converter(results, data); target[keys[0]] = keyterms; if (isInternal) { //await vectorize([data], dataDoc, isMainDoc); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 162a8fffe..c41304b9f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -209,7 +209,7 @@ export class DocumentManager { const maxLocation = StrCast(linkDoc.maximizeLocation, "inTab"); const targetContext = !Doc.AreProtosEqual(linkFollowDocContexts[reverse ? 1 : 0], currentContext) ? linkFollowDocContexts[reverse ? 1 : 0] : undefined; const target = linkFollowDocs[reverse ? 1 : 0]; - let annotatedDoc = await Cast(target.annotationOn, Doc); + const annotatedDoc = await Cast(target.annotationOn, Doc); if (annotatedDoc) { annotatedDoc.currentTimecode !== undefined && (target.currentTimecode = linkFollowTimecodes[reverse ? 1 : 0]); } else { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index dab5c842c..c11675894 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -198,7 +198,7 @@ export namespace DragManager { dropDoc && !dropDoc.creationDate && (dropDoc.creationDate = new DateField); dropDoc instanceof Doc && AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: dropDoc }, { doc: d }, "audio link", "audio timeline")); return dropDoc; - } + }; const finishDrag = (e: DragCompleteEvent) => { e.docDragData && (e.docDragData.droppedDocuments = dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index ec5d1e72a..5cbf401d4 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -180,7 +180,7 @@ export default function buildKeymap>(schema: S, props: any return true; } return false; - } + }; bind("Alt-Enter", (state: EditorState, dispatch: (tx: Transaction>) => void) => { return addTextOnRight(true); }); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 0adf060ec..31935df3e 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -889,10 +889,10 @@ export class DashFieldView { e.stopPropagation(); const collview = await Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]); collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"); - } + }; const updateText = (forceMatch: boolean) => { self._enumerables.style.display = "none"; - let newText = self._fieldSpan.innerText.startsWith(":=") || self._fieldSpan.innerText.startsWith("=:=") ? ":=-computed-" : self._fieldSpan.innerText; + const newText = self._fieldSpan.innerText.startsWith(":=") || self._fieldSpan.innerText.startsWith("=:=") ? ":=-computed-" : self._fieldSpan.innerText; // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. @@ -909,12 +909,12 @@ export class DashFieldView { // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key if (self._fieldSpan.innerText.startsWith(":=") && self._dashDoc) { - self._dashDoc![self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); + self._dashDoc[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); } else if (self._fieldSpan.innerText.startsWith("=:=") && self._dashDoc) { Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(3)); } }); - } + }; this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); @@ -926,14 +926,14 @@ export class DashFieldView { this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); self._enumerables.style.display = "inline-block"; }; - this._fieldSpan.onblur = function (e: any) { updateText(false); } + this._fieldSpan.onblur = function (e: any) { updateText(false); }; const setDashDoc = (doc: Doc) => { self._dashDoc = doc; if (self._dashDoc && self._options?.length && !self._dashDoc[node.attrs.fieldKey]) { self._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title); } - } + }; this._fieldSpan.onkeydown = function (e: any) { e.stopPropagation(); if ((e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { @@ -976,7 +976,7 @@ export class DashFieldView { alias._pivotField = self._fieldKey; tbox.props.addDocTab(alias, "onRight"); } - } + }; this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `; if (node.attrs.docid) { DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && runInAction(() => setDashDoc(dashDoc))); diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 64874b994..2d9c807dd 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -121,12 +121,12 @@ export namespace SearchUtil { export async function GetAllDocs() { const query = "*"; - let response = await rp.get(Utils.prepend('/search'), { + const response = await rp.get(Utils.prepend('/search'), { qs: { start: 0, rows: 10000, q: query }, }); - let result: IdSearchResult = JSON.parse(response); + const result: IdSearchResult = JSON.parse(response); const { ids, numFound, highlighting } = result; //console.log(ids.length); const docMap = await DocServer.GetRefFields(ids); diff --git a/src/client/views/KeyphraseQueryView.tsx b/src/client/views/KeyphraseQueryView.tsx index a9dafc4a4..1dc156968 100644 --- a/src/client/views/KeyphraseQueryView.tsx +++ b/src/client/views/KeyphraseQueryView.tsx @@ -15,8 +15,8 @@ export class KeyphraseQueryView extends React.Component{ } render() { - let kps = this.props.keyphrases.toString(); - let keyterms = this.props.keyphrases.split(','); + const kps = this.props.keyphrases.toString(); + const keyterms = this.props.keyphrases.split(','); return (
Select queries to send:
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index db8f7d5e4..00e22d6fb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -138,8 +138,8 @@ export class CollectionDockingView extends React.Component Array.from(child.contentItems).some(tryClose)); retVal && instance.stateChanged(); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 527623ad4..b995fc7d5 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -107,7 +107,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get childLayoutPairs(): { layout: Doc; data: Doc; }[] { const { Document, DataDoc } = this.props; const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout); - return validPairs.map(({ data, layout }) => ({ data: data!, layout: layout! })); // this mapping is a bit of a hack to coerce types + return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types } get childDocList() { return Cast(this.dataField, listSpec(Doc)); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 28f8bc048..7adafea0e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -801,7 +801,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.props.Document.scrollY = NumCast(doc.y) - offset; } - afterFocus && setTimeout(() => afterFocus?.(), 1000); + afterFocus && setTimeout(afterFocus, 1000); } else { const layoutdoc = Doc.Layout(doc); const newPanX = NumCast(doc.x) + NumCast(layoutdoc._width) / 2; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index bd20781dc..aa8e1fb43 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -223,7 +223,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu */ @computed private get contents(): JSX.Element[] | null { - let { childLayoutPairs } = this; + const { childLayoutPairs } = this; const { Document, PanelHeight } = this.props; const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index ac4f8a3cf..b7f3dd995 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -253,8 +253,8 @@ export class LinkGroupEditor extends React.Component { render() { const groupType = StrCast(this.props.groupDoc.linkRelationship); // if ((groupType && LinkManager.Instance.getMetadataKeysInGroup(groupType).length > 0) || groupType === "") { - let buttons = ; - let addButton = ; + const buttons = ; + const addButton = ; return (
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 3c8b1c3b8..47883db4e 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -50,7 +50,6 @@ export class AudioBox extends DocExtendableComponent(Doc openLinkEditor = action((e: React.MouseEvent) => { SelectionManager.DeselectAll(); this._editing = this._forceOpen = true; - }) + }); specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; @@ -135,7 +135,7 @@ export class DocuLinkBox extends DocComponent(Doc const targetTitle = StrCast((this.props.Document[anchor]! as Doc).title) + (timecode !== undefined ? ":" + timecode : ""); const flyout = (
Doc.UnBrushDoc(this.props.Document)}> - { })} /> + { })} /> {!this._forceOpen ? (null) :
this._isOpen = this._editing = this._forceOpen = false)}>
} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 63c6b9f88..a1cba4c2e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -571,9 +571,9 @@ export class DocumentView extends DocComponent(Docu else if (de.complete.docDragData.draggedDocuments[0].type === "text") { const text = Cast(de.complete.docDragData.draggedDocuments[0].data, RichTextField)?.Text; if (text && text[0] === "{" && text[text.length - 1] === "}" && text.includes(":")) { - let loc = text.indexOf(":"); - let key = text.slice(1, loc); - let value = text.slice(loc + 1, text.length - 1); + const loc = text.indexOf(":"); + const key = text.slice(1, loc); + const value = text.slice(loc + 1, text.length - 1); console.log(key); console.log(value); console.log(this.props.Document); @@ -756,7 +756,7 @@ export class DocumentView extends DocComponent(Docu // a.download = `DocExport-${this.props.Document[Id]}.zip`; // a.click(); }); - let recommender_subitems: ContextMenuProps[] = []; + const recommender_subitems: ContextMenuProps[] = []; recommender_subitems.push({ description: "Internal recommendations", @@ -764,7 +764,7 @@ export class DocumentView extends DocComponent(Docu icon: "brain" }); - let ext_recommender_subitems: ContextMenuProps[] = []; + const ext_recommender_subitems: ContextMenuProps[] = []; ext_recommender_subitems.push({ description: "arXiv", @@ -872,7 +872,7 @@ export class DocumentView extends DocComponent(Docu } })); const doclist = ClientRecommender.Instance.computeSimilarities("cosine"); - let recDocs: { preview: Doc, score: number }[] = []; + const recDocs: { preview: Doc, score: number }[] = []; // tslint:disable-next-line: prefer-for-of for (let i = 0; i < doclist.length; i++) { recDocs.push({ preview: doclist[i].actualDoc, score: doclist[i].score }); @@ -1113,7 +1113,7 @@ export class DocumentView extends DocComponent(Docu : this.innards}
; - { this._showKPQuery ? : undefined } + { this._showKPQuery ? : undefined; } } } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7f5f8538a..1fa603cbd 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -20,7 +20,7 @@ import { InkTool } from '../../../new_fields/InkField'; import { RichTextField } from "../../../new_fields/RichTextField"; import { RichTextUtils } from '../../../new_fields/RichTextUtils'; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; +import { Cast, NumCast, StrCast, BoolCast, DateCast } from "../../../new_fields/Types"; import { TraceMobx } from '../../../new_fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue } from '../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils'; @@ -420,11 +420,11 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & //this._editorView!.focus(); }); } - stopDictation = (abort: boolean) => { DictationManager.Controls.stop(!abort); } + stopDictation = (abort: boolean) => { DictationManager.Controls.stop(!abort); }; @action toggleMenubar = () => { - this.props.Document._chromeStatus = this.props.Document._chromeStatus == "disabled" ? "enabled" : "disabled"; + this.props.Document._chromeStatus = this.props.Document._chromeStatus === "disabled" ? "enabled" : "disabled"; } recordBullet = async () => { @@ -444,12 +444,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & setCurrentBulletContent = (value: string) => { if (this._editorView) { - let state = this._editorView.state; - let now = Date.now(); - if (NumCast(this.props.Document.recordingStart, -1) === 0) { - this.props.Document.recordingStart = now = AudioBox.START; - } - console.log("NOW = " + (now - AudioBox.START) / 1000); + const state = this._editorView.state; + const now = Date.now(); let mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(now / 1000) }); if (!this._break && state.selection.to !== state.selection.from) { for (let i = state.selection.from; i <= state.selection.to; i++) { @@ -461,9 +457,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } } } + const recordingStart = DateCast(this.props.Document.recordingStart).date.getTime(); this._break = false; - console.log("start = " + (mark.attrs.modified * 1000 - AudioBox.START) / 1000); - value = "" + (mark.attrs.modified * 1000 - AudioBox.START) / 1000 + value; + value = "" + (mark.attrs.modified * 1000 - recordingStart) / 1000 + value; const from = state.selection.from; const inserted = state.tr.insertText(value).addMark(from, from + value.length + 1, mark); this._editorView.dispatch(inserted.setSelection(TextSelection.create(inserted.doc, from, from + value.length + 1))); @@ -867,7 +863,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & if (this._recording && !e.ctrlKey && e.button === 0) { this.stopDictation(true); this._break = true; - let state = this._editorView!.state; + const state = this._editorView!.state; const to = state.selection.to; const updated = TextSelection.create(state.doc, to, to); this._editorView!.dispatch(this._editorView!.state.tr.setSelection(updated).insertText("\n", to)); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index f47620c24..4076128b2 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -94,11 +94,11 @@ export class PDFBox extends DocAnnotatableComponent !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); } - public search = (string: string, fwd: boolean) => { this._pdfViewer?.search(string, fwd); } - public prevAnnotation = () => { this._pdfViewer?.prevAnnotation(); } - public nextAnnotation = () => { this._pdfViewer?.nextAnnotation(); } - public backPage = () => { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); } - public forwardPage = () => { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); } + public search = (string: string, fwd: boolean) => { this._pdfViewer?.search(string, fwd); }; + public prevAnnotation = () => { this._pdfViewer?.prevAnnotation(); }; + public nextAnnotation = () => { this._pdfViewer?.nextAnnotation(); }; + public backPage = () => { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); }; + public forwardPage = () => { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); }; public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); }; @undoBatch -- cgit v1.2.3-70-g09d2 From aa8ed99f41a559a19ebea37b22ee1902aab2d6eb Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 27 Mar 2020 13:01:54 -0400 Subject: fixed iconifying doc script removal. fixed metadata to display inline-flex so that value truncates instead of moving to next line. --- src/client/util/RichTextSchema.tsx | 2 +- src/new_fields/Doc.ts | 13 +++++++------ src/server/authentication/models/current_user_utils.ts | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 31935df3e..659d317f6 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -875,7 +875,7 @@ export class DashFieldView { this._fieldWrapper.style.width = node.attrs.width; this._fieldWrapper.style.height = node.attrs.height; this._fieldWrapper.style.position = "relative"; - this._fieldWrapper.style.display = "inline-block"; + this._fieldWrapper.style.display = "inline-flex"; const self = this; this._enumerables = document.createElement("div"); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 322b57272..8447a4e93 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -587,7 +587,6 @@ export namespace Doc { target._nativeWidth = undefined; target._nativeHeight = undefined; target.type = undefined; - target.onClick = undefined; return; } @@ -598,8 +597,6 @@ export namespace Doc { titleTarget && (Doc.GetProto(target).title = titleTarget); Doc.GetProto(target)[targetKey] = new PrefetchProxy(templateDoc); } - const scriptField = ScriptCast(templateDoc.onClick); - scriptField && (target.onClick = scriptField[Copy]()); } target.layoutKey = targetKey; return target; @@ -791,6 +788,10 @@ export namespace Doc { return fieldStr === value; } + export function deiconifyView(doc: any) { + StrCast(doc.layoutKey).split("_")[1] === "icon" && setNativeView(doc); + } + export function setNativeView(doc: any) { const prevLayout = StrCast(doc.layoutKey).split("_")[1]; const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : ""; @@ -813,8 +814,8 @@ export namespace Doc { } } - export function aliasDocs(field:any) { - return new List(field.map((d: any) => Doc.MakeAlias(d))); + export function aliasDocs(field: any) { + return new List(field.map((d: any) => Doc.MakeAlias(d))); } // filters document in a container collection: @@ -890,7 +891,7 @@ Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy Scripting.addGlobal(function aliasDocs(field: any) { return Doc.aliasDocs(field); }); Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); }); -Scripting.addGlobal(function setNativeView(doc: any) { Doc.setNativeView(doc); }); +Scripting.addGlobal(function deiconifyView(doc: any) { Doc.deiconifyView(doc); }); Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 9c39ce7de..cfa13cb44 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -273,14 +273,14 @@ export class CurrentUserUtils { Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); - const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); + const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }); Doc.GetProto(iconDoc).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); doc.isTemplateDoc = makeTemplate(iconDoc); doc.iconView = new PrefetchProxy(iconDoc); - const imgIconDoc = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); + const imgIconDoc = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }); doc.isTemplateDoc = makeTemplate(imgIconDoc, true, "image_icon"); doc.iconImageView = new PrefetchProxy(imgIconDoc); - const colIconDoc = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); + const colIconDoc = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }); doc.isTemplateDoc = makeTemplate(colIconDoc, true, "collection_icon"); doc.iconColView = new PrefetchProxy(colIconDoc); -- cgit v1.2.3-70-g09d2 From 985d34dc993748d4be06a61238f077be84dc9678 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 27 Mar 2020 15:27:17 -0400 Subject: added metadata checkboxes in rich text notes. --- src/client/util/RichTextRules.ts | 2 +- src/client/util/RichTextSchema.tsx | 30 ++++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index e5b20a79b..c588a8d98 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -98,7 +98,7 @@ export class RichTextRules { } return state.tr; } - if (value !== "") { + if (value !== "" && value !== undefined) { this.Document[DataSym][fieldKey] = value; } const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid }); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 659d317f6..44c811b76 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -861,6 +861,7 @@ export class DashFieldView { _fieldWrapper: HTMLDivElement; // container for label and value _labelSpan: HTMLSpanElement; // field label _fieldSpan: HTMLDivElement; // field value + _fieldCheck: HTMLInputElement; _enumerables: HTMLDivElement; // field value _reactionDisposer: IReactionDisposer | undefined; _textBoxDoc: Doc; @@ -916,6 +917,22 @@ export class DashFieldView { }); }; + + this._fieldCheck = document.createElement("input"); + this._fieldCheck.id = Utils.GenerateGuid(); + this._fieldCheck.type = "checkbox"; + this._fieldCheck.style.position = "relative"; + this._fieldCheck.style.display = "inline-block"; + this._fieldCheck.style.minWidth = "12px"; + this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; + this._fieldCheck.onchange = function (e: any) { + // look for a document whose id === the fieldKey being displayed. If there's a match, then that document + // holds the different enumerated values for the field in the titles of its collected documents. + // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. + DocServer.GetRefField(node.attrs.fieldKey).then(options => self._dashDoc![self._fieldKey] = e.target.checked); + } + + this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); this._fieldSpan.contentEditable = "true"; @@ -987,10 +1004,19 @@ export class DashFieldView { this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes const dashVal = this._dashDoc?.[node.attrs.fieldKey]; return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[this._fieldKey] : dashVal; - }, fval => this._fieldSpan.innerHTML = Field.toString(fval as Field) || "", { fireImmediately: true }); + }, fval => { + const boolVal = Cast(fval, "boolean", null); + if (boolVal === true || boolVal === false) { + this._fieldCheck.checked = boolVal; + } else { + this._fieldSpan.innerHTML = Field.toString(fval as Field) || ""; + } + }, { fireImmediately: true }); + const fieldVal = Cast(this._dashDoc?.[node.attrs.fieldKey], "boolean", null); this._fieldWrapper.appendChild(this._labelSpan); - this._fieldWrapper.appendChild(this._fieldSpan); + (fieldVal === true || fieldVal === false) && this._fieldWrapper.appendChild(this._fieldCheck); + !(fieldVal === true || fieldVal === false) && this._fieldWrapper.appendChild(this._fieldSpan); this._fieldWrapper.appendChild(this._enumerables); (this as any).dom = this._fieldWrapper; updateText(false); -- cgit v1.2.3-70-g09d2 From f80aee53be8582956a1f39519938700c3e90cb53 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 27 Mar 2020 23:30:03 -0400 Subject: fixed up embedded document view layout references in text boxes to 1) create the template if it doesn't exist and 2) to allow parameters to be passed to templates --- src/client/util/RichTextRules.ts | 7 +-- src/client/util/RichTextSchema.tsx | 38 ++++++++------- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 61 +++++++++++-------------- src/new_fields/Doc.ts | 3 +- 5 files changed, 57 insertions(+), 55 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 851619f63..04a6fe21c 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -116,10 +116,11 @@ export class RichTextRules { }), // create an inline view of a document {{ : }} // {{:Doc}} => show default view of document {{}} => show layout for this doc {{ : Doc}} => show layout for another doc new InputRule( - new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(:[a-zA-Z_ \-0-9]+)?\}\}$/), + new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(\([a-zA-Z_ \-0-9]*\))(:[a-zA-Z_ \-0-9]+)?\}\}$/), (state, match, start, end) => { const fieldKey = match[1]; - const docid = match[2]?.substring(1); + const fieldParam = match[2]; + const docid = match[3]?.substring(1); if (!fieldKey && !docid) return state.tr; docid && DocServer.GetRefField(docid).then(docx => { if (!(docx instanceof Doc && docx)) { @@ -128,7 +129,7 @@ export class RichTextRules { } }); const node = (state.doc.resolve(start) as any).nodeAfter; - const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid, fieldKey, float: "right", alias: Utils.GenerateGuid() }); + const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid, fieldKey: fieldKey + fieldParam, float: "right", alias: Utils.GenerateGuid() }); const sm = state.storedMarks || undefined; return node ? state.tr.replaceRangeWith(start, end, dashDoc).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; }), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 44c811b76..5b3119d38 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -775,7 +775,8 @@ export class DashDocView { alias && DocServer.GetRefField(docid).then(async dashDocBase => { if (dashDocBase instanceof Doc) { const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); - aliasedDoc.layoutKey = node.attrs.fieldKey === "layout" ? "layout" : "layout" + (node.attrs.fieldKey ? "_" + node.attrs.fieldKey : ""); + aliasedDoc.layoutKey = "layout"; + node.attrs.fieldKey !== "layout" && DocumentView.makeCustomViewClicked(aliasedDoc, undefined, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); @@ -888,7 +889,7 @@ export class DashFieldView { this._enumerables.onpointerdown = async (e) => { e.stopPropagation(); - const collview = await Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]); + const collview = await Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, [{ title: self._fieldSpan.innerText }]); collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"); }; const updateText = (forceMatch: boolean) => { @@ -898,12 +899,12 @@ export class DashFieldView { // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - DocServer.GetRefField(node.attrs.fieldKey).then(options => { + DocServer.GetRefField(self._fieldKey).then(options => { let modText = ""; (options instanceof Doc) && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title))); if (modText) { self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = modText; - Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, []); + Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, []); } else if (!self._fieldSpan.innerText.startsWith(":=") && !self._fieldSpan.innerText.startsWith("=:=")) { self._dashDoc![self._fieldKey] = newText; } @@ -922,14 +923,14 @@ export class DashFieldView { this._fieldCheck.id = Utils.GenerateGuid(); this._fieldCheck.type = "checkbox"; this._fieldCheck.style.position = "relative"; - this._fieldCheck.style.display = "inline-block"; + this._fieldCheck.style.display = "none"; this._fieldCheck.style.minWidth = "12px"; this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldCheck.onchange = function (e: any) { // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - DocServer.GetRefField(node.attrs.fieldKey).then(options => self._dashDoc![self._fieldKey] = e.target.checked); + DocServer.GetRefField(self._fieldKey).then(options => self._dashDoc![self._fieldKey] = e.target.checked); } @@ -937,7 +938,7 @@ export class DashFieldView { this._fieldSpan.id = Utils.GenerateGuid(); this._fieldSpan.contentEditable = "true"; this._fieldSpan.style.position = "relative"; - this._fieldSpan.style.display = "inline-block"; + this._fieldSpan.style.display = "none"; this._fieldSpan.style.minWidth = "12px"; this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; @@ -947,9 +948,15 @@ export class DashFieldView { const setDashDoc = (doc: Doc) => { self._dashDoc = doc; - if (self._dashDoc && self._options?.length && !self._dashDoc[node.attrs.fieldKey]) { - self._dashDoc[node.attrs.fieldKey] = StrCast(self._options[0].title); + if (self._dashDoc && self._options?.length && !self._dashDoc[self._fieldKey]) { + self._dashDoc[self._fieldKey] = StrCast(self._options[0].title); } + const layout = tbox.props.Document; + self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(layout[StrCast(self._fieldKey).substring(1)]) : self._fieldKey; + this._labelSpan.innerHTML = `${self._fieldKey}: `; + const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null); + this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none"; + this._fieldSpan.style.display = !(fieldVal === true || fieldVal === false) ? "inline-block" : "none"; }; this._fieldSpan.onkeydown = function (e: any) { e.stopPropagation(); @@ -964,7 +971,7 @@ export class DashFieldView { } if (e.key === "Enter") { e.preventDefault(); - e.ctrlKey && Doc.addFieldEnumerations(self._textBoxDoc, node.attrs.fieldKey, [{ title: self._fieldSpan.innerText }]); + e.ctrlKey && Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, [{ title: self._fieldSpan.innerText }]); updateText(true); } }; @@ -994,7 +1001,7 @@ export class DashFieldView { tbox.props.addDocTab(alias, "onRight"); } }; - this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `; + this._labelSpan.innerHTML = `${self._fieldKey}: `; if (node.attrs.docid) { DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && runInAction(() => setDashDoc(dashDoc))); } else { @@ -1002,8 +1009,8 @@ export class DashFieldView { } this._reactionDisposer?.(); this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes - const dashVal = this._dashDoc?.[node.attrs.fieldKey]; - return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[this._fieldKey] : dashVal; + const dashVal = this._dashDoc?.[self._fieldKey]; + return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[self._fieldKey] : dashVal; }, fval => { const boolVal = Cast(fval, "boolean", null); if (boolVal === true || boolVal === false) { @@ -1013,10 +1020,9 @@ export class DashFieldView { } }, { fireImmediately: true }); - const fieldVal = Cast(this._dashDoc?.[node.attrs.fieldKey], "boolean", null); this._fieldWrapper.appendChild(this._labelSpan); - (fieldVal === true || fieldVal === false) && this._fieldWrapper.appendChild(this._fieldCheck); - !(fieldVal === true || fieldVal === false) && this._fieldWrapper.appendChild(this._fieldSpan); + this._fieldWrapper.appendChild(this._fieldCheck); + this._fieldWrapper.appendChild(this._fieldSpan); this._fieldWrapper.appendChild(this._enumerables); (this as any).dom = this._fieldWrapper; updateText(false); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 239f414fd..a58115120 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -78,7 +78,8 @@ export class DocumentContentsView extends React.Component(Docu undoBatch(() => Doc.setNativeView(doc))(); } - static makeCustomViewClicked = (doc: Doc, dataDoc: Opt, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, name: string = "custom", docLayoutTemplate?: Doc) => { + static makeCustomViewClicked = (doc: Doc, dataDoc: Opt, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { + const userDoc = Doc.UserDoc(); + const imgView = Cast(userDoc.iconView, Doc, null); + const iconImgView = Cast(userDoc.iconImageView, Doc, null); + const iconColView = Cast(userDoc.iconColView, Doc, null); + const iconViews = [imgView, iconImgView, iconColView]; + const templateButtons = DocListCast(Cast(userDoc.templateButtons, Doc, null)?.data); + const noteTypes = DocListCast(Cast(userDoc.noteTypes, Doc, null)?.data); + const allTemplates = iconViews.concat(templateButtons).concat(noteTypes); + const templateName = templateSignature.replace(/\(.*\)/, ""); + !docLayoutTemplate && allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { + if (StrCast(tempDoc.title) === doc.type + "_" + templateName) { + docLayoutTemplate = tempDoc; + } + }); + !docLayoutTemplate && allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { + if (StrCast(tempDoc.title) === templateName) { + docLayoutTemplate = tempDoc; + } + }); + const batch = UndoManager.StartBatch("CustomViewClicked"); - const customName = "layout_" + name; + const customName = "layout_" + templateSignature; if (doc[customName] === undefined) { const _width = NumCast(doc._width); const _height = NumCast(doc._height); @@ -626,39 +646,12 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action - setCustomView = - (custom: boolean, layout: string): void => { - // if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) { - // Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document); - // } else - if (custom) { - DocumentView.makeNativeViewClicked(this.props.Document); - const userDoc = Doc.UserDoc(); - - const imgView = Cast(userDoc.iconView, Doc, null); - const iconImgView = Cast(userDoc.iconImageView, Doc, null); - const iconColView = Cast(userDoc.iconColView, Doc, null); - const iconViews = [imgView, iconImgView, iconColView]; - const templateButtons = DocListCast(Cast(userDoc.templateButtons, Doc, null)?.data); - const noteTypes = DocListCast(Cast(userDoc.noteTypes, Doc, null)?.data); - const allTemplates = iconViews.concat(templateButtons).concat(noteTypes); - let foundLayout: Opt; - allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { - if (StrCast(tempDoc.title) === this.props.Document.type + "_" + layout) { - foundLayout = tempDoc; - } - }); - !foundLayout && allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { - if (StrCast(tempDoc.title) === layout) { - foundLayout = tempDoc; - } - }); - DocumentView. - makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); - } else { - DocumentView.makeNativeViewClicked(this.props.Document); - } + setCustomView = (custom: boolean, layout: string): void => { + DocumentView.makeNativeViewClicked(this.props.Document); + if (custom) { + DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, undefined); } + } @undoBatch @action diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 8447a4e93..2a7b08d44 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -463,7 +463,7 @@ export namespace Doc { // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties // of the original layout while allowing for individual layout properties to be overridden in the expanded layout. // - export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc) { + export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateParams?: string) { if (!WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders @@ -484,6 +484,7 @@ export namespace Doc { if (!targetDoc[expandedLayoutFieldKey]) { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); newLayoutDoc.expandedTemplate = targetDoc; + newLayoutDoc.params = templateParams?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1]; targetDoc[expandedLayoutFieldKey] = newLayoutDoc; const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; -- cgit v1.2.3-70-g09d2 From f488ca2b44af291c7bea853ad574cf7453fadb25 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 28 Mar 2020 01:00:30 -0400 Subject: changed template parameters to be stored in '@params'. Updated ImageBox to allow template parameters --- src/client/util/RichTextSchema.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 86 +++++++++++++++++++------------------ src/new_fields/Doc.ts | 4 +- 3 files changed, 50 insertions(+), 44 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 5b3119d38..a81c6515d 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -20,7 +20,6 @@ import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from import { DocServer } from "../DocServer"; import { Docs } from "../documents/Documents"; import { CollectionViewType } from "../views/collections/CollectionView"; -import { ContextMenu } from "../views/ContextMenu"; import { DocumentView } from "../views/nodes/DocumentView"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { DocumentManager } from "./DocumentManager"; @@ -952,7 +951,8 @@ export class DashFieldView { self._dashDoc[self._fieldKey] = StrCast(self._options[0].title); } const layout = tbox.props.Document; - self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(layout[StrCast(self._fieldKey).substring(1)]) : self._fieldKey; + // NOTE: if the field key starts with "@", then the actual field key is stored in the "@"fieldKey. Dereferencing these fields happens in ImageBox and RichTextSchema + self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(layout[StrCast(self._fieldKey)]) : self._fieldKey; this._labelSpan.innerHTML = `${self._fieldKey}: `; const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null); this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none"; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index b1c172e22..04ebf477b 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -79,23 +79,27 @@ export class ImageBox extends DocAnnotatableComponent { if (de.complete.docDragData) { if (de.metaKey) { de.complete.docDragData.droppedDocuments.forEach(action((drop: Doc) => { - Doc.AddDocToList(this.dataDoc, this.props.fieldKey + "-alternates", drop); + Doc.AddDocToList(this.dataDoc, this.fieldKey + "-alternates", drop); e.stopPropagation(); })); - } else if (de.altKey || !this.dataDoc[this.props.fieldKey]) { + } else if (de.altKey || !this.dataDoc[this.fieldKey]) { const layoutDoc = de.complete.docDragData?.draggedDocuments[0]; const targetField = Doc.LayoutFieldKey(layoutDoc); const targetDoc = layoutDoc[DataSym]; if (targetDoc[targetField] instanceof ImageField) { - this.dataDoc[this.props.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField); - this.dataDoc[this.props.fieldKey + "-nativeWidth"] = NumCast(targetDoc[targetField + "-nativeWidth"]); - this.dataDoc[this.props.fieldKey + "-nativeHeight"] = NumCast(targetDoc[targetField + "-nativeHeight"]); + this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField); + this.dataDoc[this.fieldKey + "-nativeWidth"] = NumCast(targetDoc[targetField + "-nativeWidth"]); + this.dataDoc[this.fieldKey + "-nativeHeight"] = NumCast(targetDoc[targetField + "-nativeHeight"]); e.stopPropagation(); } } @@ -123,9 +127,9 @@ export class ImageBox extends DocAnnotatableComponent { - const nw = NumCast(this.Document[this.props.fieldKey + "-nativeWidth"]); - const nh = NumCast(this.Document[this.props.fieldKey + "-nativeHeight"]); + const nw = NumCast(this.Document[this.fieldKey + "-nativeWidth"]); + const nh = NumCast(this.Document[this.fieldKey + "-nativeHeight"]); const w = this.Document._width; const h = this.Document._height; - this.dataDoc[this.props.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) + 90) % 360; - this.dataDoc[this.props.fieldKey + "-nativeWidth"] = nh; - this.dataDoc[this.props.fieldKey + "-nativeHeight"] = nw; + this.dataDoc[this.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.fieldKey + "-rotation"]) + 90) % 360; + this.dataDoc[this.fieldKey + "-nativeWidth"] = nh; + this.dataDoc[this.fieldKey + "-nativeHeight"] = nw; this.Document._width = h; this.Document._height = w; }); specificContextMenu = (e: React.MouseEvent): void => { - const field = Cast(this.Document[this.props.fieldKey], ImageField); + const field = Cast(this.Document[this.fieldKey], ImageField); if (field) { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" }); funcs.push({ description: "Reset Native Dimensions", event: action(async () => { - const curNW = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]); - const curNH = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"]); + const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { - this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; - this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); } else { - this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); - this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; } }), icon: "expand-arrows-alt" }); @@ -190,7 +194,7 @@ export class ImageBox extends DocAnnotatableComponent) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!), new List()); return faceDocs; }; - this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.props.fieldKey + "-faces"], this.url, Service.Face, converter); + this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-faces"], this.url, Service.Face, converter); } generateMetadata = (threshold: Confidence = Confidence.Excellent) => { @@ -202,16 +206,16 @@ export class ImageBox extends DocAnnotatableComponent= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`); }); - this.dataDoc[this.props.fieldKey + "-generatedTags"] = tagsList; + this.dataDoc[this.fieldKey + "-generatedTags"] = tagsList; tagDoc.title = "Generated Tags Doc"; tagDoc.confidence = threshold; return tagDoc; }; - this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.props.fieldKey + "-generatedTagsDoc"], this.url, Service.ComputerVision, converter); + this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-generatedTagsDoc"], this.url, Service.ComputerVision, converter); } @computed private get url() { - const data = Cast(this.dataDoc[this.props.fieldKey], ImageField); + const data = Cast(this.dataDoc[this.fieldKey], ImageField); return data ? data.url.href : undefined; } @@ -244,32 +248,32 @@ export class ImageBox extends DocAnnotatableComponent { const cachedNativeSize = { - width: NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]), - height: NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"]) + width: NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]), + height: NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) }; - const cachedImgPath = this.dataDoc[this.props.fieldKey + "-imgPath"]; + const cachedImgPath = this.dataDoc[this.fieldKey + "-imgPath"]; const docAspect = this.Document[HeightSym]() / this.Document[WidthSym](); const cachedAspect = cachedNativeSize.height / cachedNativeSize.width; if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05 || imgPath !== cachedImgPath) { if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { requestImageSize(imgPath).then((inquiredSize: any) => { - const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) % 180; + const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize; const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width; setTimeout(action(() => { if (this.Document[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { this.Document._height = this.Document[WidthSym]() * rotatedAspect; - this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width; - this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height; + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width; + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height; } - this.dataDoc[this.props.fieldKey + "-imgPath"] = imgPath; + this.dataDoc[this.fieldKey + "-imgPath"] = imgPath; }), 0); }).catch((err: any) => console.log(err)); } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { @@ -289,7 +293,7 @@ export class ImageBox extends DocAnnotatableComponent { const self = this; - const audioAnnos = DocListCast(this.dataDoc[this.props.fieldKey + "-audioAnnotations"]); + const audioAnnos = DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]); if (audioAnnos && audioAnnos.length && this._audioState === 0) { const anno = audioAnnos[Math.floor(Math.random() * audioAnnos.length)]; anno.data instanceof AudioField && new Howl({ @@ -324,7 +328,7 @@ export class ImageBox extends DocAnnotatableComponent { this.uploadIcon = idle; if (data) { - dataDoc[this.props.fieldKey] = data; + dataDoc[this.fieldKey] = data; } }), 2000); }} @@ -363,8 +367,8 @@ export class ImageBox extends DocAnnotatableComponent 20) { - const alts = DocListCast(this.dataDoc[this.props.fieldKey + "-alternates"]); + const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]); const altpaths = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url)); - const field = this.dataDoc[this.props.fieldKey]; + const field = this.dataDoc[this.fieldKey]; // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; @@ -389,7 +393,7 @@ export class ImageBox extends DocAnnotatableComponent + style={{ color: [DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]).length ? "blue" : "gray", "green", "red"][this._audioState] }} + icon={!DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]).length ? "microphone" : faFileAudio} size="sm" />
} {this.considerDownloadIcon} {this.considerGooglePhotosLink()} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 2a7b08d44..da723b43b 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -484,7 +484,9 @@ export namespace Doc { if (!targetDoc[expandedLayoutFieldKey]) { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); newLayoutDoc.expandedTemplate = targetDoc; - newLayoutDoc.params = templateParams?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1]; + // the template's parameters are stored in params which are derefenced to find + // the actual field key where the template data is stored. Currently this is only used in RichTextSchema's docView + newLayoutDoc["@params"] = templateParams?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1]; targetDoc[expandedLayoutFieldKey] = newLayoutDoc; const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; -- cgit v1.2.3-70-g09d2 From 7670987e5d957ff0cae12acd921275faae4041b1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 28 Mar 2020 17:11:37 -0400 Subject: ongoing work with parameterized templates --- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 8 ++++---- src/new_fields/Doc.ts | 7 ++++--- src/new_fields/util.ts | 4 ++++ 4 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a81c6515d..29fd28994 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1025,7 +1025,7 @@ export class DashFieldView { this._fieldWrapper.appendChild(this._fieldSpan); this._fieldWrapper.appendChild(this._enumerables); (this as any).dom = this._fieldWrapper; - updateText(false); + //updateText(false); } destroy() { this._reactionDisposer?.(); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 11f214625..8b7136876 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -48,8 +48,8 @@ export interface SubCollectionViewProps extends CollectionViewProps { layoutEngine?: () => string; } -export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?:X) { - class CollectionSubView extends DocComponent(schemaCtor) { +export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: X) { + class CollectionSubView extends DocComponent(schemaCtor) { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; @@ -92,7 +92,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?:X } @computed get dataDoc() { - return (this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : + return (this.props.DataDoc instanceof Doc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } @@ -195,7 +195,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?:X @undoBatch @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { - const docDragData = de.complete.docDragData; + const docDragData = de.complete.docDragData; (this.props.Document.dropConverter instanceof ScriptField) && this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this if (docDragData) { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 9d90c569a..e84ddc684 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -475,8 +475,9 @@ export namespace Doc { // If it doesn't find the expanded layout, then it makes a delegate of the template layout and // saves it on the data doc indexed by the template layout's id. // + const params = templateParams?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1] const layoutFielddKey = Doc.LayoutFieldKey(templateLayoutDoc); - const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + "]"; + const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + params + "]"; let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey]; if (templateLayoutDoc.resolvedDataDoc instanceof Promise) { expandedTemplateLayout = undefined; @@ -486,10 +487,10 @@ export namespace Doc { setTimeout(action(() => { if (!targetDoc[expandedLayoutFieldKey]) { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); + newLayoutDoc["@params"] = params; newLayoutDoc.expandedTemplate = targetDoc; // the template's parameters are stored in params which are derefenced to find // the actual field key where the template data is stored. Currently this is only used in RichTextSchema's docView - newLayoutDoc["@params"] = templateParams?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1]; targetDoc[expandedLayoutFieldKey] = newLayoutDoc; const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; @@ -511,7 +512,7 @@ export namespace Doc { } const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); - return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; + return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["@params"]) + ")"), data: resolvedDataDoc }; } export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 3ab1b299b..0b98be953 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -128,6 +128,10 @@ export function getter(target: any, in_prop: string | symbol | number, receiver: } if (target.__LAYOUT__) return target.__LAYOUT__[prop]; } + if (typeof prop === "string" && prop.startsWith("@@")) { + const expanded = target.__fields["expandedTemplate"]; + if (expanded) return expanded.cache[target.__fields[prop.substring(1)]]; + } if (prop === "then") {//If we're being awaited return undefined; } -- cgit v1.2.3-70-g09d2 From 35e84314bc054d81c44ffababd376a133532c8bc Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 28 Mar 2020 18:42:19 -0400 Subject: more improvements for parameterized templates --- src/client/util/RichTextSchema.tsx | 13 +++++++++---- src/new_fields/Doc.ts | 4 ++-- src/new_fields/util.ts | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 29fd28994..69296d8bc 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -799,7 +799,9 @@ export class DashDocView { doRender(dashDoc: Doc, removeDoc: any, node: any, view: any, getPos: any) { this._dashDoc = dashDoc; const self = this; - const finalLayout = this._textBox.props.Document instanceof Doc && (Doc.expandTemplateLayout(dashDoc, !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.props.Document) ? this._textBox.dataDoc : undefined)); + const dashLayoutDoc = Doc.Layout(dashDoc); + const finalLayout = this._textBox.props.Document instanceof Doc && (Doc.expandTemplateLayout(dashLayoutDoc, + dashLayoutDoc !== dashDoc || !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.props.Document) ? this._textBox.dataDoc : undefined, node.attrs.fieldKey)); if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc, node, view, getPos), 0); else { const layoutKey = StrCast(finalLayout.layoutKey); @@ -929,7 +931,8 @@ export class DashFieldView { // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - DocServer.GetRefField(self._fieldKey).then(options => self._dashDoc![self._fieldKey] = e.target.checked); + const checked = e.target.checked; + DocServer.GetRefField(self._fieldKey).then(options => self._dashDoc![self._fieldKey] = checked); } @@ -952,7 +955,7 @@ export class DashFieldView { } const layout = tbox.props.Document; // NOTE: if the field key starts with "@", then the actual field key is stored in the "@"fieldKey. Dereferencing these fields happens in ImageBox and RichTextSchema - self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(layout[StrCast(self._fieldKey)]) : self._fieldKey; + self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(layout[StrCast(self._fieldKey).substring(1)]) : self._fieldKey; this._labelSpan.innerHTML = `${self._fieldKey}: `; const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null); this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none"; @@ -1010,7 +1013,7 @@ export class DashFieldView { this._reactionDisposer?.(); this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes const dashVal = this._dashDoc?.[self._fieldKey]; - return StrCast(dashVal).startsWith(":=") || !dashVal ? Doc.Layout(tbox.props.Document)[self._fieldKey] : dashVal; + return StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(tbox.props.Document)[self._fieldKey] : dashVal; }, fval => { const boolVal = Cast(fval, "boolean", null); if (boolVal === true || boolVal === false) { @@ -1018,6 +1021,8 @@ export class DashFieldView { } else { this._fieldSpan.innerHTML = Field.toString(fval as Field) || ""; } + this._fieldCheck.style.display = (boolVal === true || boolVal === false) ? "inline-block" : "none"; + this._fieldSpan.style.display = !(boolVal === true || boolVal === false) ? "inline-block" : "none"; }, { fireImmediately: true }); this._fieldWrapper.appendChild(this._labelSpan); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index e84ddc684..219877f74 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -487,7 +487,7 @@ export namespace Doc { setTimeout(action(() => { if (!targetDoc[expandedLayoutFieldKey]) { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); - newLayoutDoc["@params"] = params; + newLayoutDoc["params"] = params; newLayoutDoc.expandedTemplate = targetDoc; // the template's parameters are stored in params which are derefenced to find // the actual field key where the template data is stored. Currently this is only used in RichTextSchema's docView @@ -512,7 +512,7 @@ export namespace Doc { } const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); - return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["@params"]) + ")"), data: resolvedDataDoc }; + return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["params"]) + ")"), data: resolvedDataDoc }; } export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 0b98be953..080123965 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -128,7 +128,7 @@ export function getter(target: any, in_prop: string | symbol | number, receiver: } if (target.__LAYOUT__) return target.__LAYOUT__[prop]; } - if (typeof prop === "string" && prop.startsWith("@@")) { + if (typeof prop === "string" && prop.startsWith("@")) { const expanded = target.__fields["expandedTemplate"]; if (expanded) return expanded.cache[target.__fields[prop.substring(1)]]; } -- cgit v1.2.3-70-g09d2 From 089011c748e67fcce407021c6c28dc5028303a45 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 29 Mar 2020 00:25:33 -0400 Subject: clean up of parameterized templates. added 'self' to scripts to reference the expandedTemplate --- src/client/util/RichTextSchema.tsx | 28 ++++++++-------------- src/client/util/Scripting.ts | 2 ++ .../views/collections/CollectionViewChromes.tsx | 1 + src/new_fields/Doc.ts | 23 +++++++++++------- src/new_fields/ScriptField.ts | 5 ++-- 5 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 69296d8bc..71d4530f2 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -906,15 +906,13 @@ export class DashFieldView { if (modText) { self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = modText; Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, []); - } else if (!self._fieldSpan.innerText.startsWith(":=") && !self._fieldSpan.innerText.startsWith("=:=")) { - self._dashDoc![self._fieldKey] = newText; - } - - // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key - if (self._fieldSpan.innerText.startsWith(":=") && self._dashDoc) { - self._dashDoc[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); - } else if (self._fieldSpan.innerText.startsWith("=:=") && self._dashDoc) { + } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key + else if (self._fieldSpan.innerText.startsWith(":=")) { + self._dashDoc![self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); + } else if (self._fieldSpan.innerText.startsWith("=:=")) { Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(3)); + } else { + self._dashDoc![self._fieldKey] = newText; } }); }; @@ -928,14 +926,9 @@ export class DashFieldView { this._fieldCheck.style.minWidth = "12px"; this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldCheck.onchange = function (e: any) { - // look for a document whose id === the fieldKey being displayed. If there's a match, then that document - // holds the different enumerated values for the field in the titles of its collected documents. - // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - const checked = e.target.checked; - DocServer.GetRefField(self._fieldKey).then(options => self._dashDoc![self._fieldKey] = checked); + self._dashDoc![self._fieldKey] = e.target.checked; } - this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); this._fieldSpan.contentEditable = "true"; @@ -950,12 +943,11 @@ export class DashFieldView { const setDashDoc = (doc: Doc) => { self._dashDoc = doc; - if (self._dashDoc && self._options?.length && !self._dashDoc[self._fieldKey]) { + if (self._options?.length && !self._dashDoc[self._fieldKey]) { self._dashDoc[self._fieldKey] = StrCast(self._options[0].title); } - const layout = tbox.props.Document; - // NOTE: if the field key starts with "@", then the actual field key is stored in the "@"fieldKey. Dereferencing these fields happens in ImageBox and RichTextSchema - self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(layout[StrCast(self._fieldKey).substring(1)]) : self._fieldKey; + // NOTE: if the field key starts with "@", then the actual field key is stored in the field 'fieldKey' (removing the @). + self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(tbox.props.Document[StrCast(self._fieldKey).substring(1)]) : self._fieldKey; this._labelSpan.innerHTML = `${self._fieldKey}: `; const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null); this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none"; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 0fa96963e..ce21b7fa7 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -215,6 +215,8 @@ function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, inde export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult { const { requiredType = "", addReturn = false, params = {}, capturedVariables = {}, typecheck = true } = options; + if (options.params && !options.params.this) options.params.this = Doc.name; + if (options.params && !options.params.self) options.params.self = Doc.name; if (options.globals) { Scripting.setScriptingGlobals(options.globals); } diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 9391b153e..aa6e07968 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -400,6 +400,7 @@ export class CollectionViewBaseChrome extends React.Component and then arguments would be passed in the layout key as: + // layout_mytemplate(somparam=somearg). + // then any references to @someparam would be rewritten as accesses to 'somearg' on the expandedTemplate + export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string) { if (!WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders @@ -475,9 +481,10 @@ export namespace Doc { // If it doesn't find the expanded layout, then it makes a delegate of the template layout and // saves it on the data doc indexed by the template layout's id. // - const params = templateParams?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1].replace("()", "") || ""; + const args = templateArgs?.match(/\(([a-zA-Z0-9_-]*)\)/)?.[1].replace("()", "") || ""; + const params = args.split("=").length > 1 ? args.split("=")[0] : "PARAMS"; const layoutFielddKey = Doc.LayoutFieldKey(templateLayoutDoc); - const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + params + "]"; + const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + args + "]"; let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey]; if (templateLayoutDoc.resolvedDataDoc instanceof Promise) { expandedTemplateLayout = undefined; @@ -487,10 +494,10 @@ export namespace Doc { setTimeout(action(() => { if (!targetDoc[expandedLayoutFieldKey]) { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); - newLayoutDoc["params"] = params; + // the template's arguments are stored in params which is derefenced to find + // the actual field key where the parameterized template data is stored. + newLayoutDoc[params] = args; newLayoutDoc.expandedTemplate = targetDoc; - // the template's parameters are stored in params which are derefenced to find - // the actual field key where the template data is stored. Currently this is only used in RichTextSchema's docView targetDoc[expandedLayoutFieldKey] = newLayoutDoc; const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; @@ -512,7 +519,7 @@ export namespace Doc { } const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); - return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["params"]) + ")"), data: resolvedDataDoc }; + return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["PARAMS"]) + ")"), data: resolvedDataDoc }; } export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index 606f55b7c..954c22a8d 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -7,6 +7,7 @@ import { Doc, Field } from "../new_fields/Doc"; import { Plugins } from "./util"; import { computedFn } from "mobx-utils"; import { ProxyField } from "./Proxy"; +import { Cast } from "./Types"; function optional(propSchema: PropSchema) { return custom(value => { @@ -106,7 +107,7 @@ export class ScriptField extends ObjectField { } public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) { const compiled = CompileScript(script, { - params: { this: Doc.name, source: Doc.name, _last_: "any", ...params }, + params: { this: Doc.name, self: Doc.name, _last_: "any", ...params }, typecheck: false, editable: true, addReturn: addReturn, @@ -130,7 +131,7 @@ export class ScriptField extends ObjectField { export class ComputedField extends ScriptField { _lastComputedResult: any; //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc - value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ source: doc.expandedTemplate || doc, this: doc, _last_: this._lastComputedResult }, console.log).result); + value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.expandedTemplate, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result); public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; -- cgit v1.2.3-70-g09d2 From 8475b309106d519a2d541b7cd61f22ac44b6392d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 29 Mar 2020 13:27:36 -0400 Subject: more tweaks to embedded documents in text. fixes for expandedTemplate to show the original doc (not dataDoc). got rid of imgPath in imageBox. --- src/client/util/RichTextSchema.tsx | 9 ++++++--- src/client/views/nodes/ImageBox.tsx | 4 +--- src/new_fields/Doc.ts | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 71d4530f2..7e4a095bc 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -768,7 +768,7 @@ export class DashDocView { }; const alias = node.attrs.alias; - const docid = node.attrs.docid || tbox.props.DataDoc?.[Id] || tbox.dataDoc?.[Id]; + const docid = node.attrs.docid || tbox.props.Document[Id];// tbox.props.DataDoc?.[Id] || tbox.dataDoc?.[Id]; DocServer.GetRefField(docid + alias).then(async dashDoc => { if (!(dashDoc instanceof Doc)) { alias && DocServer.GetRefField(docid).then(async dashDocBase => { @@ -800,10 +800,13 @@ export class DashDocView { this._dashDoc = dashDoc; const self = this; const dashLayoutDoc = Doc.Layout(dashDoc); - const finalLayout = this._textBox.props.Document instanceof Doc && (Doc.expandTemplateLayout(dashLayoutDoc, + const finalLayout = node.attrs.docid ? dashDoc : this._textBox.props.Document instanceof Doc && (Doc.expandTemplateLayout(dashLayoutDoc, dashLayoutDoc !== dashDoc || !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.props.Document) ? this._textBox.dataDoc : undefined, node.attrs.fieldKey)); if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc, node, view, getPos), 0); else { + if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { + finalLayout.expandedTemplate = dashDoc.aliasOf; + } const layoutKey = StrCast(finalLayout.layoutKey); const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; if (finalLayout !== dashDoc && finalKey) { @@ -820,7 +823,7 @@ export class DashDocView { }, { fireImmediately: true }); ReactDOM.render( 0.05 || imgPath !== cachedImgPath) { + if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) { if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { requestImageSize(imgPath).then((inquiredSize: any) => { const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; @@ -273,7 +272,6 @@ export class ImageBox extends DocAnnotatableComponent console.log(err)); } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 3ac297e94..0e3bab32a 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -472,7 +472,7 @@ export namespace Doc { // in the future, field references could be written as @ and then arguments would be passed in the layout key as: // layout_mytemplate(somparam=somearg). // then any references to @someparam would be rewritten as accesses to 'somearg' on the expandedTemplate - export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string) { + export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string, templateParent?: Doc) { if (!WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders @@ -497,7 +497,7 @@ export namespace Doc { // the template's arguments are stored in params which is derefenced to find // the actual field key where the parameterized template data is stored. newLayoutDoc[params] = args; - newLayoutDoc.expandedTemplate = targetDoc; + newLayoutDoc.expandedTemplate = templateParent || targetDoc; targetDoc[expandedLayoutFieldKey] = newLayoutDoc; const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; @@ -519,7 +519,7 @@ export namespace Doc { } const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); - return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["PARAMS"]) + ")"), data: resolvedDataDoc }; + return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc["PARAMS"]) + ")", Cast(containerDoc.expandedTemplate, Doc, null)), data: resolvedDataDoc }; } export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { -- cgit v1.2.3-70-g09d2 From f1ee7b622c3acc654d19bcf8d306f15f8e087a76 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 29 Mar 2020 19:12:40 -0400 Subject: cleand up richtextschema to work when layout changes due to template being loaded --- src/client/util/RichTextSchema.tsx | 92 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 41 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 7e4a095bc..1c637cfbe 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -723,6 +723,7 @@ export class DashDocView { _outer: HTMLElement; _dashDoc: Doc | undefined; _reactionDisposer: IReactionDisposer | undefined; + _renderDisposer: IReactionDisposer | undefined; _textBox: FormattedTextBox; getDocTransform = () => { @@ -804,55 +805,64 @@ export class DashDocView { dashLayoutDoc !== dashDoc || !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.props.Document) ? this._textBox.dataDoc : undefined, node.attrs.fieldKey)); if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc, node, view, getPos), 0); else { - if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { - finalLayout.expandedTemplate = dashDoc.aliasOf; - } - const layoutKey = StrCast(finalLayout.layoutKey); - const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; - if (finalLayout !== dashDoc && finalKey) { - const finalLayoutField = finalLayout[finalKey]; - if (finalLayoutField instanceof ObjectField) { - finalLayout[finalKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${finalKey})`, { this: Doc.name }); - } - } this._reactionDisposer?.(); this._reactionDisposer = reaction(() => ({ dim: [finalLayout[WidthSym](), finalLayout[HeightSym]()], color: finalLayout.color }), ({ dim, color }) => { this._dashSpan.style.width = this._outer.style.width = Math.max(20, dim[0]) + "px"; this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px"; this._outer.style.border = "1px solid " + StrCast(finalLayout.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray")); }, { fireImmediately: true }); - ReactDOM.render(, this._dashSpan); - 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); + let doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => { + ReactDOM.unmountComponentAtNode(this._dashSpan); + ReactDOM.render(, this._dashSpan); + 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); + } } } + this._renderDisposer?.(); + this._renderDisposer = reaction(() => { + if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { + finalLayout.expandedTemplate = dashDoc.aliasOf; + } + const layoutKey = StrCast(finalLayout.layoutKey); + const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; + if (finalLayout !== dashDoc && finalKey) { + const finalLayoutField = finalLayout[finalKey]; + if (finalLayoutField instanceof ObjectField) { + finalLayout[finalKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${finalKey})`, { this: Doc.name }); + } + } + return { finalLayout, resolvedDataDoc: Cast(finalLayout.resolvedDataDoc, Doc, null) }; + }, + (res) => doReactRender(res.finalLayout, res.resolvedDataDoc), + { fireImmediately: true }); } } destroy() { -- cgit v1.2.3-70-g09d2 From 71b0e84cb852bc171a5df96b36cbb5f7bd1c150c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 30 Mar 2020 14:19:03 -0400 Subject: changed expandedTemplate to rootDocument --- src/client/util/ProsemirrorExampleTransfer.ts | 6 +++--- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 4 ++-- src/client/views/presentationview/PresElementBox.tsx | 2 +- src/new_fields/Doc.ts | 18 +++++++++--------- src/new_fields/ScriptField.ts | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 5cbf401d4..42247f177 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -151,14 +151,14 @@ export default function buildKeymap>(schema: S, props: any }); bind("Ctrl-Enter", (state: EditorState, dispatch: (tx: Transaction) => void) => { const layoutDoc = props.Document; - const originalDoc = layoutDoc.expandedTemplate || layoutDoc; + const originalDoc = layoutDoc.rootDocument || layoutDoc; if (originalDoc instanceof Doc) { const newDoc = Docs.Create.TextDocument("", { title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x), y: NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10, _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); FormattedTextBox.SelectOnLoad = newDoc[Id]; - originalDoc instanceof Doc && props.addDocument(newDoc); + props.addDocument(newDoc); } }); @@ -169,7 +169,7 @@ export default function buildKeymap>(schema: S, props: any }; const addTextOnRight = (force: boolean) => { const layoutDoc = props.Document; - const originalDoc = layoutDoc.expandedTemplate || layoutDoc; + const originalDoc = layoutDoc.rootDocument || layoutDoc; if (force || props.Document._singleLine) { const newDoc = Docs.Create.TextDocument("", { title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 1c637cfbe..b612c82ae 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -849,7 +849,7 @@ export class DashDocView { this._renderDisposer?.(); this._renderDisposer = reaction(() => { if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { - finalLayout.expandedTemplate = dashDoc.aliasOf; + finalLayout.rootDocument = dashDoc.aliasOf; } const layoutKey = StrCast(finalLayout.layoutKey); const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8b7136876..39621b75c 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -125,7 +125,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } const dfield = this.dataField; - const rawdocs = (dfield instanceof Doc) ? [dfield] : Cast(dfield, listSpec(Doc), this.props.Document.expandedTemplate && !this.props.annotationsKey ? [Cast(this.props.Document.expandedTemplate, Doc, null)] : []); + const rawdocs = (dfield instanceof Doc) ? [dfield] : Cast(dfield, listSpec(Doc), this.props.Document.rootDocument && !this.props.annotationsKey ? [Cast(this.props.Document.rootDocument, Doc, null)] : []); const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 324417cf8..edb9fd930 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -306,7 +306,7 @@ export class CollectionView extends Touchable { } get childDocs() { const dfield = this.dataField; - const rawdocs = (dfield instanceof Doc) ? [dfield] : Cast(dfield, listSpec(Doc), Cast(this.props.Document.expandedTemplate, Doc, null) ? [Cast(this.props.Document.expandedTemplate, Doc, null)] : []); + const rawdocs = (dfield instanceof Doc) ? [dfield] : Cast(dfield, listSpec(Doc), Cast(this.props.Document.rootDocument, Doc, null) ? [Cast(this.props.Document.rootDocument, Doc, null)] : []); const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 63e3e0431..080c722b2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -291,7 +291,7 @@ export class DocumentView extends DocComponent(Docu SelectionManager.DeselectAll(); UndoManager.RunInBatch(() => this.onClickHandler!.script.run({ this: this.props.Document, - self: Cast(this.props.Document.expandedTemplate, Doc, null) || this.props.Document, + self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document, containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log) && !this.props.Document.dontSelect && !this.props.Document.isButton && this.select(false), "on click"); } else if (this.Document.type === DocumentType.BUTTON) { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f83beade3..bc43beab9 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -389,7 +389,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & const funcs: ContextMenuProps[] = []; this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); - !this.props.Document.expandedTemplate && funcs.push({ + !this.props.Document.rootDocument && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = makeTemplate(this.props.Document, true); Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); @@ -822,7 +822,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } } - const selectOnLoad = (Cast(this.props.Document.expandedTemplate, Doc, null) || this.props.Document)[Id] === FormattedTextBox.SelectOnLoad; + const selectOnLoad = (Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document)[Id] === FormattedTextBox.SelectOnLoad; if (selectOnLoad && !this.props.dontRegisterView) { FormattedTextBox.SelectOnLoad = ""; this.props.select(false); diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 9329a5aa1..758795ed5 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -50,7 +50,7 @@ export class PresElementBox extends DocExtendableComponent and then arguments would be passed in the layout key as: // layout_mytemplate(somparam=somearg). - // then any references to @someparam would be rewritten as accesses to 'somearg' on the expandedTemplate + // then any references to @someparam would be rewritten as accesses to 'somearg' on the rootDocument export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string) { const args = templateArgs?.match(/\(([a-zA-Z0-9._\-]*)\)/)?.[1].replace("()", "") || StrCast(templateLayoutDoc.PARAMS); if (!args && !WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; @@ -499,8 +499,8 @@ export namespace Doc { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); // the template's arguments are stored in params which is derefenced to find // the actual field key where the parameterized template data is stored. - newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'expandedTemplate' field, but we don't need to reassign their params. it would be better if the 'expandedTemplate' field could be passed dynamically to avoid have to create instances - newLayoutDoc.expandedTemplate = targetDoc; + newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params. it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances + newLayoutDoc.rootDocument = targetDoc; targetDoc[expandedLayoutFieldKey] = newLayoutDoc; const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; @@ -511,7 +511,7 @@ export namespace Doc { }), 0); } } - return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplate is pending. + return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplateLayout is pending. } // if the childDoc is a template for a field, then this will return the expanded layout with its data doc. @@ -882,10 +882,10 @@ export namespace Doc { Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); } const options = optionsCollection as Doc; - const targetDoc = doc && Doc.GetProto(Cast(doc.expandedTemplate, Doc, null) || doc); - targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"])?._backgroundColor || "white"`, undefined, { options })); - targetDoc && (targetDoc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"]).color || "black"`, undefined, { options })); - targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this)["${enumeratedFieldKey}"]).borderRounding`, undefined, { options })); + const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc); + targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?._backgroundColor || "white"`, undefined, { options })); + targetDoc && (targetDoc.color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"]).color || "black"`, undefined, { options })); + targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"]).borderRounding`, undefined, { options })); enumerations.map(enumeration => { const found = DocListCast(options.data).find(d => d.title === enumeration.title); if (found) { diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index 954c22a8d..148886848 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -131,7 +131,7 @@ export class ScriptField extends ObjectField { export class ComputedField extends ScriptField { _lastComputedResult: any; //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc - value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.expandedTemplate, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result); + value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result); public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; -- cgit v1.2.3-70-g09d2 From 486e84c725b60a1dd1312c7903a4d248aa44d4e8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 30 Mar 2020 17:10:04 -0400 Subject: fixed captions and got rid of inappropriate references to Doc.expandTemplate --- src/client/util/DocumentManager.ts | 1 - src/client/util/RichTextRules.ts | 4 +-- src/client/util/RichTextSchema.tsx | 5 ++-- .../views/collections/CollectionSchemaView.tsx | 5 ++-- src/client/views/nodes/DocumentContentsView.tsx | 33 ++++++++++++--------- src/client/views/nodes/DocumentView.tsx | 34 +++++++--------------- 6 files changed, 35 insertions(+), 47 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 0c410c4ce..e0ffaf7e0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -28,7 +28,6 @@ export class DocumentManager { //private constructor so no other class can create a nodemanager private constructor() { - // this.DocumentViews = new Array(); } //gets all views diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 0b6fdff42..b0a124cb8 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -118,8 +118,8 @@ export class RichTextRules { new InputRule( new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(\([a-zA-Z0-9…._\-]*\))?(:[a-zA-Z_ \-0-9]+)?\}\}$/), (state, match, start, end) => { - const fieldKey = match[1]; - const fieldParam = match[2]?.replace("…", "..."); + const fieldKey = match[1] || ""; + const fieldParam = match[2]?.replace("…", "...") || ""; const docid = match[3]?.substring(1); if (!fieldKey && !docid) return state.tr; docid && DocServer.GetRefField(docid).then(docx => { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index b612c82ae..a2fb7c11b 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -776,7 +776,7 @@ export class DashDocView { if (dashDocBase instanceof Doc) { const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); aliasedDoc.layoutKey = "layout"; - node.attrs.fieldKey !== "layout" && DocumentView.makeCustomViewClicked(aliasedDoc, undefined, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); + node.attrs.fieldKey && DocumentView.makeCustomViewClicked(aliasedDoc, undefined, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); @@ -801,8 +801,7 @@ export class DashDocView { this._dashDoc = dashDoc; const self = this; const dashLayoutDoc = Doc.Layout(dashDoc); - const finalLayout = node.attrs.docid ? dashDoc : this._textBox.props.Document instanceof Doc && (Doc.expandTemplateLayout(dashLayoutDoc, - dashLayoutDoc !== dashDoc || !Doc.AreProtosEqual(this._textBox.dataDoc, this._textBox.props.Document) ? this._textBox.dataDoc : undefined, node.attrs.fieldKey)); + const finalLayout = node.attrs.docid ? dashDoc : Doc.expandTemplateLayout(dashLayoutDoc, dashDoc, node.attrs.fieldKey); if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc, node, view, getPos), 0); else { this._reactionDisposer?.(); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 6eeceb552..a4502cced 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -119,11 +119,10 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @computed get previewPanel() { - const layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined; return
boolean, select: (ctrl: boolean) => void, layoutKey: string, + forceLayout?: string, + forceFieldKey?: string }> { @computed get layout(): string { TraceMobx(); @@ -94,20 +96,23 @@ export class DocumentContentsView extends React.Component 12 || !this.layout || !this.layoutDoc) ? (null) : - + : + { console.log(test); }} - />; + onError={(test: any) => { console.log(test); }} + />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 080c722b2..1dee25c51 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -981,25 +981,6 @@ export class DocumentView extends DocComponent(Docu return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true; } - // bcz: ARGH! these two are the same as in DocumentContentsView (without the _). They should be reconciled to be the same functions... - get _dataDoc() { - if (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string") { - // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), - // then we render the layout document as a template and use this document as the data context for the template layout. - const proto = Doc.GetProto(this.props.Document); - return proto instanceof Promise ? undefined : proto; - } - return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc; - } - get _layoutDoc() { - if (this.props.LayoutDoc || (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string")) { - // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), - // then we render the layout document as a template and use this document as the data context for the template layout. - return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document); - } - return Doc.Layout(this.props.Document); - } - @computed get innards() { TraceMobx(); if (!this.props.PanelWidth()) { @@ -1022,11 +1003,16 @@ export class DocumentView extends DocComponent(Docu
); const captionView = (!showCaption ? (null) :
- +
); const titleView = (!showTitle ? (null) :
Date: Wed, 1 Apr 2020 17:15:14 -0400 Subject: fixed warnings and some compile errors. Made a key value layout and extened DocumentBox to have a childLayoutKey field --- src/client/ClientRecommender.tsx | 54 +++++----- src/client/cognitive_services/CognitiveServices.ts | 36 +++---- src/client/documents/Documents.ts | 3 +- src/client/util/RichTextSchema.tsx | 18 ++-- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/EditableView.tsx | 22 ++-- src/client/views/GestureOverlay.tsx | 8 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/MainView.tsx | 2 + src/client/views/RecommendationsBox.tsx | 16 +-- src/client/views/TemplateMenu.tsx | 8 +- src/client/views/TouchScrollableMenu.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/CollectionSchemaCells.tsx | 2 + .../views/collections/CollectionSchemaView.tsx | 8 +- .../views/collections/CollectionStackingView.tsx | 2 +- .../CollectionStackingViewFieldColumn.tsx | 3 +- .../views/collections/CollectionStaffView.tsx | 12 +-- src/client/views/collections/CollectionSubView.tsx | 3 +- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/CollectionViewChromes.tsx | 10 +- .../CollectionFreeFormLinksView.tsx | 116 ++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- src/client/views/nodes/ButtonBox.tsx | 2 +- .../views/nodes/ContentFittingDocumentView.tsx | 2 + src/client/views/nodes/DocumentBox.tsx | 3 +- src/client/views/nodes/DocumentContentsView.tsx | 24 +++-- src/client/views/nodes/KeyValuePair.tsx | 2 + src/client/views/nodes/RadialMenuItem.tsx | 30 +++--- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/webcam/DashWebRTCVideo.tsx | 8 +- src/mobile/MobileInterface.tsx | 2 + src/new_fields/Doc.ts | 4 +- src/new_fields/util.ts | 2 +- .../Session/agents/applied_session_agent.ts | 2 +- src/server/DashSession/Session/agents/monitor.ts | 2 +- .../Session/agents/promisified_ipc_manager.ts | 6 +- src/server/Websocket/Websocket.ts | 8 +- src/server/database.ts | 2 +- src/server/server_Initialization.ts | 2 +- 43 files changed, 232 insertions(+), 218 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx index 0e67a6e57..537e331ab 100644 --- a/src/client/ClientRecommender.tsx +++ b/src/client/ClientRecommender.tsx @@ -69,7 +69,7 @@ export class ClientRecommender extends React.Component { */ private distance(vector1: number[], vector2: number[], metric: string = "cosine") { - assert(vector1.length === vector2.length, "Vectors are not the same length"); + // assert(vector1.length === vector2.length, "Vectors are not the same length"); let similarity: number; switch (metric) { case "cosine": @@ -113,7 +113,7 @@ export class ClientRecommender extends React.Component { } } ); - let doclist = Array.from(ClientRecommender.Instance.docVectors); + const doclist = Array.from(ClientRecommender.Instance.docVectors); if (distance_metric === "euclidian") { doclist.sort((a: RecommenderDocument, b: RecommenderDocument) => a.score - b.score); } @@ -169,12 +169,12 @@ export class ClientRecommender extends React.Component { */ generateMetadata = async (dataDoc: Doc, extDoc: Doc, threshold: Confidence = Confidence.Excellent) => { - let converter = (results: any) => { - let tagDoc = new Doc; - let tagsList = new List(); + const converter = (results: any) => { + const tagDoc = new Doc; + const tagsList = new List(); results.tags.map((tag: Tag) => { tagsList.push(tag.name); - let sanitized = tag.name.replace(" ", "_"); + const sanitized = tag.name.replace(" ", "_"); tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`); }); extDoc.generatedTags = tagsList; @@ -193,7 +193,7 @@ export class ClientRecommender extends React.Component { */ private url(dataDoc: Doc) { - let data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField); + const data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField); return data ? data.url.href : undefined; } @@ -215,14 +215,14 @@ export class ClientRecommender extends React.Component { } } else { - let fielddata = Cast(dataDoc.data, RichTextField); - fielddata ? data = fielddata[ToPlainText]() : data = ""; + const fielddata = Cast(dataDoc.data, RichTextField, null); + data = fielddata?.Text || ""; } // STEP 2. Upon receiving response from Text Cognitive Services, do additional processing on keywords. // Currently we are still using Cognitive Services for internal recommendations, but in the future this might not be necessary. - let converter = async (results: any, data: string, isImage: boolean = false) => { + const converter = async (results: any, data: string, isImage: boolean = false) => { let keyterms = new List(); // raw keywords let kp_string: string = ""; // keywords*frequency concatenated into a string. input into TF let highKP: string[] = [""]; // most frequent keyphrase @@ -237,7 +237,7 @@ export class ClientRecommender extends React.Component { } else { // text processing results.documents.forEach((doc: any) => { - let keyPhrases = doc.keyPhrases; // returned by Cognitive Services + const keyPhrases = doc.keyPhrases; // returned by Cognitive Services keyPhrases.map((kp: string) => { keyterms.push(kp); const frequency = this.countFrequencies(kp, data); // frequency of keyphrase in paragraph @@ -308,10 +308,10 @@ export class ClientRecommender extends React.Component { */ private countFrequencies(keyphrase: string, paragraph: string) { - let data = paragraph.split(/ |\n/); // splits by new lines and spaces - let kp_array = keyphrase.split(" "); - let num_keywords = kp_array.length; - let par_length = data.length; + const data = paragraph.split(/ |\n/); // splits by new lines and spaces + const kp_array = keyphrase.split(" "); + const num_keywords = kp_array.length; + const par_length = data.length; let frequency = 0; // slides keyphrase windows across paragraph and checks if it matches with corresponding paragraph slice for (let i = 0; i <= par_length - num_keywords; i++) { @@ -353,8 +353,8 @@ export class ClientRecommender extends React.Component { bingWebSearch = async (query: string) => { const converter = async (results: any) => { - let title_vals: string[] = []; - let url_vals: string[] = []; + const title_vals: string[] = []; + const url_vals: string[] = []; results.webPages.value.forEach((doc: any) => { title_vals.push(doc.name); url_vals.push(doc.url); @@ -369,23 +369,23 @@ export class ClientRecommender extends React.Component { */ arxivrequest = async (query: string) => { - let xhttp = new XMLHttpRequest(); - let serveraddress = "http://export.arxiv.org/api"; + const xhttp = new XMLHttpRequest(); + const serveraddress = "http://export.arxiv.org/api"; const maxresults = 5; - let endpoint = serveraddress + "/query?search_query=all:" + query + "&start=0&max_results=" + maxresults.toString(); - let promisified = (resolve: any, reject: any) => { + const endpoint = serveraddress + "/query?search_query=all:" + query + "&start=0&max_results=" + maxresults.toString(); + const promisified = (resolve: any, reject: any) => { xhttp.onreadystatechange = function () { if (this.readyState === 4) { - let result = xhttp.response; - let xml = xhttp.responseXML; + const result = xhttp.response; + const xml = xhttp.responseXML; console.log("arXiv Result: ", xml); switch (this.status) { case 200: - let title_vals: string[] = []; - let url_vals: string[] = []; + const title_vals: string[] = []; + const url_vals: string[] = []; //console.log(result); if (xml) { - let titles = xml.getElementsByTagName("title"); + const titles = xml.getElementsByTagName("title"); let counter = 1; if (titles && titles.length > 1) { while (counter <= maxresults) { @@ -394,7 +394,7 @@ export class ClientRecommender extends React.Component { counter++; } } - let ids = xml.getElementsByTagName("id"); + const ids = xml.getElementsByTagName("id"); counter = 1; if (ids && ids.length > 1) { while (counter <= maxresults) { diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 542ccf04d..3f3726621 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -208,7 +208,7 @@ export namespace CognitiveServices { results.recognitionUnits && (results = results.recognitionUnits); } return results; - } + }; } export interface AzureStrokeData { @@ -232,13 +232,13 @@ export namespace CognitiveServices { return data; }, requester: async (apiKey: string, query: string) => { - let xhttp = new XMLHttpRequest(); - let serverAddress = "https://api.cognitive.microsoft.com"; - let endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query); - let promisified = (resolve: any, reject: any) => { + const xhttp = new XMLHttpRequest(); + const serverAddress = "https://api.cognitive.microsoft.com"; + const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query); + const promisified = (resolve: any, reject: any) => { xhttp.onreadystatechange = function () { if (this.readyState === 4) { - let result = xhttp.responseText; + const result = xhttp.responseText; switch (this.status) { case 200: return resolve(result); @@ -266,7 +266,7 @@ export namespace CognitiveServices { export namespace Appliers { export const analyzer = async (query: string, converter: BingConverter) => { - let results = await ExecuteQuery(Service.Bing, Manager, query); + const results = await ExecuteQuery(Service.Bing, Manager, query); console.log("Bing results: ", results); const { title_vals, url_vals } = await converter(results); return { title_vals, url_vals }; @@ -281,13 +281,13 @@ export namespace CognitiveServices { return data; }, requester: async (apiKey: string, query: string) => { - let xhttp = new XMLHttpRequest(); - let serverAddress = "https://babel.hathitrust.org/cgi/htd/​"; - let endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query); - let promisified = (resolve: any, reject: any) => { + const xhttp = new XMLHttpRequest(); + const serverAddress = "https://babel.hathitrust.org/cgi/htd/​"; + const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query); + const promisified = (resolve: any, reject: any) => { xhttp.onreadystatechange = function () { if (this.readyState === 4) { - let result = xhttp.responseText; + const result = xhttp.responseText; switch (this.status) { case 200: return resolve(result); @@ -315,7 +315,7 @@ export namespace CognitiveServices { export namespace Appliers { export const analyzer = async (query: string, converter: BingConverter) => { - let results = await ExecuteQuery(Service.Bing, Manager, query); + const results = await ExecuteQuery(Service.Bing, Manager, query); console.log("Bing results: ", results); const { title_vals, url_vals } = await converter(results); return { title_vals, url_vals }; @@ -337,9 +337,9 @@ export namespace CognitiveServices { }); }, requester: async (apiKey: string, body: string, service: Service) => { - let serverAddress = "https://eastus.api.cognitive.microsoft.com"; - let endpoint = serverAddress + "/text/analytics/v2.1/keyPhrases"; - let sampleBody = { + const serverAddress = "https://eastus.api.cognitive.microsoft.com"; + const endpoint = serverAddress + "/text/analytics/v2.1/keyPhrases"; + const sampleBody = { "documents": [ { "language": "en", @@ -348,7 +348,7 @@ export namespace CognitiveServices { } ] }; - let actualBody = body; + const actualBody = body; const options = { uri: endpoint, body: actualBody, @@ -368,7 +368,7 @@ export namespace CognitiveServices { console.log("vectorizing..."); //keyterms = ["father", "king"]; - let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true }; + const args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true }; await requestPromise.post(args).then(async (wordvecs) => { if (wordvecs) { const indices = Object.keys(wordvecs); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index dbea8062e..96425ba30 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -266,7 +266,7 @@ export namespace Docs { options: { _width: 40, _height: 40, borderRounding: "100%" }, }], [DocumentType.RECOMMENDATION, { - layout: { view: RecommendationsBox }, + layout: { view: RecommendationsBox, dataField: data }, options: { width: 200, height: 200 }, }], [DocumentType.WEBCAM, { @@ -365,6 +365,7 @@ export namespace Docs { const options = { title, type, baseProto: true, ...defaultOptions, ...(template.options || {}) }; options.layout = layout.view.LayoutString(layout.dataField); const doc = Doc.assign(new Doc(prototypeId, true), { layoutKey: "layout", ...options }); + doc.layout_keyValue = KeyValueBox.LayoutString(""); return doc; } diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a2fb7c11b..81ab95ff5 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -810,7 +810,7 @@ export class DashDocView { this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px"; this._outer.style.border = "1px solid " + StrCast(finalLayout.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray")); }, { fireImmediately: true }); - let doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => { + const doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => { ReactDOM.unmountComponentAtNode(this._dashSpan); ReactDOM.render( { if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { @@ -939,7 +939,7 @@ export class DashFieldView { this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; this._fieldCheck.onchange = function (e: any) { self._dashDoc![self._fieldKey] = e.target.checked; - } + }; this._fieldSpan = document.createElement("div"); this._fieldSpan.id = Utils.GenerateGuid(); @@ -1095,12 +1095,12 @@ export class FootnoteView { "Mod-y": () => redo(this.outerView.state, this.outerView.dispatch), "Mod-b": toggleMark(schema.marks.strong) }), - new Plugin({ - view(newView) { - // TODO -- make this work with RichTextMenu - // return FormattedTextBox.getToolTip(newView); - } - }) + // new Plugin({ + // view(newView) { + // // TODO -- make this work with RichTextMenu + // // return FormattedTextBox.getToolTip(newView); + // } + // }) ], }), diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index e673189f9..c6fb9ad0b 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -39,7 +39,7 @@ library.add(faCheckCircle); library.add(faCloudUploadAlt); library.add(faSyncAlt); library.add(faShare); -library.add(faPhotoVideo) +library.add(faPhotoVideo); const cloud: IconProp = "cloud-upload-alt"; const fetch: IconProp = "sync-alt"; diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 4a27425e8..2219966e5 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -4,10 +4,7 @@ import { observer } from 'mobx-react'; import * as Autosuggest from 'react-autosuggest'; import { ObjectField } from '../../new_fields/ObjectField'; import { SchemaHeaderField } from '../../new_fields/SchemaHeaderField'; -import { ContextMenu } from './ContextMenu'; -import { ContextMenuProps } from './ContextMenuItem'; import "./EditableView.scss"; -import { CollectionTreeView } from './collections/CollectionTreeView'; export interface EditableProps { /** @@ -88,12 +85,12 @@ export class EditableView extends React.Component { onKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Tab") { e.stopPropagation(); - this.finalizeEdit(e.currentTarget.value, e.shiftKey); + this.finalizeEdit(e.currentTarget.value, e.shiftKey, false); this.props.OnTab && this.props.OnTab(e.shiftKey); } else if (e.key === "Enter") { e.stopPropagation(); if (!e.ctrlKey) { - this.finalizeEdit(e.currentTarget.value, e.shiftKey); + this.finalizeEdit(e.currentTarget.value, e.shiftKey, false); } else if (this.props.OnFillDown) { this.props.OnFillDown(e.currentTarget.value); this._editing = false; @@ -123,10 +120,17 @@ export class EditableView extends React.Component { } @action - private finalizeEdit(value: string, shiftDown: boolean) { - this._editing = false; + private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean) { if (this.props.SetValue(value, shiftDown)) { + this._editing = false; + this.props.isEditingCallback?.(false); + } else { + this._editing = false; this.props.isEditingCallback?.(false); + !lostFocus && setTimeout(action(() => { + this._editing = true; + this.props.isEditingCallback?.(true); + }), 0); } } @@ -151,7 +155,7 @@ export class EditableView extends React.Component { className: "editableView-input", onKeyDown: this.onKeyDown, autoFocus: true, - onBlur: e => this.finalizeEdit(e.currentTarget.value, false), + onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true), onPointerDown: this.stopPropagation, onClick: this.stopPropagation, onPointerUp: this.stopPropagation, @@ -163,7 +167,7 @@ export class EditableView extends React.Component { defaultValue={this.props.GetValue()} onKeyDown={this.onKeyDown} autoFocus={true} - onBlur={e => this.finalizeEdit(e.currentTarget.value, false)} + onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} style={{ display: this.props.display, fontSize: this.props.fontSize }} />; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 1eff58948..ea60907f6 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -165,7 +165,7 @@ export default class GestureOverlay extends Touchable { this._holdTimer = setTimeout(() => { console.log("hold"); const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY); - let pt: any = te.touches[te.touches.length - 1]; + const pt: any = te.touches[te.touches.length - 1]; if (nts.nt.length === 1 && pt.radiusX > 1 && pt.radiusY > 1) { target?.dispatchEvent( new CustomEvent>("dashOnTouchHoldStart", @@ -589,7 +589,7 @@ export default class GestureOverlay extends Touchable { for (const wR of wordResults) { console.log(wR); if (wR?.recognizedText) { - possibilities.push(wR?.recognizedText) + possibilities.push(wR?.recognizedText); } possibilities.push(...wR?.alternates?.map((a: any) => a.recognizedString)); } @@ -743,16 +743,16 @@ export default class GestureOverlay extends Touchable { {this.elements}
{this._clipboardDoc}
{ - let stopPropagation = false; - let preventDefault = false; + const stopPropagation = false; + const preventDefault = false; switch (keyname) { // case "~": diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a81e0cc2c..8d9be5980 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -521,7 +521,9 @@ export class MainView extends React.Component { DataDoc={undefined} LibraryPath={emptyPath} fieldKey={"data"} + dropAction={"alias"} annotationsKey={""} + bringToFront={emptyFunction} select={emptyFunction} active={returnFalse} isSelected={returnFalse} diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx index 262226bac..5ebba0abb 100644 --- a/src/client/views/RecommendationsBox.tsx +++ b/src/client/views/RecommendationsBox.tsx @@ -6,7 +6,7 @@ import "./RecommendationsBox.scss"; import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc"; import { DocumentIcon } from "./nodes/DocumentIcon"; import { StrCast, NumCast } from "../../new_fields/Types"; -import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils"; +import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath } from "../../Utils"; import { Transform } from "../util/Transform"; import { ObjectField } from "../../new_fields/ObjectField"; import { DocumentView } from "./nodes/DocumentView"; @@ -31,7 +31,7 @@ library.add(faBullseye, faLink); @observer export class RecommendationsBox extends React.Component { - public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); } + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); } // @observable private _display: boolean = false; @observable private _pageX: number = 0; @@ -48,17 +48,17 @@ export class RecommendationsBox extends React.Component { @action private DocumentIcon(doc: Doc) { - let layoutresult = StrCast(doc.type); + const layoutresult = StrCast(doc.type); let renderDoc = doc; //let box: number[] = []; if (layoutresult.indexOf(DocumentType.COL) !== -1) { renderDoc = Doc.MakeDelegate(renderDoc); } - let returnXDimension = () => 150; - let returnYDimension = () => 150; - let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension()); + const returnXDimension = () => 150; + const returnYDimension = () => 150; + const scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension()); //let scale = () => 1; - let newRenderDoc = Doc.MakeAlias(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt + const newRenderDoc = Doc.MakeAlias(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt newRenderDoc.height = NumCast(this.props.Document.documentIconHeight); newRenderDoc.autoHeight = false; const docview =
@@ -66,8 +66,8 @@ export class RecommendationsBox extends React.Component { fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1} Document={newRenderDoc} addDocument={returnFalse} + LibraryPath={emptyPath} removeDocument={returnFalse} - ruleProvider={undefined} ScreenToLocalTransform={Transform.Identity} addDocTab={returnFalse} pinToPres={returnFalse} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 83dbd3db3..996928cca 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -114,7 +114,7 @@ export class TemplateMenu extends React.Component { const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", ""); const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null); const noteTypes = DocListCast(noteTypesDoc?.data); - const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data) + const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data); const layout = Doc.Layout(firstDoc); const templateMenu: Array = []; this.props.templates.forEach((checked, template) => @@ -170,8 +170,8 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc) { if (template.dragFactory) { template = Cast(template.dragFactory, Doc, null); } - let templateTitle = StrCast(template?.title); - return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template) + const templateTitle = StrCast(template?.title); + return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template); }); Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) { @@ -180,4 +180,4 @@ Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: st const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title); return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked'; // return SelectionManager.SelectedDocuments().some(view => StrCast(view.props.Document.layoutKey) === "layout_" + template) ? 'check' : 'unchecked' -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/client/views/TouchScrollableMenu.tsx b/src/client/views/TouchScrollableMenu.tsx index 4bda0818e..969605be9 100644 --- a/src/client/views/TouchScrollableMenu.tsx +++ b/src/client/views/TouchScrollableMenu.tsx @@ -44,7 +44,7 @@ export default class TouchScrollableMenu extends React.Component
- ) + ); } } @@ -54,6 +54,6 @@ export class TouchScrollableMenuItem extends React.Component {this.props.text}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2ee39bc0d..4e1e76f39 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -513,7 +513,7 @@ export class CollectionDockingView extends React.Component ((view: Opt) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)), (views) => { diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 79b5d7bb7..f124fe21b 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -157,6 +157,8 @@ export class CollectionSchemaCell extends React.Component { Document: this.props.rowProps.original, DataDoc: this.props.rowProps.original, LibraryPath: [], + dropAction: "alias", + bringToFront: emptyFunction, fieldKey: this.props.rowProps.column.id as string, ContainingCollectionView: this.props.CollectionView, ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document, diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index a4502cced..981438513 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -51,8 +51,7 @@ const columnTypes: Map = new Map([ @observer export class CollectionSchemaView extends CollectionSubView(doc => doc) { - private _mainCont?: HTMLDivElement; - private _startPreviewWidth = 0; + private _previewCont?: HTMLDivElement; private DIVIDER_WIDTH = 4; @observable previewDoc: Doc | undefined = undefined; @@ -64,7 +63,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } private createTarget = (ele: HTMLDivElement) => { - this._mainCont = ele; + this._previewCont = ele; super.CreateDropTarget(ele); } @@ -81,12 +80,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } onDividerDown = (e: React.PointerEvent) => { - this._startPreviewWidth = this.previewWidth(); setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, action(() => this.toggleExpander())); } @action onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => { - const nativeWidth = this._mainCont!.getBoundingClientRect(); + const nativeWidth = this._previewCont!.getBoundingClientRect(); const minWidth = 40; const maxWidth = 1000; const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 086e0842e..076dd3629 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -106,7 +106,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { fields.delete(header); sectionHeaders.splice(sectionHeaders.indexOf(header), 1); changed = true; - }) + }); } changed && setTimeout(action(() => { if (this.sectionHeaders) { this.sectionHeaders.length = 0; this.sectionHeaders.push(...sectionHeaders); } }), 0); return fields; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 646b433bf..0a48c95e4 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -131,7 +131,8 @@ export class CollectionStackingViewFieldColumn extends React.Component NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3; newDoc.heading = heading; - return this.props.parent.props.addDocument(newDoc); + this.props.parent.props.addDocument(newDoc); + return false; } @action diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx index 8c7e113b2..5b9a69bf7 100644 --- a/src/client/views/collections/CollectionStaffView.tsx +++ b/src/client/views/collections/CollectionStaffView.tsx @@ -1,22 +1,20 @@ import { CollectionSubView } from "./CollectionSubView"; -import { Transform } from "../../util/Transform"; import React = require("react"); import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx"; -import { Doc } from "../../../new_fields/Doc"; import { NumCast } from "../../../new_fields/Types"; import "./CollectionStaffView.scss"; import { observer } from "mobx-react"; @observer export class CollectionStaffView extends CollectionSubView(doc => doc) { - private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(0, -this._mainCont.current!.scrollTop); - private _mainCont = React.createRef(); private _reactionDisposer: IReactionDisposer | undefined; @observable private _staves = NumCast(this.props.Document.staves); + componentWillUnmount() { + this._reactionDisposer?.(); + } componentDidMount = () => { - this._reactionDisposer = reaction( - () => NumCast(this.props.Document.staves), + this._reactionDisposer = reaction(() => NumCast(this.props.Document.staves), (staves) => runInAction(() => this._staves = staves) ); @@ -47,7 +45,7 @@ export class CollectionStaffView extends CollectionSubView(doc => doc) { } render() { - return
+ return
{this.staves} {this.addStaffButton}
; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 88cfde0b6..70927cf22 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,5 +1,4 @@ import { action, computed, IReactionDisposer, reaction } from "mobx"; -import * as rp from 'request-promise'; import CursorField from "../../../new_fields/CursorField"; import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; @@ -107,7 +106,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: get childLayoutPairs(): { layout: Doc; data: Doc; }[] { const { Document, DataDoc } = this.props; const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout); - return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types + return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types } get childDocList() { return Cast(this.dataField, listSpec(Doc)); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 64832506b..0d2207b27 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -146,7 +146,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { back -
+
; } render() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index edb9fd930..b6ce2f3a9 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -299,7 +299,7 @@ export class CollectionView extends Touchable { get childLayoutPairs(): { layout: Doc; data: Doc; }[] { const { Document, DataDoc } = this.props; const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout); - return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types + return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types } get childDocList() { return Cast(this.dataField, listSpec(Doc)); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 960c6554e..2d565d9db 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -267,10 +267,10 @@ export class CollectionViewBaseChrome extends React.Component); - case CollectionViewType.Schema: return (); - case CollectionViewType.Tree: return (); - case CollectionViewType.Masonry: return (); + case CollectionViewType.Stacking: return (); + case CollectionViewType.Schema: return (); + case CollectionViewType.Tree: return (); + case CollectionViewType.Masonry: return (); default: return null; } } @@ -355,7 +355,7 @@ export class CollectionViewBaseChrome extends React.Component Doc.setChildLayout(this.target, source?.[0]), initialize: emptyFunction, }; - DragManager.StartButtonDrag([this._viewRef.current!], c.script, c.title, + DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title), { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY); return true; }, emptyFunction, emptyFunction); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index a1ec0daef..49ca024a2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,4 +1,4 @@ -import { computed, IReactionDisposer } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; @@ -10,67 +10,9 @@ import React = require("react"); import { Utils, emptyFunction } from "../../../../Utils"; import { SelectionManager } from "../../../util/SelectionManager"; import { DocumentType } from "../../../documents/DocumentTypes"; -import { StrCast } from "../../../../new_fields/Types"; @observer export class CollectionFreeFormLinksView extends React.Component { - - _brushReactionDisposer?: IReactionDisposer; - componentDidMount() { - // this._brushReactionDisposer = reaction( - // () => { - // let doclist = DocListCast(this.props.Document[this.props.fieldKey]); - // return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) }; - // }, - // () => { - // let doclist = DocListCast(this.props.Document[this.props.fieldKey]); - // let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : []; - // views.forEach((dstDoc, i) => { - // views.forEach((srcDoc, j) => { - // let dstTarg = dstDoc; - // let srcTarg = srcDoc; - // let x1 = NumCast(srcDoc.x); - // let x2 = NumCast(dstDoc.x); - // let x1w = NumCast(srcDoc.width, -1); - // let x2w = NumCast(dstDoc.width, -1); - // if (x1w < 0 || x2w < 0 || i === j) { } - // else { - // let findBrush = (field: (Doc | Promise)[]) => field.findIndex(brush => { - // let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined; - // return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false; - // }); - // let brushAction = (field: (Doc | Promise)[]) => { - // let found = findBrush(field); - // if (found !== -1) { - // field.splice(found, 1); - // } - // }; - // if (Math.abs(x1 + x1w - x2) < 20) { - // let linkDoc: Doc = new Doc(); - // linkDoc.title = "Histogram Brush"; - // linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title); - // linkDoc.brushingDocs = new List([dstTarg, srcTarg]); - - // brushAction = (field: (Doc | Promise)[]) => { - // if (findBrush(field) === -1) { - // field.push(linkDoc); - // } - // }; - // } - // if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List(); - // if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List(); - // let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []); - // let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []); - // brushAction(dstBrushDocs); - // brushAction(srcBrushDocs); - // } - // }); - // }); - // }); - } - componentWillUnmount() { - this._brushReactionDisposer && this._brushReactionDisposer(); - } @computed get uniqueConnections() { const connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => { @@ -101,4 +43,60 @@ export class CollectionFreeFormLinksView extends React.Component { {this.props.children}
; } + // _brushReactionDisposer?: IReactionDisposer; + // componentDidMount() { + // this._brushReactionDisposer = reaction( + // () => { + // let doclist = DocListCast(this.props.Document[this.props.fieldKey]); + // return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) }; + // }, + // () => { + // let doclist = DocListCast(this.props.Document[this.props.fieldKey]); + // let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : []; + // views.forEach((dstDoc, i) => { + // views.forEach((srcDoc, j) => { + // let dstTarg = dstDoc; + // let srcTarg = srcDoc; + // let x1 = NumCast(srcDoc.x); + // let x2 = NumCast(dstDoc.x); + // let x1w = NumCast(srcDoc.width, -1); + // let x2w = NumCast(dstDoc.width, -1); + // if (x1w < 0 || x2w < 0 || i === j) { } + // else { + // let findBrush = (field: (Doc | Promise)[]) => field.findIndex(brush => { + // let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined; + // return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false; + // }); + // let brushAction = (field: (Doc | Promise)[]) => { + // let found = findBrush(field); + // if (found !== -1) { + // field.splice(found, 1); + // } + // }; + // if (Math.abs(x1 + x1w - x2) < 20) { + // let linkDoc: Doc = new Doc(); + // linkDoc.title = "Histogram Brush"; + // linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title); + // linkDoc.brushingDocs = new List([dstTarg, srcTarg]); + + // brushAction = (field: (Doc | Promise)[]) => { + // if (findBrush(field) === -1) { + // field.push(linkDoc); + // } + // }; + // } + // if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List(); + // if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List(); + // let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []); + // let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []); + // brushAction(dstBrushDocs); + // brushAction(srcBrushDocs); + // } + // }); + // }); + // }); + // } + // componentWillUnmount() { + // this._brushReactionDisposer?.(); + // } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0f94bffd6..276a49570 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -4,7 +4,7 @@ import { Doc, DocListCast, DataSym, WidthSym, HeightSym } from "../../../../new_ import { InkField, InkData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; -import { Cast, NumCast, FieldValue } from "../../../../new_fields/Types"; +import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types"; import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; import { Utils } from "../../../../Utils"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -107,7 +107,7 @@ export class MarqueeView extends React.Component(Butt style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
{(this.Document.text || this.Document.title)} diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 8632f9c9a..9494a4bc4 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -22,6 +22,7 @@ interface ContentFittingDocumentViewProps { childDocs?: Doc[]; renderDepth: number; fitToBox?: boolean; + layoutKey?: string; dropAction?: dropActionType; PanelWidth: () => number; PanelHeight: () => number; @@ -88,6 +89,7 @@ export class ContentFittingDocumentView extends React.Componentawaiting layout

"; const layout = Cast(this.layoutDoc[StrCast(this.layoutDoc.layoutKey, this.layoutDoc === this.props.Document ? this.props.layoutKey : "layout")], "string"); - if (layout === undefined) { - return this.props.Document.data ? - "" : - KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : ""); - } else if (typeof layout === "string") { - return layout; - } else { - return "

Loading layout

"; - } + if (this.props.layoutKey === "layout_keyValue") { + return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data")); + } else + if (layout === undefined) { + return this.props.Document.data ? + "" : + KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : ""); + } else if (typeof layout === "string") { + return layout; + } else { + return "

Loading layout

"; + } } get dataDoc() { @@ -81,7 +84,8 @@ export class DocumentContentsView extends React.Component { fieldKey: this.props.keyName, isSelected: returnFalse, select: emptyFunction, + dropAction:"alias", + bringToFront:emptyFunction, renderDepth: 1, active: returnFalse, whenActiveChanged: emptyFunction, diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index fdc732d3f..bd5b3bff4 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -44,12 +44,12 @@ export class RadialMenuItem extends React.Component { setcircle() { let circlemin = 0; - let circlemax = 1 + let circlemax = 1; this.props.min ? circlemin = this.props.min : null; this.props.max ? circlemax = this.props.max : null; if (document.getElementById("myCanvas") !== null) { - var c: any = document.getElementById("myCanvas"); - let color = "white" + const c: any = document.getElementById("myCanvas"); + let color = "white"; switch (circlemin % 3) { case 1: color = "#c2c2c5"; @@ -70,38 +70,38 @@ export class RadialMenuItem extends React.Component { } if (c.getContext) { - var ctx = c.getContext("2d"); + const ctx = c.getContext("2d"); ctx.beginPath(); ctx.arc(150, 150, 150, (circlemin / circlemax) * 2 * Math.PI, ((circlemin + 1) / circlemax) * 2 * Math.PI); ctx.arc(150, 150, 50, ((circlemin + 1) / circlemax) * 2 * Math.PI, (circlemin / circlemax) * 2 * Math.PI, true); ctx.fillStyle = color; - ctx.fill() + ctx.fill(); } } } calculatorx() { let circlemin = 0; - let circlemax = 1 + let circlemax = 1; this.props.min ? circlemin = this.props.min : null; this.props.max ? circlemax = this.props.max : null; - let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; - let degrees = 360 * avg; - let x = 100 * Math.cos(degrees * Math.PI / 180); - let y = -125 * Math.sin(degrees * Math.PI / 180); + const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + const degrees = 360 * avg; + const x = 100 * Math.cos(degrees * Math.PI / 180); + const y = -125 * Math.sin(degrees * Math.PI / 180); return x; } calculatory() { let circlemin = 0; - let circlemax = 1 + let circlemax = 1; this.props.min ? circlemin = this.props.min : null; this.props.max ? circlemax = this.props.max : null; - let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; - let degrees = 360 * avg; - let x = 125 * Math.cos(degrees * Math.PI / 180); - let y = -100 * Math.sin(degrees * Math.PI / 180); + const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + const degrees = 360 * avg; + const x = 125 * Math.cos(degrees * Math.PI / 180); + const y = -100 * Math.sin(degrees * Math.PI / 180); return y; } diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 548066f1c..7c58a5148 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -142,7 +142,7 @@ export class ScreenshotBox extends DocAnnotatableComponent { this._screenCapture = !this._screenCapture; this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); - }) + }); private get uIButtons() { return (
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 591864f2c..838fbefb1 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -63,7 +63,7 @@ export class WebBox extends DocAnnotatableComponent this.layoutDoc._height = NumCast(this.layoutDoc._width) / youtubeaspect; } } else if (field?.url) { - var result = await WebRequest.get(Utils.CorsProxy(field.url.href)); + const result = await WebRequest.get(Utils.CorsProxy(field.url.href)); this.dataDoc.text = htmlToText.fromString(result.content); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a1e7d5c2a..cc187cd67 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -238,7 +238,7 @@ export class PDFViewer extends DocAnnotatableComponent { if (e.keyCode === 13) { - let submittedTitle = this.roomText!.value; + const submittedTitle = this.roomText!.value; this.roomText!.value = ""; this.roomText!.blur(); initialize(submittedTitle, this.changeUILook); @@ -56,7 +56,7 @@ export class DashWebRTCVideo extends React.Component
DashWebRTC
this.roomText = e!} onKeyDown={this.onEnterKeyDown} /> @@ -72,8 +72,8 @@ export class DashWebRTCVideo extends React.Component
; - let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; + const classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 5d3a517ae..1d2d57b96 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -199,6 +199,8 @@ export default class MobileInterface extends React.Component { DataDoc={undefined} LibraryPath={emptyPath} fieldKey={""} + dropAction={"alias"} + bringToFront={emptyFunction } addDocTab={returnFalse} pinToPres={emptyFunction} PanelHeight={() => window.innerHeight} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 25b526168..440f13d6b 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -353,7 +353,7 @@ export namespace Doc { // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype'). export function GetProto(doc: Doc): Doc { if (doc instanceof Promise) { - console.log("GetProto: error: got Promise insead of Doc") + console.log("GetProto: error: got Promise insead of Doc"); } const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc)); return proto === doc ? proto : Doc.GetProto(proto); @@ -697,7 +697,7 @@ export namespace Doc { // the document containing the view layout information - will be the Document itself unless the Document has // a layout field or 'layout' is given. export function Layout(doc: Doc, layout?: Doc): Doc { - const overrideLayout = layout && Cast(doc["data-layout[" + layout[Id] + "]"], Doc, null); + const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, "data")}-layout[` + layout[Id] + "]"], Doc, null); return overrideLayout || doc[LayoutSym] || doc; } export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 3a1fd41f8..8c719ccd8 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -12,7 +12,7 @@ function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); } -let tracing = false; +const tracing = false; export function TraceMobx() { tracing && trace(); } diff --git a/src/server/DashSession/Session/agents/applied_session_agent.ts b/src/server/DashSession/Session/agents/applied_session_agent.ts index 46c9e22ed..12064668b 100644 --- a/src/server/DashSession/Session/agents/applied_session_agent.ts +++ b/src/server/DashSession/Session/agents/applied_session_agent.ts @@ -44,7 +44,7 @@ export abstract class AppliedSessionAgent { if (!this.launched) { this.launched = true; if (isMaster) { - this.sessionMonitorRef = Monitor.Create() + this.sessionMonitorRef = Monitor.Create(); const sessionKey = await this.initializeMonitor(this.sessionMonitorRef); this.sessionMonitorRef.finalize(sessionKey); } else { diff --git a/src/server/DashSession/Session/agents/monitor.ts b/src/server/DashSession/Session/agents/monitor.ts index 6f8d25614..ee8afee65 100644 --- a/src/server/DashSession/Session/agents/monitor.ts +++ b/src/server/DashSession/Session/agents/monitor.ts @@ -167,7 +167,7 @@ export class Monitor extends IPCMessageReceiver { * and pass down any variables the pertinent to the child processes as environment variables. */ private loadAndValidateConfiguration = (): Configuration => { - let config: Configuration; + let config: Configuration | undefined; try { console.log(this.timestamp(), cyan("validating configuration...")); config = JSON.parse(readFileSync('./session.config.json', 'utf8')); diff --git a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts index 9f0db8330..feff568e1 100644 --- a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts +++ b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts @@ -35,8 +35,8 @@ export type MessageHandler = (args: T) => (any | Promise); * When a message is emitted, it is embedded with private metadata * to facilitate the resolution of promises, etc. */ -interface InternalMessage extends Message { metadata: Metadata } -interface Metadata { isResponse: boolean; id: string } +interface InternalMessage extends Message { metadata: Metadata; } +interface Metadata { isResponse: boolean; id: string; } type InternalMessageHandler = (message: InternalMessage) => (any | Promise); /** @@ -133,7 +133,7 @@ export class PromisifiedIPCManager { Object.keys(pendingMessages).forEach(id => { const error: ErrorLike = { name: "ManagerDestroyed", message: "The IPC manager was destroyed before the response could be returned." }; const message: InternalMessage = { name: pendingMessages[id], args: { error }, metadata: { id, isResponse: true } }; - this.target.send?.(message) + this.target.send?.(message); }); this.pendingMessages = {}; } diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index c5dc22912..9f9fc9619 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -55,8 +55,8 @@ export namespace WebSocket { socket.on('create or join', function (room) { console.log('Received request to create or join room ' + room); - var clientsInRoom = socket.adapter.rooms[room]; - var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; + const clientsInRoom = socket.adapter.rooms[room]; + const numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; console.log('Room ' + room + ' now has ' + numClients + ' client(s)'); if (numClients === 0) { @@ -76,8 +76,8 @@ export namespace WebSocket { }); socket.on('ipaddr', function () { - var ifaces = networkInterfaces(); - for (var dev in ifaces) { + const ifaces = networkInterfaces(); + for (const dev in ifaces) { ifaces[dev].forEach(function (details) { if (details.family === 'IPv4' && details.address !== '127.0.0.1') { socket.emit('ipaddr', details.address); diff --git a/src/server/database.ts b/src/server/database.ts index 055f04c49..fc91ff3a2 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -328,7 +328,7 @@ export namespace Database { export const LogUpload = async (information: Upload.ImageInformation) => { const bundle = { - _id: Utils.GenerateDeterministicGuid(String(information.contentSize!)), + _id: Utils.GenerateDeterministicGuid(String(information.contentSize)), ...information }; return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory); diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 7b2228831..1150118f7 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -123,7 +123,7 @@ function registerCorsProxy(server: express.Express) { const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; server.use("/corsProxy", (req, res) => { - let requrl = decodeURIComponent(req.url.substring(1)); + const requrl = decodeURIComponent(req.url.substring(1)); const referer = req.headers.referer ? decodeURIComponent(req.headers.referer) : ""; // cors weirdness here... // if the referer is a cors page and the cors() route (I think) redirected to /corsProxy/ and the requested url path was relative, -- cgit v1.2.3-70-g09d2 From 6596e9aa8a23abe6f126e9cada5e3e8b8545884f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 2 Apr 2020 12:42:44 -0400 Subject: cleaned up applying template code. fixed DocumentBox to work better with excluding collections + locking selection. --- .../apis/google_docs/GooglePhotosClientUtils.ts | 2 +- src/client/util/DragManager.ts | 1 - src/client/util/RichTextSchema.tsx | 2 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/nodes/DocumentBox.scss | 3 + src/client/views/nodes/DocumentBox.tsx | 19 +++- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 118 ++++++++------------- src/client/views/pdf/PDFViewer.tsx | 2 +- src/new_fields/Doc.ts | 10 +- src/new_fields/RichTextUtils.ts | 4 +- src/new_fields/documentSchemas.ts | 3 +- .../authentication/models/current_user_utils.ts | 21 ++-- 14 files changed, 89 insertions(+), 102 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index f8723f02d..7c4137f59 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -340,7 +340,7 @@ export namespace GooglePhotos { const url = data.url.href; const target = Doc.MakeAlias(source); const description = parseDescription(target, descriptionKey); - await DocumentView.makeCustomViewClicked(target, undefined, Docs.Create.FreeformDocument); + await DocumentView.makeCustomViewClicked(target, Docs.Create.FreeformDocument); media.push({ url, description }); } if (media.length) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 8d3f6751e..db7a54ca8 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -137,7 +137,6 @@ export namespace DragManager { userDropAction: dropActionType; embedDoc?: boolean; moveDocument?: MoveFunction; - applyAsTemplate?: boolean; isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts } export class LinkDragData { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 81ab95ff5..094cd58f3 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -776,7 +776,7 @@ export class DashDocView { if (dashDocBase instanceof Doc) { const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); aliasedDoc.layoutKey = "layout"; - node.attrs.fieldKey && DocumentView.makeCustomViewClicked(aliasedDoc, undefined, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); + node.attrs.fieldKey && DocumentView.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 996928cca..8eb5c5050 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -171,7 +171,7 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc) { template = Cast(template.dragFactory, Doc, null); } const templateTitle = StrCast(template?.title); - return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template); + return templateTitle && DocumentView.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template); }); Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) { diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 0d2207b27..4f77e8b0e 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -31,7 +31,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { componentDidMount() { this.props.Document._freezeOnDrop = true; const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked; - const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.layoutKey='layout_detailedView'; alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", containingCollection: Doc.name, shiftKey: "boolean" }); this.props.Document._fitToBox = true; if (!this.props.Document.onViewDefClick) { diff --git a/src/client/views/nodes/DocumentBox.scss b/src/client/views/nodes/DocumentBox.scss index 6fc87e4f1..ce21391ce 100644 --- a/src/client/views/nodes/DocumentBox.scss +++ b/src/client/views/nodes/DocumentBox.scss @@ -8,4 +8,7 @@ color: white; position: absolute; } + .contentFittingDocumentView { + position: absolute; + } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx index 9d1c08389..debe104d7 100644 --- a/src/client/views/nodes/DocumentBox.tsx +++ b/src/client/views/nodes/DocumentBox.tsx @@ -15,6 +15,8 @@ import "./DocumentBox.scss"; import { FieldView, FieldViewProps } from "./FieldView"; import React = require("react"); import { TraceMobx } from "../../../new_fields/util"; +import { DocumentView } from "./DocumentView"; +import { Docs } from "../../documents/Documents"; type DocBoxSchema = makeInterface<[typeof documentSchema]>; const DocBoxDocument = makeInterface(documentSchema); @@ -35,12 +37,12 @@ export class DocumentBox extends DocAnnotatableComponent { const funcs: ContextMenuProps[] = []; funcs.push({ description: (this.isSelectionLocked() ? "Show" : "Lock") + " Selection", event: () => this.toggleLockSelection, icon: "expand-arrows-alt" }); - funcs.push({ description: (this.props.Document.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => this.props.Document.excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" }); + funcs.push({ description: (this.props.Document.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => Doc.GetProto(this.props.Document).excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" }); funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" }); @@ -105,14 +107,21 @@ export class DocumentBox extends DocAnnotatableComponent this.props.PanelHeight() - 2 * this.yPad; getTransform = () => this.props.ScreenToLocalTransform().translate(-this.xPad, -this.yPad); get renderContents() { - const containedDoc = this.contentDoc[this.props.fieldKey]; + const containedDoc = Cast(this.contentDoc[this.props.fieldKey], Doc, null); + const childTemplateName = StrCast(this.props.Document.childTemplateName); + if (containedDoc && childTemplateName && !containedDoc["layout_" + childTemplateName]) { + setTimeout(() => { + DocumentView.createCustomView(containedDoc, Docs.Create.StackingDocument, childTemplateName); + Doc.expandTemplateLayout(Cast(containedDoc["layout_" + childTemplateName], Doc, null)!, containedDoc, undefined); + }, 0); + } const contents = !(containedDoc instanceof Doc) ? (null) : + {this.renderContents}
- {this.renderContents}
; } } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index da035a6ce..68501fca2 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -59,7 +59,7 @@ export class DocumentContentsView extends React.Component Opt; }> { @computed get layout(): string { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d8bbd88ce..02a1ac527 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -508,58 +508,49 @@ export class DocumentView extends DocComponent(Docu @undoBatch deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument?.(this.props.Document); } - static makeNativeViewClicked = (doc: Doc) => { - undoBatch(() => Doc.setNativeView(doc))(); - } - - static makeCustomViewClicked = (doc: Doc, dataDoc: Opt, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { - const userDoc = Doc.UserDoc(); - const imgView = Cast(userDoc.iconView, Doc, null); - const iconImgView = Cast(userDoc.iconImageView, Doc, null); - const iconColView = Cast(userDoc.iconColView, Doc, null); - const iconViews = [imgView, iconImgView, iconColView]; - const templateButtons = DocListCast(Cast(userDoc.templateButtons, Doc, null)?.data); - const noteTypes = DocListCast(Cast(userDoc.noteTypes, Doc, null)?.data); - const allTemplates = iconViews.concat(templateButtons).concat(noteTypes); - const templateName = templateSignature.replace(/\(.*\)/, ""); - !docLayoutTemplate && allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { - if (StrCast(tempDoc.title) === doc.type + "_" + templateName) { - docLayoutTemplate = tempDoc; - } - }); - !docLayoutTemplate && allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { - if (StrCast(tempDoc.title) === templateName) { - docLayoutTemplate = tempDoc; + // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView) + static makeCustomViewClicked = (doc: Doc, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { + const batch = UndoManager.StartBatch("makeCustomViewClicked"); + runInAction(() => { + doc.layoutKey = "layout_" + templateSignature; + if (doc[doc.layoutKey] === undefined) { + DocumentView.createCustomView(doc, creator, templateSignature, docLayoutTemplate); } }); + batch.end(); + } + static createCustomView = (doc: Doc, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { + const iconViews = DocListCast(Cast(Doc.UserDoc().iconViews, Doc, null)?.data); + const templBtns = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data); + const noteTypes = DocListCast(Cast(Doc.UserDoc().noteTypes, Doc, null)?.data); + const allTemplates = iconViews.concat(templBtns).concat(noteTypes).map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc); + const templateName = templateSignature.replace(/\(.*\)/, ""); + // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized + // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on + !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === doc.type + "_" + templateName && (docLayoutTemplate = tempDoc)); + !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); - const batch = UndoManager.StartBatch("CustomViewClicked"); const customName = "layout_" + templateSignature; - if (doc[customName] === undefined) { - const _width = NumCast(doc._width); - const _height = NumCast(doc._height); - const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; - - let fieldTemplate: Opt; - if (doc.data instanceof RichTextField || typeof (doc.data) === "string") { - fieldTemplate = Docs.Create.TextDocument("", options); - } else if (doc.data instanceof PdfField) { - fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); - } else if (doc.data instanceof VideoField) { - fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); - } else if (doc.data instanceof AudioField) { - fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); - } else if (doc.data instanceof ImageField) { - fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); - } - const docTemplate = docLayoutTemplate || creator(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); - - fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate)); - Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); - } else { - doc.layoutKey = customName; + const _width = NumCast(doc._width); + const _height = NumCast(doc._height); + const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; + + let fieldTemplate: Opt; + if (doc.data instanceof RichTextField || typeof (doc.data) === "string") { + fieldTemplate = Docs.Create.TextDocument("", options); + } else if (doc.data instanceof PdfField) { + fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); + } else if (doc.data instanceof VideoField) { + fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); + } else if (doc.data instanceof AudioField) { + fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); + } else if (doc.data instanceof ImageField) { + fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); } - batch.end(); + const docTemplate = docLayoutTemplate || creator(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); + + fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate)); + Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); } @undoBatch @@ -583,29 +574,6 @@ export class DocumentView extends DocComponent(Docu DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document }, "link"); } - if (de.complete.docDragData) { - if (de.complete.docDragData.applyAsTemplate) { - Doc.ApplyTemplateTo(de.complete.docDragData.draggedDocuments[0], this.props.Document, "layout_custom", undefined); - e.stopPropagation(); - } - else if (de.complete.docDragData.draggedDocuments[0].type === "text") { - const text = Cast(de.complete.docDragData.draggedDocuments[0].data, RichTextField)?.Text; - if (text && text[0] === "{" && text[text.length - 1] === "}" && text.includes(":")) { - const loc = text.indexOf(":"); - const key = text.slice(1, loc); - const value = text.slice(loc + 1, text.length - 1); - console.log(key); - console.log(value); - console.log(this.props.Document); - this.props.Document[key] = value; - console.log(de.complete.docDragData.draggedDocuments[0].x); - console.log(de.complete.docDragData.draggedDocuments[0].x); - e.preventDefault(); - e.stopPropagation(); - de.complete.aborted = true; - } - } - } if (de.complete.linkDragData) { e.stopPropagation(); // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); @@ -646,9 +614,9 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action setCustomView = (custom: boolean, layout: string): void => { - DocumentView.makeNativeViewClicked(this.props.Document); + Doc.setNativeView(this.props.Document); if (custom) { - DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, undefined); + DocumentView.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined); } } @@ -1002,9 +970,9 @@ export class DocumentView extends DocComponent(Docu const ept = Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1_timecode : linkDoc.anchor2_timecode; return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true; } -c - @observable _link:Opt; - makeLink = () => { + + @observable _link: Opt; + makeLink = () => { return this._link; } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index cc187cd67..71495d95f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -575,7 +575,7 @@ export class PDFViewer extends DocAnnotatableComponent([clipDoc]); - DocumentView.makeCustomViewClicked(targetDoc, undefined, Docs.Create.StackingDocument, "slideView", undefined); + DocumentView.makeCustomViewClicked(targetDoc, Docs.Create.StackingDocument, "slideView", undefined); // const targetDoc = Docs.Create.TextDocument("", { _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title }); // Doc.GetProto(targetDoc).snipped = this.dataDoc[this.props.fieldKey][Copy](); // const snipLayout = Docs.Create.PdfDocument("http://www.msn.com", { title: "snippetView", isTemplateDoc: true, isTemplateForField: "snipped", _fitWidth: true, _width: this.marqueeWidth(), _height: this.marqueeHeight(), _scrollTop: this.marqueeY() }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 440f13d6b..a6cbabf42 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -592,7 +592,10 @@ export namespace Doc { let _applyCount: number = 0; export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { - const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), StrCast(templateDoc.layoutKey, "layout"), templateDoc.title + "(..." + _applyCount++ + ")"); + const target = Doc.MakeDelegate(new Doc()); + const targetKey = StrCast(templateDoc.layoutKey, "layout"); + const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); + target.layoutKey = targetKey; applied && (Doc.GetProto(applied).type = templateDoc.type); return applied; } @@ -615,7 +618,6 @@ export namespace Doc { Doc.GetProto(target)[targetKey] = new PrefetchProxy(templateDoc); } } - target.layoutKey = targetKey; return target; } @@ -920,7 +922,9 @@ Scripting.addGlobal(function curPresentationItem() { }); Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); }); Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { - const docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCUMENT && d.type !== DocumentType.KVP && (!excludeCollections || !Cast(d.data, listSpec(Doc), null))); + const docs = DocListCast(Doc.UserDoc().SelectedDocs). + filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCUMENT && d.type !== DocumentType.KVP && + (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null))); return docs.length ? new List(docs) : prevValue; }); Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); }); diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index 1d90c984d..c211b3d3c 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -274,7 +274,7 @@ export namespace RichTextUtils { const backingDocId = StrCast(textNote[guid]); if (!backingDocId) { const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 }); - DocumentView.makeCustomViewClicked(backingDoc, undefined, Docs.Create.FreeformDocument); + DocumentView.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument); docid = backingDoc[Id]; textNote[guid] = docid; } else { @@ -403,7 +403,7 @@ export namespace RichTextUtils { let exported = (await Cast(linkDoc.anchor2, Doc))!; if (!exported.customLayout) { exported = Doc.MakeAlias(exported); - DocumentView.makeCustomViewClicked(exported, undefined, Docs.Create.FreeformDocument); + DocumentView.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); linkDoc.anchor2 = exported; } url = Utils.shareUrl(exported[Id]); diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index e06452a4e..91ea32bee 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -61,7 +61,8 @@ export const documentSchema = createSchema({ fontSize: "string", fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view letterSpacing: "string", - textTransform: "string" + textTransform: "string", + childTemplateName: "string" // the name of a template to use to override the layoutKey when rendering a document in DocumentBox }); export const positionSchema = createSchema({ diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index d9f354cf2..4f82da44d 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -55,6 +55,16 @@ export class CurrentUserUtils { Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues); doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 })); } + static setupDefaultIconTypes(doc: Doc, buttons?: string[]) { + doc.iconView = new PrefetchProxy(Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); + Doc.GetProto(doc.iconView as any as Doc).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); + doc.isTemplateDoc = makeTemplate(doc.iconView as any as Doc); + doc.iconImageView = new PrefetchProxy(Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); + doc.isTemplateDoc = makeTemplate(doc.iconImageView as any as Doc, true, "image_icon"); + doc.iconColView = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); + doc.isTemplateDoc = makeTemplate(doc.iconColView as any as Doc, true, "collection_icon"); + doc.iconViews = Docs.Create.TreeDocument([doc.iconView as any as Doc, doc.iconImageView as any as Doc, doc.iconColView as any as Doc], { title: "icon types", _height: 75 }); + } // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools static setupCreatorButtons(doc: Doc, alreadyCreatedButtons?: string[]) { @@ -63,7 +73,7 @@ export class CurrentUserUtils { doc.activePen = doc; const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ { title: "collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, - { title: "preview", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,true,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, + { title: "preview", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, { title: "web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", {_width: 300, _height: 300, title: "New Webpage" })' }, { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' }, { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" }, @@ -278,14 +288,6 @@ export class CurrentUserUtils { Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); - doc.iconView = new PrefetchProxy(Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); - Doc.GetProto(doc.iconView as any as Doc).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); - doc.isTemplateDoc = makeTemplate(doc.iconView as any as Doc); - doc.iconImageView = new PrefetchProxy(Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); - doc.isTemplateDoc = makeTemplate(doc.iconImageView as any as Doc, true, "image_icon"); - doc.iconColView = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); - doc.isTemplateDoc = makeTemplate(doc.iconColView as any as Doc, true, "collection_icon"); - const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, dontSelect: true, dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc; const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { ...opts, @@ -324,6 +326,7 @@ export class CurrentUserUtils { static updateUserDocument(doc: Doc) { doc.title = Doc.CurrentUserEmail; new InkingControl(); + (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc); (doc.noteTypes === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc); (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc); (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc); -- cgit v1.2.3-70-g09d2