From 3b9ca92421f54514f30bcb828e81172e6a9e6658 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 2 Oct 2020 16:17:00 -0400 Subject: fixed creating groups --- src/client/util/GroupManager.tsx | 5 ++--- src/client/views/GlobalKeyHandler.ts | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index e81c95d83..fb3342e68 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -66,8 +66,7 @@ export class GroupManager extends React.Component<{}> { const evaluating = raw.map(async user => { const userSharingDocument = await DocServer.GetRefField(user.sharingDocumentId); if (userSharingDocument instanceof Doc) { - const notificationDoc = await Cast(userSharingDocument.data, Doc, null); - runInAction(() => notificationDoc && this.users.push(user.email)); + runInAction(() => this.users.push(user.email)); } }); return Promise.all(evaluating).then(() => this.populating = false); @@ -398,7 +397,7 @@ export class GroupManager extends React.Component<{}> {

Manage Groups

diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 2ea1c464f..c48ba109a 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -51,11 +51,11 @@ export class KeyManager { } public unhandle = action((e: KeyboardEvent) => { - if (e.key.toLowerCase() === "shift") KeyManager.Instance.ShiftPressed = false; + if (e.key?.toLowerCase() === "shift") KeyManager.Instance.ShiftPressed = false; }); public handle = action(async (e: KeyboardEvent) => { - if (e.key.toLowerCase() === "shift" && e.ctrlKey && e.altKey) KeyManager.Instance.ShiftPressed = true; + if (e.key?.toLowerCase() === "shift" && e.ctrlKey && e.altKey) KeyManager.Instance.ShiftPressed = true; if (!Doc.UserDoc().noviceMode && e.key.toLocaleLowerCase() === "shift") DocServer.PRINT_CACHE(); const keyname = e.key && e.key.toLowerCase(); this.handleGreedy(keyname); -- cgit v1.2.3-70-g09d2 From 08d87df9cda89b4c81a27377461fbe674eeb76da Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 2 Oct 2020 19:22:53 -0400 Subject: fixed disappearance of undo/redo button area --- src/client/views/MainView.scss | 3 +++ src/client/views/MainView.tsx | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index f64449616..5efe9adad 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -319,6 +319,9 @@ .mainView-libraryFlyout-out { transition: width .25s; box-shadow: rgb(156, 147, 150) 0.2vw 0.2vw 0.2vw; + .mainView-docButtons { + left: 0; + } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8e30eba2a..cb84409cb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -312,7 +312,9 @@ export class MainView extends React.Component { } @computed get flyout() { - return !this._flyoutWidth ?
: + return !this._flyoutWidth ?
+ {this.docButtons} +
:
Date: Fri, 2 Oct 2020 21:35:45 -0400 Subject: cleaned up CollectionLinkView and fixed an issue with link lines flopping around --- .../CollectionFreeFormLinkView.tsx | 145 +++++++++------------ 1 file changed, 64 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 9dcfde7f9..3e9c0b485 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -22,74 +22,63 @@ export class CollectionFreeFormLinkView extends React.Component (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25))); + componentWillUnmount() { this._anchorDisposer?.(); } + @action timeout = action(() => (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25))); componentDidMount() { - this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)], + this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform()], action(() => { this._start = Date.now(); this._timeout && clearTimeout(this._timeout); this._timeout = setTimeout(this.timeout, 25); - if (SnappingManager.GetIsDragging() || !this.props.A.ContentDiv || !this.props.B.ContentDiv) return; - setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() - setTimeout(action(() => (!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line. - const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; - const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; - const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv); - const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv); - const a = adiv.getBoundingClientRect(); - const b = bdiv.getBoundingClientRect(); - const abounds = adiv.parentElement!.getBoundingClientRect(); - const bbounds = bdiv.parentElement!.getBoundingClientRect(); - const apt = Utils.closestPtBetweenRectangles(abounds.left, abounds.top, abounds.width, abounds.height, - bbounds.left, bbounds.top, bbounds.width, bbounds.height, - a.left + a.width / 2, a.top + a.height / 2); - const bpt = Utils.closestPtBetweenRectangles(bbounds.left, bbounds.top, bbounds.width, bbounds.height, - abounds.left, abounds.top, abounds.width, abounds.height, - apt.point.x, apt.point.y); - const afield = this.props.A.props.LayoutTemplateString?.indexOf("anchor1") === -1 ? "anchor2" : "anchor1"; - const bfield = afield === "anchor1" ? "anchor2" : "anchor1"; - - // really hacky stuff to make the LinkAnchorBox display where we want it to: - // if there's an element in the DOM with a classname containing the link's id and a data-targetids attribute containing the other end of the link, - // then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right - // otherwise, we just use the computed nearest point on the document boundary to the target Document - const linkId = this.props.LinkDocs[0][Id]; // this link's Id - const AanchorId = (this.props.LinkDocs[0][afield] as Doc)[Id]; // anchor a's id - const BanchorId = (this.props.LinkDocs[0][bfield] as Doc)[Id]; // anchor b's id - const linkEles = Array.from(window.document.getElementsByClassName(linkId)); - const targetAhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes(AanchorId)); - const targetBhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes(BanchorId)); - if (!targetBhyperlink) { - this.props.A.rootDoc[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100; - this.props.A.rootDoc[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100; - } else { - setTimeout(() => { - (this.props.A.rootDoc[(this.props.A.props as any).fieldKey] as Doc); - const m = targetBhyperlink.getBoundingClientRect(); - const mp = this.props.A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); - this.props.A.rootDoc[afield + "_x"] = Math.min(1, mp[0] / this.props.A.props.PanelWidth()) * 100; - this.props.A.rootDoc[afield + "_y"] = Math.min(1, mp[1] / this.props.A.props.PanelHeight()) * 100; - }, 0); - } - if (!targetAhyperlink) { - this.props.A.rootDoc[bfield + "_x"] = (bpt.point.x - bbounds.left) / bbounds.width * 100; - this.props.A.rootDoc[bfield + "_y"] = (bpt.point.y - bbounds.top) / bbounds.height * 100; - } else { - setTimeout(() => { - (this.props.B.rootDoc[(this.props.B.props as any).fieldKey] as Doc); - const m = targetAhyperlink.getBoundingClientRect(); - const mp = this.props.B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); - this.props.B.rootDoc[bfield + "_x"] = Math.min(1, mp[0] / this.props.B.props.PanelWidth()) * 100; - this.props.B.rootDoc[bfield + "_y"] = Math.min(1, mp[1] / this.props.B.props.PanelHeight()) * 100; - }, 0); - } + setTimeout(this.placeAnchors); }) , { fireImmediately: true }); } + placeAnchors = () => { + const { A, B, LinkDocs } = this.props; + const linkDoc = LinkDocs[0]; + if (SnappingManager.GetIsDragging() || !A.ContentDiv || !B.ContentDiv) return; + setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() + setTimeout(action(() => (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line. + const acont = A.props.Document.type === DocumentType.LINK ? A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; + const bcont = B.props.Document.type === DocumentType.LINK ? B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; + const adiv = (acont.length ? acont[0] : A.ContentDiv); + const bdiv = (bcont.length ? bcont[0] : B.ContentDiv); + const a = adiv.getBoundingClientRect(); + const b = bdiv.getBoundingClientRect(); + const { left: aleft, top: atop, width: awidth, height: aheight } = adiv.parentElement!.getBoundingClientRect(); + const { left: bleft, top: btop, width: bwidth, height: bheight } = bdiv.parentElement!.getBoundingClientRect(); + const apt = Utils.closestPtBetweenRectangles(aleft, atop, awidth, aheight, bleft, btop, bwidth, bheight, a.left + a.width / 2, a.top + a.height / 2); + const bpt = Utils.closestPtBetweenRectangles(bleft, btop, bwidth, bheight, aleft, atop, awidth, aheight, apt.point.x, apt.point.y); + const afield = A.props.LayoutTemplateString?.indexOf("anchor1") === -1 ? "anchor2" : "anchor1"; + const bfield = afield === "anchor1" ? "anchor2" : "anchor1"; + + // really hacky stuff to make the LinkAnchorBox display where we want it to: + // if there's an element in the DOM with a classname containing the link's id and a data-targetids attribute containing the other end of the link, + // then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right + // otherwise, we just use the computed nearest point on the document boundary to the target Document + const linkEles = Array.from(window.document.getElementsByClassName(linkDoc[Id])); + const targetAhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes((linkDoc[afield] as Doc)[Id])); + const targetBhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes((linkDoc[bfield] as Doc)[Id])); + if (!targetBhyperlink) { + A.rootDoc[afield + "_x"] = (apt.point.x - aleft) / awidth * 100; + A.rootDoc[afield + "_y"] = (apt.point.y - atop) / aheight * 100; + } else { + const m = targetBhyperlink.getBoundingClientRect(); + const mp = A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); + A.rootDoc[afield + "_x"] = Math.min(1, mp[0] / A.props.PanelWidth()) * 100; + A.rootDoc[afield + "_y"] = Math.min(1, mp[1] / A.props.PanelHeight()) * 100; + } + if (!targetAhyperlink) { + B.rootDoc[bfield + "_x"] = (bpt.point.x - bleft) / bwidth * 100; + B.rootDoc[bfield + "_y"] = (bpt.point.y - btop) / bheight * 100; + } else { + const m = targetAhyperlink.getBoundingClientRect(); + const mp = B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); + B.rootDoc[bfield + "_x"] = Math.min(1, mp[0] / B.props.PanelWidth()) * 100; + B.rootDoc[bfield + "_y"] = Math.min(1, mp[1] / B.props.PanelHeight()) * 100; + } + } pointerDown = (e: React.PointerEvent) => { @@ -138,14 +127,12 @@ export class CollectionFreeFormLinkView extends React.Component Date: Fri, 2 Oct 2020 21:40:38 -0400 Subject: from last --- .../views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3e9c0b485..f051d5f8d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -102,7 +102,7 @@ export class CollectionFreeFormLinkView extends React.Component Date: Sat, 3 Oct 2020 09:49:54 -0400 Subject: style fix for schema view to see dropdown list items in a cell --- src/client/views/collections/CollectionSchemaView.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 8d2f645d9..b0b5f995a 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -500,7 +500,7 @@ button.add-column { border: grey; border-style: solid; border-width: 1px; - height: 100%; + height: 30px; .collectionSchemaView-dropdownButton { -- cgit v1.2.3-70-g09d2 From 90948700fb669c609355dab83d6cef74654879d9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 02:06:13 -0400 Subject: got rid of link group stuff. fixed sidebar popping out when properties pops out. got rid of Layout from properties because it caused PDFs to scroll. --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/LinkManager.ts | 83 +-------- src/client/views/MainView.scss | 1 - src/client/views/PropertiesView.tsx | 4 +- src/client/views/linking/LinkEditor.tsx | 264 ----------------------------- src/client/views/linking/LinkMenuGroup.tsx | 11 -- src/client/views/linking/LinkMenuItem.tsx | 19 +-- 7 files changed, 10 insertions(+), 374 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index ec550c15a..f6ac363da 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -986,9 +986,9 @@ export class CurrentUserUtils { this.setupDockedButtons(doc); // the bottom bar of font icons await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels await this.setupMenuPanel(doc, sharingDocumentId); - doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument(); doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument(); doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument(); + if (!doc.myLinkDatabase) doc.myLinkDatabase = new List([]); setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 269de08a1..0371dc4d9 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -2,7 +2,7 @@ import { Doc, DocListCast, Opt } from "../../fields/Doc"; import { List } from "../../fields/List"; import { listSpec } from "../../fields/Schema"; import { Cast, StrCast } from "../../fields/Types"; -import { CurrentUserUtils } from "./CurrentUserUtils"; +import { SharingManager } from "./SharingManager"; /* * link doc: @@ -33,31 +33,19 @@ export class LinkManager { private constructor() { } - // the linkmanagerdoc stores a list of docs representing all linkdocs in 'allLinks' and a list of strings representing all group types in 'allGroupTypes' - // lists of strings representing the metadata keys for each group type is stored under a key that is the same as the group type - public get LinkManagerDoc(): Doc | undefined { - return Doc.UserDoc().globalLinkDatabase as Doc; - } public getAllLinks(): Doc[] { - const ldoc = LinkManager.Instance.LinkManagerDoc; - return ldoc ? DocListCast(ldoc.data) : []; + const lset = new Set(DocListCast(Doc.UserDoc().myLinkDatabase)); + SharingManager.Instance.users.forEach(user => DocListCast(user.sharingDoc.myLinkDatabase).map(lset.add)); + return Array.from(lset); } public addLink(linkDoc: Doc): boolean { - if (LinkManager.Instance.LinkManagerDoc) { - Doc.AddDocToList(LinkManager.Instance.LinkManagerDoc, "data", linkDoc); - return true; - } - return false; + return Doc.AddDocToList(Doc.UserDoc(), "myLinkDatabase", linkDoc); } public deleteLink(linkDoc: Doc): boolean { - if (LinkManager.Instance.LinkManagerDoc && linkDoc instanceof Doc) { - Doc.RemoveDocFromList(LinkManager.Instance.LinkManagerDoc, "data", linkDoc); - return true; - } - return false; + return Doc.RemoveDocFromList(Doc.UserDoc(), "myLinkDatabase", linkDoc); } // finds all links that contain the given anchor @@ -85,49 +73,6 @@ export class LinkManager { related.forEach(linkDoc => LinkManager.Instance.deleteLink(linkDoc)); } - public addGroupType(groupType: string): boolean { - if (LinkManager.Instance.LinkManagerDoc) { - LinkManager.Instance.LinkManagerDoc[groupType] = new List([]); - const groupTypes = LinkManager.Instance.getAllGroupTypes(); - groupTypes.push(groupType); - LinkManager.Instance.LinkManagerDoc.allGroupTypes = new List(groupTypes); - return true; - } - return false; - } - - // removes all group docs from all links with the given group type - public deleteGroupType(groupType: string): boolean { - if (LinkManager.Instance.LinkManagerDoc) { - if (LinkManager.Instance.LinkManagerDoc[groupType]) { - const groupTypes = LinkManager.Instance.getAllGroupTypes(); - const index = groupTypes.findIndex(type => type.toUpperCase() === groupType.toUpperCase()); - if (index > -1) groupTypes.splice(index, 1); - LinkManager.Instance.LinkManagerDoc.allGroupTypes = new List(groupTypes); - LinkManager.Instance.LinkManagerDoc[groupType] = undefined; - LinkManager.Instance.getAllLinks().forEach(async linkDoc => { - const anchor1 = await Cast(linkDoc.anchor1, Doc); - const anchor2 = await Cast(linkDoc.anchor2, Doc); - anchor1 && LinkManager.Instance.removeGroupFromAnchor(linkDoc, anchor1, groupType); - anchor2 && LinkManager.Instance.removeGroupFromAnchor(linkDoc, anchor2, groupType); - }); - } - return true; - } else return false; - } - - public getAllGroupTypes(): string[] { - if (LinkManager.Instance.LinkManagerDoc) { - if (LinkManager.Instance.LinkManagerDoc.allGroupTypes) { - return Cast(LinkManager.Instance.LinkManagerDoc.allGroupTypes, listSpec("string"), []); - } else { - LinkManager.Instance.LinkManagerDoc.allGroupTypes = new List([]); - return []; - } - } - return []; - } - // gets the groups associates with an anchor in a link public getAnchorGroups(linkDoc: Doc, anchor?: Doc): Array { if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) { @@ -164,22 +109,6 @@ export class LinkManager { return anchorGroups; } - // gets a list of strings representing the keys of the metadata associated with the given group type - public getMetadataKeysInGroup(groupType: string): string[] { - if (LinkManager.Instance.LinkManagerDoc) { - return LinkManager.Instance.LinkManagerDoc[groupType] ? Cast(LinkManager.Instance.LinkManagerDoc[groupType], listSpec("string"), []) : []; - } - return []; - } - - public setMetadataKeysForGroup(groupType: string, keys: string[]): boolean { - if (LinkManager.Instance.LinkManagerDoc) { - LinkManager.Instance.LinkManagerDoc[groupType] = new List(keys); - return true; - } - return false; - } - // returns a list of all metadata docs associated with the given group type public getAllMetadataDocsInGroup(groupType: string): Array { const md: Doc[] = []; diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 5efe9adad..b608eceb1 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -293,7 +293,6 @@ .mainView-libraryFlyout-out, .mainView-libraryFlyout { height: 100%; - width: 100%; position: relative; display: flex; flex-direction: column; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index f3241e8d9..a64004c5c 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -972,7 +972,7 @@ export class PropertiesView extends React.Component {
{this.openContexts ?
{this.contexts}
: null}
-
+ {/*
this.openLayout = !this.openLayout)} style={{ backgroundColor: this.openLayout ? "black" : "" }}> @@ -982,7 +982,7 @@ export class PropertiesView extends React.Component {
{this.openLayout ?
{this.layoutPreview}
: null} -
+
*/}
; } if (this.isPres) { diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 3713a1026..435b9d904 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -10,264 +10,6 @@ import { undoBatch } from "../../util/UndoManager"; import './LinkEditor.scss'; import React = require("react"); -interface GroupTypesDropdownProps { - groupType: string; - setGroupType: (group: string) => void; -} -// this dropdown could be generalized -@observer -class GroupTypesDropdown extends React.Component { - @observable private _searchTerm: string = this.props.groupType; - @observable private _groupType: string = this.props.groupType; - @observable private _isEditing: boolean = false; - - @action - createGroup = (groupType: string): void => { - this.props.setGroupType(groupType); - LinkManager.Instance.addGroupType(groupType); - } - - @action - onChange = (val: string): void => { - this._searchTerm = val; - this._groupType = val; - this._isEditing = true; - } - - @action - onKeyDown = (e: React.KeyboardEvent): void => { - if (e.key === "Enter") { - const allGroupTypes = Array.from(LinkManager.Instance.getAllGroupTypes()); - const groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); - const exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase()); - - if (exactFound > -1) { - const groupType = groupOptions[exactFound]; - this.props.setGroupType(groupType); - this._groupType = groupType; - } else { - this.createGroup(this._searchTerm); - this._groupType = this._searchTerm; - } - - this._searchTerm = this._groupType; - this._isEditing = false; - } - } - - @action - onOptionClick = (value: string, createNew: boolean): void => { - if (createNew) { - this.createGroup(this._searchTerm); - this._groupType = this._searchTerm; - - } else { - this.props.setGroupType(value); - this._groupType = value; - - } - this._searchTerm = this._groupType; - this._isEditing = false; - } - - @action - onButtonPointerDown = (): void => { - this._isEditing = true; - } - - renderOptions = (): JSX.Element[] | JSX.Element => { - if (this._searchTerm === "") return <>; - - const allGroupTypes = Array.from(LinkManager.Instance.getAllGroupTypes()); - const groupOptions = allGroupTypes.filter(groupType => groupType.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); - const exactFound = groupOptions.findIndex(groupType => groupType.toUpperCase() === this._searchTerm.toUpperCase()) > -1; - - const options = groupOptions.map(groupType => { - const ref = React.createRef(); - return
this.onOptionClick(groupType, false)}>{groupType}
; - }); - - // if search term does not already exist as a group type, give option to create new group type - if (!exactFound && this._searchTerm !== "") { - const ref = React.createRef(); - options.push(
this.onOptionClick(this._searchTerm, true)}>Define new "{this._searchTerm}" relationship
); - } - - return options; - } - - render() { - if (this._isEditing || this._groupType === "") { - return ( -
- this.onChange(e.target.value)} onKeyDown={this.onKeyDown} autoFocus> -
- {this.renderOptions()} -
-
- ); - } else { - return ; - } - } -} - - -interface LinkMetadataEditorProps { - id: string; - groupType: string; - mdDoc: Doc; - mdKey: string; - mdValue: string; - changeMdIdKey: (id: string, newKey: string) => void; -} -@observer -class LinkMetadataEditor extends React.Component { - @observable private _key: string = this.props.mdKey; - @observable private _value: string = this.props.mdValue; - @observable private _keyError: boolean = false; - - @action - setMetadataKey = (value: string): void => { - const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType); - - // don't allow user to create existing key - const newIndex = groupMdKeys.findIndex(key => key.toUpperCase() === value.toUpperCase()); - if (newIndex > -1) { - this._keyError = true; - this._key = value; - return; - } else { - this._keyError = false; - } - - // set new value for key - const currIndex = groupMdKeys.findIndex(key => { - return StrCast(key).toUpperCase() === this._key.toUpperCase(); - }); - if (currIndex === -1) console.error("LinkMetadataEditor: key was not found"); - groupMdKeys[currIndex] = value; - - this.props.changeMdIdKey(this.props.id, value); - this._key = value; - LinkManager.Instance.setMetadataKeysForGroup(this.props.groupType, [...groupMdKeys]); - } - - @action - setMetadataValue = (value: string): void => { - if (!this._keyError) { - this._value = value; - Doc.GetProto(this.props.mdDoc)[this._key] = value; - } - } - - @action - removeMetadata = (): void => { - const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType); - - const index = groupMdKeys.findIndex(key => key.toUpperCase() === this._key.toUpperCase()); - if (index === -1) console.error("LinkMetadataEditor: key was not found"); - groupMdKeys.splice(index, 1); - - LinkManager.Instance.setMetadataKeysForGroup(this.props.groupType, groupMdKeys); - this._key = ""; - } - - render() { - return ( -
- this.setMetadataKey(e.target.value)}>: - this.setMetadataValue(e.target.value)}> - -
- ); - } -} - -interface LinkGroupEditorProps { - sourceDoc: Doc; - linkDoc: Doc; - groupDoc: Doc; -} -@observer -export class LinkGroupEditor extends React.Component { - - private _metadataIds: Map = new Map(); - - constructor(props: LinkGroupEditorProps) { - super(props); - - const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(StrCast(props.groupDoc.linkRelationship)); - groupMdKeys.forEach(key => this._metadataIds.set(key, Utils.GenerateGuid())); - } - - @action - setGroupType = (groupType: string): void => { - Doc.GetProto(this.props.groupDoc).linkRelationship = groupType; - } - - removeGroupFromLink = (groupType: string): void => { - LinkManager.Instance.removeGroupFromAnchor(this.props.linkDoc, this.props.sourceDoc, groupType); - } - - deleteGroup = (groupType: string): void => { - LinkManager.Instance.deleteGroupType(groupType); - } - - - @action - addMetadata = (groupType: string): void => { - this._metadataIds.set("new key", Utils.GenerateGuid()); - const mdKeys = LinkManager.Instance.getMetadataKeysInGroup(groupType); - // only add "new key" if there is no other key with value "new key"; prevents spamming - if (mdKeys.indexOf("new key") === -1) mdKeys.push("new key"); - LinkManager.Instance.setMetadataKeysForGroup(groupType, mdKeys); - } - - // for key rendering purposes - changeMdIdKey = (id: string, newKey: string) => { - this._metadataIds.set(newKey, id); - } - - renderMetadata = (): JSX.Element[] => { - const metadata: Array = []; - const groupDoc = this.props.groupDoc; - const groupType = StrCast(groupDoc.linkRelationship); - const groupMdKeys = LinkManager.Instance.getMetadataKeysInGroup(groupType); - - groupMdKeys.forEach((key) => { - const val = StrCast(groupDoc[key]); - metadata.push( - - ); - }); - return metadata; - } - - render() { - const groupType = StrCast(this.props.groupDoc.linkRelationship); - // if ((groupType && LinkManager.Instance.getMetadataKeysInGroup(groupType).length > 0) || groupType === "") { - const buttons = ; - const addButton = ; - - return ( -
-
- {buttons} - - -
- {this.renderMetadata().length > 0 ?

metadata:

: <>} - {addButton} - {this.renderMetadata()} -
- ); - } -} - interface LinkEditorProps { sourceDoc: Doc; @@ -422,10 +164,6 @@ export class LinkEditor extends React.Component { render() { const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc); - const groups = [this.props.linkDoc].map(groupDoc => { - return ; - }); return !destination ? (null) : (
@@ -450,8 +188,6 @@ export class LinkEditor extends React.Component {
{this.editDescription}
{this.followingDropdown}
- - {/* {groups.length > 0 ? groups :
There are currently no relationships associated with this link.
} */}
); diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 29e1d921c..e76227ccf 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -54,17 +54,6 @@ export class LinkMenuGroup extends React.Component { e.stopPropagation(); } - viewGroupAsTable = (groupType: string): JSX.Element => { - const keys = LinkManager.Instance.getMetadataKeysInGroup(groupType); - const index = keys.indexOf(""); - if (index > -1) keys.splice(index, 1); - const cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c, "#f1efeb")); - const docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType); - const createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { _width: 500, _height: 300, title: groupType + " table", childDropAction: "alias" })); - const ref = React.createRef(); - return
; - } - render() { const set = new Set(this.props.group); const groupItems = Array.from(set.keys()).map(linkDoc => { diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 3a8d41fef..00e667db7 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -90,19 +90,6 @@ export class LinkMenuItem extends React.Component { return true; } - renderMetadata = (): JSX.Element => { - const index = StrCast(this.props.linkDoc.title).toUpperCase() === this.props.groupType.toUpperCase() ? 0 : -1; - const mdDoc = index > -1 ? this.props.linkDoc : undefined; - - let mdRows: Array = []; - if (mdDoc) { - const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType); - mdRows = keys.map(key =>
{key}: {StrCast(mdDoc[key])}
); - } - - return (
{mdRows}
); - } - @action onLinkButtonDown = (e: React.PointerEvent): void => { this._downX = e.clientX; @@ -191,8 +178,6 @@ export class LinkMenuItem extends React.Component { } render() { - const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType); - const canExpand = keys ? keys.length > 0 : false; const eyeIcon = this.props.linkDoc.hidden ? "eye-slash" : "eye"; @@ -230,7 +215,7 @@ export class LinkMenuItem extends React.Component { return (
-
+
LinkDocPreview.LinkInfo = undefined)} @@ -257,8 +242,6 @@ export class LinkMenuItem extends React.Component { {StrCast(this.props.linkDoc.description)}

: null}
- {canExpand ?
this.toggleShowMore(e)}> -
: <>}
{this.props.linkDoc.hidden ? "Show link" : "Hide link"}
}>
-- cgit v1.2.3-70-g09d2 From 8e14d42c61efb0ee5547fbcb7ec9131a7f0ff74f Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 02:20:34 -0400 Subject: fixed linkEditor to edit links for annotations embedded on PDFs --- src/client/util/LinkManager.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 0371dc4d9..a2bb16dfc 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -137,6 +137,8 @@ export class LinkManager { const a2 = Cast(linkDoc.anchor2, Doc, null); if (Doc.AreProtosEqual(anchor, a1)) return a2; if (Doc.AreProtosEqual(anchor, a2)) return a1; + if (Doc.AreProtosEqual(anchor, a1.annotationOn as Doc)) return a2; + if (Doc.AreProtosEqual(anchor, a2.annotationOn as Doc)) return a1; if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b725cbb244136ddfffad24d4ac68b9beb31845a3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 09:36:13 -0400 Subject: stopped ctrl-a from selecting doucment.body. prevented pdfviewer's texxt layer from scrolling horizontally when text annotations go out of bounds horizontally. fixed text boxes to not grab selectonOnLoad focus unless they're in an active tab. --- src/client/views/GlobalKeyHandler.ts | 5 +++++ src/client/views/nodes/formattedText/FormattedTextBox.tsx | 10 +++++++++- src/client/views/pdf/PDFViewer.tsx | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c48ba109a..b9b771027 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -223,6 +223,11 @@ export class KeyManager { stopPropagation = false; break; case "a": + if (e.target !== document.body) { + stopPropagation = false; + preventDefault = false; + }; + break; case "v": stopPropagation = false; preventDefault = false; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index a998386d8..b0199b35f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1123,6 +1123,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } + private isActiveTab(el: Element | null | undefined) { + do { + if (el?.className.includes("lm_active")) return true; + el = el?.parentNode as any; + } while (el !== document.body); + return false; + } + private setupEditor(config: any, fieldKey: string) { const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null); const rtfField = Cast((!curText?.Text && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField); @@ -1161,7 +1169,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad; - if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad) { + if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) { FormattedTextBox.SelectOnLoad = ""; this.props.select(false); if (FormattedTextBox.SelectOnLoadChar && this._editorView) { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 77dd40f2a..582e4ba84 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -155,6 +155,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._mainCont.current && (this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0))); observer.observe(this._mainCont.current); + this._mainCont.current.addEventListener("scroll", (e) => (e.target as any).scrollLeft = 0); } this._disposers.searchMatch = reaction(() => Doc.IsSearchMatch(this.rootDoc), -- cgit v1.2.3-70-g09d2 From 2a5cceb16d102a2139ca876983577eb8d882e9e0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 11:59:48 -0400 Subject: handled concurrent list additions as a special case (need to handle all concurrent edits still). --- src/client/views/GlobalKeyHandler.ts | 2 +- src/fields/List.ts | 4 ++-- src/fields/util.ts | 22 ++++++++++++---------- src/server/websocket.ts | 14 +++++++++++++- 4 files changed, 28 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index b9b771027..89292a445 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -226,7 +226,7 @@ export class KeyManager { if (e.target !== document.body) { stopPropagation = false; preventDefault = false; - }; + } break; case "v": stopPropagation = false; diff --git a/src/fields/List.ts b/src/fields/List.ts index c9e4bd3c1..dca8d111c 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -43,7 +43,7 @@ const listHandlers: any = { } } const res = list.__fields.push(...items); - this[Update](); + this[Update]("$addToSet"); return res; }), reverse() { @@ -314,7 +314,7 @@ class ListImpl extends ObjectField { // console.log(diff); const update = this[OnUpdate]; // update && update(diff); - update?.(); + update?.(diff); } private [Self] = this; diff --git a/src/fields/util.ts b/src/fields/util.ts index 4da9fce74..90446f531 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -371,17 +371,19 @@ export function deleteProperty(target: any, prop: string | number | symbol) { export function updateFunction(target: any, prop: any, value: any, receiver: any) { let current = ObjectField.MakeCopy(value); return (diff?: any) => { - if (true || !diff) { + if (diff === "$addToSet") { + diff = { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; + } else { diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; - const oldValue = current; - const newValue = ObjectField.MakeCopy(value); - current = newValue; - if (!(value instanceof CursorField) && !(value?.some?.((v: any) => v instanceof CursorField))) { - UndoManager.AddEvent({ - redo() { receiver[prop] = newValue; }, - undo() { receiver[prop] = oldValue; } - }); - } + } + const oldValue = current; + const newValue = ObjectField.MakeCopy(value); + current = newValue; + if (!(value instanceof CursorField) && !(value?.some?.((v: any) => v instanceof CursorField))) { + UndoManager.AddEvent({ + redo() { receiver[prop] = newValue; }, + undo() { receiver[prop] = oldValue; } + }); } target[Update](diff); }; diff --git a/src/server/websocket.ts b/src/server/websocket.ts index b33e76c0b..7d13480f5 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -201,7 +201,7 @@ export namespace WebSocket { function setField(socket: Socket, newValue: Transferable) { Database.Instance.update(newValue.id, newValue, () => - socket.broadcast.emit(MessageStore.SetField.Message, newValue)); + socket.broadcast.emit(MessageStore.SetField.Message, newValue)); // broadcast set value to all other clients if (newValue.type === Types.Text) { // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR Search.updateDocument({ id: newValue.id, data: { set: (newValue as any).data } }); } @@ -271,7 +271,19 @@ export namespace WebSocket { return typeof value === "string" ? value : value[0]; } + function updateListField(socket: Socket, diff: Diff, results?: Transferable): void { + diff.diff.$set = diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones + delete diff.diff.$addToSet; + const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; + const list = (results as any).fields?.[updatefield.replace("fields.", "")].fields; + list.forEach((item: any) => !diff.diff.$set[updatefield].fields.some((x: any) => x.fieldId === item.fieldId) && diff.diff.$set[updatefield].fields.push(item)); + Database.Instance.update(diff.id, diff.diff, + () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); + console.log(results, diff.diff.$set); + } + function UpdateField(socket: Socket, diff: Diff) { + if (diff.diff.$addToSet) return GetRefField([diff.id, (result?: Transferable) => updateListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); const docfield = diff.diff.$set || diff.diff.$unset; -- cgit v1.2.3-70-g09d2 From 1f1ec5e1ce014cfc96400b908e5e9a439c30fca7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 12:51:16 -0400 Subject: try sending list back to sender if we notice the set of fields is different than the originally sent set of fields --- src/server/websocket.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 7d13480f5..0d19c3a91 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -276,9 +276,18 @@ export namespace WebSocket { delete diff.diff.$addToSet; const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; const list = (results as any).fields?.[updatefield.replace("fields.", "")].fields; + const prelen = diff.diff.$set[updatefield].fields.length; list.forEach((item: any) => !diff.diff.$set[updatefield].fields.some((x: any) => x.fieldId === item.fieldId) && diff.diff.$set[updatefield].fields.push(item)); + const sendBack = diff.diff.$set[updatefield].fields.length !== prelen; Database.Instance.update(diff.id, diff.diff, - () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); + () => { + if (sendBack) { + const id = socket.id; + socket.id = ""; + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + socket.id = id; + } else socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + }, false); console.log(results, diff.diff.$set); } -- cgit v1.2.3-70-g09d2 From 934087035ac00270c24850bceb365caa689549c9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 12:51:44 -0400 Subject: from last --- src/server/websocket.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 0d19c3a91..644eedf62 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -288,7 +288,6 @@ export namespace WebSocket { socket.id = id; } else socket.broadcast.emit(MessageStore.UpdateField.Message, diff); }, false); - console.log(results, diff.diff.$set); } function UpdateField(socket: Socket, diff: Diff) { -- cgit v1.2.3-70-g09d2 From cd68d18b3b72fea20675dcaa9678f6824a60e68c Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 12:58:10 -0400 Subject: from last --- src/client/views/linking/LinkMenuItem.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 00e667db7..1ba724889 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -260,7 +260,6 @@ export class LinkMenuItem extends React.Component {
*/}
- {this._showMore ? this.renderMetadata() : <>}
-- cgit v1.2.3-70-g09d2 From 56d9d31d4ac9f2913bec14a2e3c4472fcfd90a7b Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 14:34:16 -0400 Subject: fixed formatted texst box select on load when pdf is full screen and the same pdf is in inactive tab behind it. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index b0199b35f..ef39e6a90 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1124,11 +1124,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } private isActiveTab(el: Element | null | undefined) { - do { - if (el?.className.includes("lm_active")) return true; - el = el?.parentNode as any; - } while (el !== document.body); - return false; + while (el && el !== document.body) { + if (getComputedStyle(el).display === "none") return false; + el = el.parentNode as any; + } + return true; } private setupEditor(config: any, fieldKey: string) { -- cgit v1.2.3-70-g09d2 From 9c4701f8a8214544a0e1e6b31887d393e8ad344f Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 5 Oct 2020 16:00:34 -0400 Subject: fixed search over DB to not use quotes when setting field column filters. --- src/client/views/search/SearchBox.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index b381bbfa9..1104d8d2a 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -146,7 +146,7 @@ export class SearchBox extends ViewBoxBaseComponent i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"")); + oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + word) : newWords.push("AND " + key + mod + word)); query = `(${query}) AND (${newWords.join(" ")})`; } else { @@ -154,7 +154,7 @@ export class SearchBox extends ViewBoxBaseComponent i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"")); + oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + word) : newWords.push("AND " + key + mod + word)); const v = "(" + newWords.join(" ") + ")"; if (i === 0) { query = `(${query}) AND (${v}` + (values.length === 1 ? ")" : ""); -- cgit v1.2.3-70-g09d2 From 83aaea5320257ce15d68a5299c00977684ddab8e Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 11:07:28 -0400 Subject: restored ability to open document that has been moved from another document's annotation overlay --- src/client/util/DocumentManager.ts | 8 +++++--- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 6 +++--- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 2ca29cb7e..e2518d05f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -193,11 +193,13 @@ export class DocumentManager { if (retryDocView) { // we found the target in the context retryDocView.props.focus(targetDoc, willZoom, undefined, focusAndFinish); // focus on the target in the context highlight(); - } - if (delay > 2500) { + } else if (delay > 1500) { // we didn't find the target, so it must have moved out of the context. Go back to just creating it. if (closeContextIfNotFound) targetDocContextView.props.removeDocument?.(targetDocContextView.props.Document); - // targetDoc.layout && createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target + if (targetDoc.layout) { + Doc.SetInPlace(targetDoc, "annotationOn", undefined, false); + createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target + } } else { setTimeout(() => findView(delay + 250), 250); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2783011cf..fc3fd3a7c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -891,9 +891,10 @@ export class CollectionFreeFormView extends CollectionSubView { // ); } else if (field instanceof List) { - return
{field.length ? field.map(f => Field.toString(f)).join(", ") : "[]"}
; + return
{field.length ? field.map(f => Field.toString(f)).join(", ") : ""}
; } // bcz: this belongs here, but it doesn't render well so taking it out for now else if (field instanceof WebField) { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 582e4ba84..4c5f72b97 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -180,9 +180,9 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._mainCont.current && smoothScroll(1000, this._mainCont.current, scrollY || 0), 250); } setTimeout(() => this.Document._scrollY = undefined, 1000); } -- cgit v1.2.3-70-g09d2 From 68916ee8daafb03ad2aff3338e18ca419ce888de Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 12:15:49 -0400 Subject: fixed adding documents to check acl of added document(s) correctly --- src/client/views/DocComponent.tsx | 5 +++-- src/client/views/MainView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b3fbe418b..d6f8c49df 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -123,8 +123,9 @@ export function ViewBoxAnnotatableComponent

effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin); + if (docs.length) { const docs = doc instanceof Doc ? [doc] : doc; docs.map(doc => doc.isPushpin = doc.annotationOn = undefined); const targetDataDoc = this.dataDoc; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cb84409cb..69354020b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -86,7 +86,7 @@ export class MainView extends React.Component { document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!)); new InkStrokeProperties(); this._sidebarContent.proto = undefined; - DocServer.setPlaygroundFields(["dataTransition", "_delayAutoHeight", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollY", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's + DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_delayAutoHeight", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollY", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg))); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2bdc8e2f3..0ef3dd6cd 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -157,7 +157,7 @@ export class CollectionView extends Touchable { + added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document const context = Cast(doc.context, Doc, null); if (context && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { const pushpin = Docs.Create.FontIconDocument({ @@ -186,9 +186,9 @@ export class CollectionView extends Touchable { const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]); - const docAcl = GetEffectiveAcl(doc); - if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin || docAcl === AclAdmin) { - const docs = doc instanceof Doc ? [doc] : doc as Doc[]; + const indocs = doc instanceof Doc ? [doc] : doc as Doc[]; + const docs = indocs.filter(doc => effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin); + if (docs.length) { const targetDataDoc = this.props.Document[DataSym]; const value = DocListCast(targetDataDoc[this.props.fieldKey]); const toRemove = value.filter(v => docs.includes(v)); -- cgit v1.2.3-70-g09d2 From 82355dad8304a3264349734a94db13aa94bb277c Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 13:14:32 -0400 Subject: cleanup fixes. --- src/client/views/DocComponent.tsx | 2 +- src/server/websocket.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index d6f8c49df..98e888538 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -123,7 +123,7 @@ export function ViewBoxAnnotatableComponent

effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin); if (docs.length) { const docs = doc instanceof Doc ? [doc] : doc; diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 644eedf62..3687ef876 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -275,9 +275,9 @@ export namespace WebSocket { diff.diff.$set = diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones delete diff.diff.$addToSet; const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; - const list = (results as any).fields?.[updatefield.replace("fields.", "")].fields; + const list = (results as any).fields?.[updatefield.replace("fields.", "")]?.fields; const prelen = diff.diff.$set[updatefield].fields.length; - list.forEach((item: any) => !diff.diff.$set[updatefield].fields.some((x: any) => x.fieldId === item.fieldId) && diff.diff.$set[updatefield].fields.push(item)); + list?.forEach((item: any) => !diff.diff.$set[updatefield].fields.some((x: any) => x.fieldId === item.fieldId) && diff.diff.$set[updatefield].fields.push(item)); const sendBack = diff.diff.$set[updatefield].fields.length !== prelen; Database.Instance.update(diff.id, diff.diff, () => { -- cgit v1.2.3-70-g09d2 From e66380d8a99c3ee61faeaaebf6e28395332e1d64 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 14:12:06 -0400 Subject: fixed list additions to be truly incremental to allow undo to work --- src/client/views/collections/CollectionView.tsx | 1 - src/fields/List.ts | 2 +- src/fields/util.ts | 28 ++++++++++++++++--------- src/server/websocket.ts | 10 +++++---- 4 files changed, 25 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0ef3dd6cd..80e9b41ad 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -196,7 +196,6 @@ export class CollectionView extends Touchable { const ind = (targetDataDoc[this.props.fieldKey] as List).indexOf(doc); - (targetDataDoc[this.props.fieldKey] as List).splice(ind, 0); if (ind !== -1) { Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc); recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true); diff --git a/src/fields/List.ts b/src/fields/List.ts index dca8d111c..d9bd54673 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -43,7 +43,7 @@ const listHandlers: any = { } } const res = list.__fields.push(...items); - this[Update]("$addToSet"); + this[Update]({ op: "$addToSet", items }); return res; }), reverse() { diff --git a/src/fields/util.ts b/src/fields/util.ts index 90446f531..b6128f5e6 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -11,6 +11,8 @@ import { ComputedField } from "./ScriptField"; import { ScriptCast, StrCast } from "./Types"; import { returnZero } from "../Utils"; import CursorField from "./CursorField"; +import { undo } from "prosemirror-history"; +import { List } from "./List"; function _readOnlySetter(): never { @@ -371,20 +373,26 @@ export function deleteProperty(target: any, prop: string | number | symbol) { export function updateFunction(target: any, prop: any, value: any, receiver: any) { let current = ObjectField.MakeCopy(value); return (diff?: any) => { - if (diff === "$addToSet") { - diff = { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; - } else { - diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; - } + const op = diff?.op === "$addToSet" ? + { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(new List(diff.items)) } } + : { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; const oldValue = current; const newValue = ObjectField.MakeCopy(value); current = newValue; if (!(value instanceof CursorField) && !(value?.some?.((v: any) => v instanceof CursorField))) { - UndoManager.AddEvent({ - redo() { receiver[prop] = newValue; }, - undo() { receiver[prop] = oldValue; } - }); + UndoManager.AddEvent(diff?.op === "$addToSet" ? + { + redo: () => receiver[prop].push(...(newValue as List)), + undo: action(() => (newValue as List).forEach(doc => { + const ind = receiver[prop].indexOf(doc); + ind !== -1 && receiver[prop].splice(ind, 1); + })) + } + : { + redo: () => receiver[prop] = newValue, + undo: () => receiver[prop] = oldValue + }); } - target[Update](diff); + target[Update](op); }; } \ No newline at end of file diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 3687ef876..221a01308 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -271,14 +271,16 @@ export namespace WebSocket { return typeof value === "string" ? value : value[0]; } - function updateListField(socket: Socket, diff: Diff, results?: Transferable): void { + function updateListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { diff.diff.$set = diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones delete diff.diff.$addToSet; const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; - const list = (results as any).fields?.[updatefield.replace("fields.", "")]?.fields; + const newListItems = diff.diff.$set[updatefield].fields; + const curList = (curListItems as any).fields?.[updatefield.replace("fields.", "")]?.fields; const prelen = diff.diff.$set[updatefield].fields.length; - list?.forEach((item: any) => !diff.diff.$set[updatefield].fields.some((x: any) => x.fieldId === item.fieldId) && diff.diff.$set[updatefield].fields.push(item)); - const sendBack = diff.diff.$set[updatefield].fields.length !== prelen; + let insInd = 0; + curList?.forEach((curItem: any) => !newListItems.some((newItem: any) => newItem.fieldId === curItem.fieldId) && newListItems.splice(insInd++, 0, curItem)); + const sendBack = curList.length !== prelen; Database.Instance.update(diff.id, diff.diff, () => { if (sendBack) { -- cgit v1.2.3-70-g09d2 From 031e29b1cf14f643f3b52c52f77785e71f011708 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 14:29:43 -0400 Subject: from last --- src/client/util/CurrentUserUtils.ts | 2 +- src/fields/util.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f6ac363da..144c4b804 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -884,7 +884,7 @@ export class CurrentUserUtils { (sharedDocs as Doc)["acl-Public"] = Doc.GetProto(sharedDocs as Doc)["acl-Public"] = SharingPermissions.Add; } if (sharedDocs instanceof Doc) { - sharedDocs.userColor = sharedDocs.userColor || "#12121233"; + sharedDocs.userColor = sharedDocs.userColor || "#121212"; } doc.mySharedDocs = new PrefetchProxy(sharedDocs); } diff --git a/src/fields/util.ts b/src/fields/util.ts index b6128f5e6..6e72675db 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -382,8 +382,8 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any if (!(value instanceof CursorField) && !(value?.some?.((v: any) => v instanceof CursorField))) { UndoManager.AddEvent(diff?.op === "$addToSet" ? { - redo: () => receiver[prop].push(...(newValue as List)), - undo: action(() => (newValue as List).forEach(doc => { + redo: () => receiver[prop].push(...diff.items), + undo: action(() => diff.items.forEach((doc: Doc) => { const ind = receiver[prop].indexOf(doc); ind !== -1 && receiver[prop].splice(ind, 1); })) -- cgit v1.2.3-70-g09d2 From c65ca9da4ccdbb525ca7c4e50e7403cf6b543cbe Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 19:14:06 -0400 Subject: fixes for undo with multi-users --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/fields/List.ts | 3 +- src/fields/util.ts | 55 +++++++++++++++------- src/server/websocket.ts | 35 ++++++++++---- 4 files changed, 66 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fc3fd3a7c..1ddb709ac 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1160,7 +1160,7 @@ export class CollectionFreeFormView extends CollectionSubView { - super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); + // super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } diff --git a/src/fields/List.ts b/src/fields/List.ts index d9bd54673..ceb538b2d 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -66,6 +66,7 @@ const listHandlers: any = { this[Self].__realFields(); // coerce retrieving entire array items = items.map(toObjectField); const list = this[Self]; + const removed = list.__fields.filter((item: any, i: number) => i >= start && i < start + deleteCount); for (let i = 0; i < items.length; i++) { const item = items[i]; //TODO Error checking to make sure parent doesn't already exist @@ -76,7 +77,7 @@ const listHandlers: any = { } } const res = list.__fields.splice(start, deleteCount, ...items); - this[Update](); + this[Update](items.length === 0 && deleteCount ? { op: "$remFromSet", items: removed } : undefined); return res.map(toRealField); }), unshift(...items: any[]) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 6e72675db..b251236d0 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -11,10 +11,8 @@ import { ComputedField } from "./ScriptField"; import { ScriptCast, StrCast } from "./Types"; import { returnZero } from "../Utils"; import CursorField from "./CursorField"; -import { undo } from "prosemirror-history"; import { List } from "./List"; - function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); } @@ -95,7 +93,10 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number } else { DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); } - UndoManager.AddEvent({ + if (prop === "data-annotations") { + console.log("Yukc") + } + !receiver[UpdatingFromServer] && UndoManager.AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue }); @@ -373,25 +374,43 @@ export function deleteProperty(target: any, prop: string | number | symbol) { export function updateFunction(target: any, prop: any, value: any, receiver: any) { let current = ObjectField.MakeCopy(value); return (diff?: any) => { - const op = diff?.op === "$addToSet" ? - { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(new List(diff.items)) } } - : { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; + const op = diff?.op === "$addToSet" ? { '$addToSet': { ["fields." + prop]: SerializationHelper.Serialize(new List(diff.items)) } } : + diff?.op === "$remFromSet" ? { '$remFromSet': { ["fields." + prop]: SerializationHelper.Serialize(new List(diff.items)) } } + : { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; const oldValue = current; const newValue = ObjectField.MakeCopy(value); current = newValue; if (!(value instanceof CursorField) && !(value?.some?.((v: any) => v instanceof CursorField))) { - UndoManager.AddEvent(diff?.op === "$addToSet" ? - { - redo: () => receiver[prop].push(...diff.items), - undo: action(() => diff.items.forEach((doc: Doc) => { - const ind = receiver[prop].indexOf(doc); - ind !== -1 && receiver[prop].splice(ind, 1); - })) - } - : { - redo: () => receiver[prop] = newValue, - undo: () => receiver[prop] = oldValue - }); + !receiver[UpdatingFromServer] && UndoManager.AddEvent( + diff?.op === "$addToSet" ? + { + redo: () => { + receiver[prop].push(...diff.items); + }, + undo: action(() => { + let curList = receiver[prop]; + //while (curList[ForwardUpates]) curList = curList[ForwardUpates]; + diff.items.forEach((doc: any) => { + const ind = curList.indexOf(doc.value()); + ind !== -1 && curList.splice(ind, 1); + }); + }) + } : + diff?.op === "$remFromSet" ? + { + redo: action(() => { + let curList = receiver[prop]; + diff.items.forEach((doc: any) => { + const ind = curList.indexOf(doc.value()); + ind !== -1 && curList.splice(ind, 1); + }); + }), + undo: () => receiver[prop].push(...diff.items) + } + : { + redo: () => receiver[prop] = newValue, + undo: () => receiver[prop] = oldValue + }); } target[Update](op); }; diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 221a01308..459fa520b 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -271,16 +271,13 @@ export namespace WebSocket { return typeof value === "string" ? value : value[0]; } - function updateListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { - diff.diff.$set = diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones - delete diff.diff.$addToSet; + function addToListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { + diff.diff.$set = diff.diff.$addToSet; delete diff.diff.$addToSet;// convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; const newListItems = diff.diff.$set[updatefield].fields; - const curList = (curListItems as any).fields?.[updatefield.replace("fields.", "")]?.fields; - const prelen = diff.diff.$set[updatefield].fields.length; - let insInd = 0; - curList?.forEach((curItem: any) => !newListItems.some((newItem: any) => newItem.fieldId === curItem.fieldId) && newListItems.splice(insInd++, 0, curItem)); - const sendBack = curList.length !== prelen; + const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields || []; + diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => !curList.some((curItem: any) => curItem.fieldId === newItem.fieldId))]; + const sendBack = true;//curList.length !== prelen; Database.Instance.update(diff.id, diff.diff, () => { if (sendBack) { @@ -292,8 +289,28 @@ export namespace WebSocket { }, false); } + function remFromListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { + diff.diff.$set = diff.diff.$remFromSet; delete diff.diff.$remFromSet; + const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; + const remListItems = diff.diff.$set[updatefield].fields; + const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields || []; + diff.diff.$set[updatefield].fields = curList?.filter((curItem: any) => !remListItems.some((remItem: any) => remItem.fieldId === curItem.fieldId)); + const sendBack = true;//curList.length + remListItems.length !== prelen; + Database.Instance.update(diff.id, diff.diff, + () => { + if (sendBack) { + const id = socket.id; + socket.id = ""; + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + socket.id = id; + } else socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + }, false); + } + + function UpdateField(socket: Socket, diff: Diff) { - if (diff.diff.$addToSet) return GetRefField([diff.id, (result?: Transferable) => updateListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + if (diff.diff.$addToSet) return GetRefField([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + if (diff.diff.$remFromSet) return GetRefField([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); const docfield = diff.diff.$set || diff.diff.$unset; -- cgit v1.2.3-70-g09d2 From 647ca3d121921580090d5fc5c1fbaa7ae666992c Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 19:27:56 -0400 Subject: fromlast --- src/fields/util.ts | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/fields/util.ts b/src/fields/util.ts index b251236d0..8a694de83 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -93,9 +93,6 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number } else { DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); } - if (prop === "data-annotations") { - console.log("Yukc") - } !receiver[UpdatingFromServer] && UndoManager.AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue -- cgit v1.2.3-70-g09d2 From f6ff002d4b0ede04a2e2751677078b31763c780d Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 21:01:44 -0400 Subject: set default user color explicitly --- src/client/util/CurrentUserUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 144c4b804..1096b8e5f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -884,7 +884,7 @@ export class CurrentUserUtils { (sharedDocs as Doc)["acl-Public"] = Doc.GetProto(sharedDocs as Doc)["acl-Public"] = SharingPermissions.Add; } if (sharedDocs instanceof Doc) { - sharedDocs.userColor = sharedDocs.userColor || "#121212"; + sharedDocs.userColor = sharedDocs.userColor || "rgb(202, 202, 202)"; } doc.mySharedDocs = new PrefetchProxy(sharedDocs); } -- cgit v1.2.3-70-g09d2 From e32312a409673a23eb4af82ef33f41f8bf226292 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Oct 2020 22:37:41 -0400 Subject: runtime error fix for fetchProto(). fix for preview layout of text link. --- src/client/views/nodes/formattedText/FormattedTextBoxComment.scss | 3 --- src/fields/Doc.ts | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss b/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss index 582ada6ce..81afba4d7 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss @@ -29,9 +29,6 @@ font-style: italic; color: rgb(95, 97, 102); font-size: 10px; - padding-bottom: 4px; - margin-bottom: 5px; - } } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index a8a5ba9bd..54d85ba86 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -104,6 +104,7 @@ const AclMap = new Map([ ]); export function fetchProto(doc: Doc) { + if (!doc) return; const permissions: { [key: string]: symbol } = {}; Object.keys(doc).filter(key => key.startsWith("acl") && (permissions[key] = AclMap.get(StrCast(doc[key]))!)); -- cgit v1.2.3-70-g09d2 From b833f71fbd6a610164cc02a30dac60a3249a971d Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Wed, 7 Oct 2020 18:08:06 +0530 Subject: can add -> can augment in sharingmanager --- .vscode/settings.json | 4 ---- src/client/util/SharingManager.tsx | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/.vscode/settings.json b/.vscode/settings.json index e636c9d73..27acfd1a2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,8 +12,4 @@ "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, "search.usePCRE2": true, "typescript.tsdk": "node_modules/typescript/lib", - "python.testing.promptToConfigure": false, - "python.testing.pytestEnabled": false, - "python.testing.unittestEnabled": false, - "python.testing.nosetestsEnabled": false } \ No newline at end of file diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index c67ec2db5..d2e25dc26 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -470,7 +470,7 @@ export class SharingManager extends React.Component<{}> { ) : (

- {permissions} + {permissions === SharingPermissions.Add ? "Can Augment" : permissions}
)}
-- cgit v1.2.3-70-g09d2 From c8cb8b63764bba4a1d885745f53ee43ae78c2d46 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 7 Oct 2020 10:42:19 -0400 Subject: fixed portals to zoom in place. fixed following links to not focus on context if starting anchor is in the same context. maded pushpins call finished() --- src/client/util/DocumentManager.ts | 4 ++-- src/client/views/nodes/DocumentView.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e2518d05f..cb9aa35d0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -151,7 +151,7 @@ export class DocumentManager { }; const docView = getFirstDocView(targetDoc, originatingDoc); let annotatedDoc = await Cast(targetDoc.annotationOn, Doc); - if (annotatedDoc && !targetDoc?.isPushpin) { + if (annotatedDoc && annotatedDoc !== docContext && !targetDoc?.isPushpin) { const first = getFirstDocView(annotatedDoc); if (first) { annotatedDoc = first.props.Document; @@ -161,6 +161,7 @@ export class DocumentManager { if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? if (originatingDoc?.isPushpin) { docView.props.Document.hidden = !docView.props.Document.hidden; + finished?.(); } else { docView.select(false); @@ -216,7 +217,6 @@ export class DocumentManager { public async FollowLink(link: Opt, doc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) { const linkDocs = link ? [link] : DocListCast(doc.links); - SelectionManager.DeselectAll(); const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor1 const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor2 const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ddcf7f6f4..369b53aa0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -740,6 +740,7 @@ export class DocumentView extends DocComponent(Docu const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), title: StrCast(this.props.Document.title) + ".portal" }); DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to"); } + this.Document.followLinkLocation = "inPlace"; this.Document.followLinkZoom = true; this.Document.isLinkButton = true; } -- cgit v1.2.3-70-g09d2 From c6e407d7ab92244964c2fad05b6a68d124bf18df Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 7 Oct 2020 11:32:23 -0400 Subject: fixed following links to not center outer document if originating anchor is in that document. fixed scroling to happen instantly if it's already scrolled there. fixed clicking on pdf text anchor to select the pdf. --- src/client/util/DocumentManager.ts | 5 +++-- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 11 +++++++---- src/client/views/pdf/Annotation.tsx | 7 +++++-- src/client/views/pdf/PDFViewer.tsx | 7 ++++--- 4 files changed, 19 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index cb9aa35d0..4becdf4a3 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -151,7 +151,7 @@ export class DocumentManager { }; const docView = getFirstDocView(targetDoc, originatingDoc); let annotatedDoc = await Cast(targetDoc.annotationOn, Doc); - if (annotatedDoc && annotatedDoc !== docContext && !targetDoc?.isPushpin) { + if (annotatedDoc && annotatedDoc !== originatingDoc?.context && !targetDoc?.isPushpin) { const first = getFirstDocView(annotatedDoc); if (first) { annotatedDoc = first.props.Document; @@ -166,7 +166,8 @@ export class DocumentManager { else { docView.select(false); docView.props.Document.hidden && (docView.props.Document.hidden = undefined); - docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); + // @ts-ignore + docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish, annotatedDoc && annotatedDoc === originatingDoc?.context); highlight(); } } else { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1ddb709ac..35b4c8e98 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -867,7 +867,7 @@ export class CollectionFreeFormView extends CollectionSubView boolean) => { + focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean, dontCenter?: boolean) => { const state = HistoryUtil.getState(); // TODO This technically isn't correct if type !== "doc", as @@ -886,16 +886,19 @@ export class CollectionFreeFormView extends CollectionSubView 5 ? 1000 : 0; } - this.props.focus(this.props.Document); - afterFocus && setTimeout(afterFocus, 1000); + !dontCenter && this.props.focus(this.props.Document); + afterFocus && setTimeout(afterFocus, delay); } else { const layoutdoc = Doc.Layout(doc); const newPanX = NumCast(doc.x) + NumCast(layoutdoc._width) / 2; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 84b14cd61..e7f901091 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -15,6 +15,7 @@ interface IAnnotationProps { addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc, unpin?: boolean) => void; focus: (doc: Doc) => void; + select: (isCtrlPressed: boolean) => void; dataDoc: Doc; fieldKey: string; showInfo: (anno: Opt) => void; @@ -25,7 +26,7 @@ export class Annotation extends React.Component { render() { return DocListCast(this.props.anno.annotations).map(a => - ); + ); } } @@ -37,6 +38,7 @@ interface IRegionAnnotationProps { height: number; addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc, unpin: boolean) => void; + select: (isCtrlPressed: boolean) => void; document: Doc; dataDoc: Doc; fieldKey: string; @@ -115,7 +117,8 @@ class RegionAnnotation extends React.Component { e.persist(); e.stopPropagation(); PromiseValue(this.props.document.group).then(annoGroup => annoGroup instanceof Doc && - DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation), false, undefined) + DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation), false, undefined, + () => this.props.select(false)) ); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 4c5f72b97..3570c565a 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -460,7 +460,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { const hit = document.elementFromPoint(e.clientX, e.clientY); - if (hit && hit.localName === "span" && this.props.isSelected(true)) { // drag selecting text stops propagation + if (hit && hit.localName === "span" && this.annotationsActive(true)) { // drag selecting text stops propagation e.button === 0 && e.stopPropagation(); } // if alt+left click, drag and annotate @@ -557,6 +557,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { clearStyleSheetRules(PDFViewer._annotationStyle); + this.props.select(false); this._savedAnnotations.clear(); if (this._marqueeing) { if (this._marqueeWidth > 10 || this._marqueeHeight > 10) { @@ -694,7 +695,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - ) + ) } ; } @@ -763,7 +764,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._zoomed; render() { TraceMobx(); - return
Date: Wed, 7 Oct 2020 15:02:16 -0400 Subject: fixed following links to set the scollTop of PDFs corretion. Fixed following links to rich text anchors to scroll and highlight properly. fixed pushpin behavior to only toggle off when the target is in sight. --- src/client/util/DocumentManager.ts | 13 ++++++++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 22 ++++++++++++++++------ .../views/nodes/formattedText/FormattedTextBox.tsx | 12 +++++++----- src/client/views/pdf/PDFViewer.tsx | 2 +- src/fields/util.ts | 4 ++-- 5 files changed, 36 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 4becdf4a3..ce4e1e378 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -159,17 +159,24 @@ export class DocumentManager { } } if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? + const sameContext = annotatedDoc && annotatedDoc === originatingDoc?.context; if (originatingDoc?.isPushpin) { - docView.props.Document.hidden = !docView.props.Document.hidden; + const hide = !docView.props.Document.hidden; + (!hide || !sameContext) && (docView.props.Document.hidden = !docView.props.Document.hidden); + docView.props.focus(docView.props.Document, willZoom, undefined, (notfocused: boolean) => { // bcz: Argh! TODO: Need to add a notFocused argument to the after finish callback function that indicates whether the window had to scroll to show the target + notfocused && hide && (docView.props.Document.hidden = true); + return focusAndFinish(); + // @ts-ignore bcz: Argh TODO: Need to add a parameter to focus() everywhere for whether focus should center the target's container in the view or not. // here we don't want to focus the container if the source and target are in the same container + }, sameContext); finished?.(); } else { docView.select(false); docView.props.Document.hidden && (docView.props.Document.hidden = undefined); // @ts-ignore - docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish, annotatedDoc && annotatedDoc === originatingDoc?.context); - highlight(); + docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish, sameContext); } + highlight(); } else { const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc)) ? docContext : undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 35b4c8e98..382929861 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -888,17 +888,27 @@ export class CollectionFreeFormView extends CollectionSubView 5 ? 1000 : 0; + const curScroll = NumCast(this.props.Document._scrollTop); + let scrollTo = curScroll; + if (curScroll + contextHgt < NumCast(doc.y)) { + scrollTo = NumCast(doc.y) + NumCast(doc._height) - contextHgt; + } else if (curScroll > NumCast(doc.y)) { + scrollTo = NumCast(doc.y); + } + if (curScroll !== scrollTo) { + this.props.Document._scrollY = scrollTo; + delay = Math.abs(scrollTo - curScroll) > 5 ? 1000 : 0; + !dontCenter && delay && this.props.focus(this.props.Document); + afterFocus && setTimeout(afterFocus, delay); + // @ts-ignore + } else afterFocus(true); // bcz: TODO Aragh -- need to add a parameter to afterFocus() functions to indicate whether the focus function didn't need to scroll } - !dontCenter && this.props.focus(this.props.Document); - afterFocus && setTimeout(afterFocus, delay); } else { const layoutdoc = Doc.Layout(doc); const newPanX = NumCast(doc.x) + NumCast(layoutdoc._width) / 2; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ef39e6a90..0fccbd8ef 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -916,11 +916,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp async (scrollToLinkID) => { const findLinkFrag = (frag: Fragment, editor: EditorView) => { const nodes: Node[] = []; + let hadStart = start !== 0; frag.forEach((node, index) => { const examinedNode = findLinkNode(node, editor); - if (examinedNode?.textContent) { - nodes.push(examinedNode); - !start && (start = index); + if (examinedNode?.node.textContent) { + nodes.push(examinedNode.node); + !hadStart && (start = index + examinedNode.start); + hadStart = true; } }); return { frag: Fragment.fromArray(nodes), start }; @@ -928,11 +930,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const findLinkNode = (node: Node, editor: EditorView) => { if (!node.isText) { const content = findLinkFrag(node.content, editor); - return node.copy(content.frag); + return { node: node.copy(content.frag), start: content.start }; } const marks = [...node.marks]; const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor); - return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? node : undefined; + return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? { node, start: 0 } : undefined; }; let start = 0; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 3570c565a..606d3e550 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -184,7 +184,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._mainCont.current && smoothScroll(1000, this._mainCont.current, scrollY || 0), 250); } - setTimeout(() => this.Document._scrollY = undefined, 1000); + setTimeout(() => { this.Document._scrollTop = scrollY; this.Document._scrollY = undefined; }, 1000); } }, { fireImmediately: true } diff --git a/src/fields/util.ts b/src/fields/util.ts index 8a694de83..7293db0c2 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -385,7 +385,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any receiver[prop].push(...diff.items); }, undo: action(() => { - let curList = receiver[prop]; + const curList = receiver[prop]; //while (curList[ForwardUpates]) curList = curList[ForwardUpates]; diff.items.forEach((doc: any) => { const ind = curList.indexOf(doc.value()); @@ -396,7 +396,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any diff?.op === "$remFromSet" ? { redo: action(() => { - let curList = receiver[prop]; + const curList = receiver[prop]; diff.items.forEach((doc: any) => { const ind = curList.indexOf(doc.value()); ind !== -1 && curList.splice(ind, 1); -- cgit v1.2.3-70-g09d2 From 192e23a2ae335a5f0de361eed9a24a5d08547217 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 7 Oct 2020 17:49:20 -0400 Subject: fixed undoing changes to a textbox's fontsize/family. changed auto-page ref syntax to start with ':'. fixed making text menu appear when clicking on caption & other text boxes. --- src/client/views/collections/CollectionMenu.tsx | 45 +++++++++++----------- .../views/nodes/formattedText/FormattedTextBox.tsx | 5 +-- .../views/nodes/formattedText/RichTextMenu.tsx | 45 ++++++++++++---------- .../views/nodes/formattedText/RichTextRules.ts | 6 +-- 4 files changed, 50 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 09ff3bb0c..4bdb233c9 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -529,12 +529,7 @@ export class CollectionFreeFormViewChrome extends React.Component - {!Doc.UserDoc().noviceMode && !this.isText && !this.props.isDoc ? Back Frame
} placement="bottom"> -
- -
- : null} - {!Doc.UserDoc().noviceMode && !this.isText && !this.props.isDoc ? Toggle View All} placement="bottom"> -
this.document.editing = !this.document.editing)} > - {NumCast(this.document._currentFrame)} -
-
: null} - {!Doc.UserDoc().noviceMode && !this.isText && !this.props.isDoc ? Forward Frame} placement="bottom"> -
- -
-
: null} + {!Doc.UserDoc().noviceMode && !this.isText && !this.props.isDoc ? + <> + Back Frame} placement="bottom"> +
+ +
+
+ Toggle View All} placement="bottom"> +
this.document.editing = !this.document.editing)} > + {NumCast(this.document._currentFrame)} +
+
+ Forward Frame} placement="bottom"> +
+ +
+
+ + : null} {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText || this.props.isDoc ? (null) : this.urlEditor @@ -872,7 +871,7 @@ export class CollectionFreeFormViewChrome extends React.Component : (null) } - {this.isText ? : null} + {
} ; } } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 0fccbd8ef..c6bd0cb81 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1321,6 +1321,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) { y = Math.min(bounds.bottom, window.innerHeight - RichTextMenu.Instance.height); } + this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props); setTimeout(() => window.document.activeElement === this.ProseRef?.children[0] && RichTextMenu.Instance.jumpTo(x, y), 250); } } @@ -1557,9 +1558,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
{ - console.log(e); - }} />; } @@ -1608,7 +1606,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const scale = this.props.hideOnLeave ? 1 : this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = (Doc.GetSelectedTool() === InkTool.None || SnappingManager.GetIsDragging()) && !this.layoutDoc._isBackground; - selected && setTimeout(() => this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props)); // need to make sure that we update a text box that is selected after updating the one that was deselected if (!selected && FormattedTextBoxComment.textBox === this) { FormattedTextBoxComment.Hide(); } const minimal = this.props.ignoreAutoHeight; const margins = NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 68239a8f1..d492b561b 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -32,7 +32,7 @@ export class RichTextMenu extends AntimodeMenu { static Instance: RichTextMenu; public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable - public view?: EditorView; + @observable public view?: EditorView; public editorProps: FieldViewProps & FormattedTextBoxProps | undefined; public _brushMap: Map> = new Map(); @@ -154,7 +154,7 @@ export class RichTextMenu extends AntimodeMenu { @action public updateMenu(view: EditorView, lastState: EditorState | undefined, props: any) { - if (!view || !(view as any).TextView?.props.isSelected(true) || !view.hasFocus()) { + if (!view || !view.hasFocus()) { return; } this.view = view; @@ -366,7 +366,7 @@ export class RichTextMenu extends AntimodeMenu { ); } - createMarksDropdown(activeOption: string, options: { mark: Mark | null, title: string, label: string, command: (mark: Mark, view: EditorView) => void, hidden?: boolean, style?: {} }[], key: string, setter: (val: string) => {}): JSX.Element { + createMarksDropdown(activeOption: string, options: { mark: Mark | null, title: string, label: string, command: (mark: Mark, view: EditorView) => void, hidden?: boolean, style?: {} }[], key: string, setter: (val: string) => void): JSX.Element { const items = options.map(({ title, label, hidden, style }) => { if (hidden) { return ; @@ -378,19 +378,22 @@ export class RichTextMenu extends AntimodeMenu { function onChange(e: React.ChangeEvent) { e.stopPropagation(); e.preventDefault(); - self.TextView.endUndoTypingBatch(); - options.forEach(({ label, mark, command }) => { - if (e.target.value === label && mark) { - if (!self.TextView.props.isSelected(true)) { - switch (mark.type) { - case schema.marks.pFontFamily: setter(Doc.UserDoc().fontFamily = mark.attrs.family); break; - case schema.marks.pFontSize: setter(Doc.UserDoc().fontSize = mark.attrs.fontSize.toString() + "px"); break; + self.TextView?.endUndoTypingBatch(); + UndoManager.RunInBatch(() => { + options.forEach(({ label, mark, command }) => { + if (e.target.value === label && mark) { + if (!self.TextView?.props.isSelected(true)) { + switch (mark.type) { + case schema.marks.pFontFamily: setter(Doc.UserDoc().fontFamily = mark.attrs.family); break; + case schema.marks.pFontSize: setter(Doc.UserDoc().fontSize = mark.attrs.fontSize.toString() + "px"); break; + } } + else self.view && mark && command(mark, self.view); } - else UndoManager.RunInBatch(() => self.view && mark && command(mark, self.view), "text mark dropdown"); - } - }); + }); + }, "text mark dropdown"); } + return {key}
} placement="bottom"> ; @@ -424,9 +427,6 @@ export class RichTextMenu extends AntimodeMenu { } changeFontSize = (mark: Mark, view: EditorView) => { - if ((this.view?.state.selection.$from.pos || 0) < 2) { - this.TextView.layoutDoc._fontSize = mark.attrs.fontSize === Number(mark.attrs.fontSize) ? `${mark.attrs.fontSize}pt` : mark.attrs.fontSize; - } const fmark = view.state.schema.marks.pFontSize.create({ fontSize: mark.attrs.fontSize }); this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true); view.focus(); @@ -434,9 +434,6 @@ export class RichTextMenu extends AntimodeMenu { } changeFontFamily = (mark: Mark, view: EditorView) => { - if ((this.view?.state.selection.$from.pos || 0) < 2) { - this.TextView.layoutDoc._fontFamily = mark.attrs.family; - } const fmark = view.state.schema.marks.pFontFamily.create({ family: mark.attrs.family }); this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true); view.focus(); @@ -984,8 +981,14 @@ export class RichTextMenu extends AntimodeMenu { {this.collapsed ? this.getDragger() : (null)}
, - {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => this.activeFontSize = val)), - this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family", action((val: string) => this.activeFontFamily = val)), + {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => { + this.activeFontSize = val; + SelectionManager.SelectedDocuments().map(dv => dv.props.Document._fontSize = val); + })), + this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family", action((val: string) => { + this.activeFontFamily = val; + SelectionManager.SelectedDocuments().map(dv => dv.props.Document._fontFamily = val); + })),
, this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", () => ({})), this.createButton("sort-amount-down", "Summarize", undefined, this.insertSummarizer), diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 72b91c955..99334b6db 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -267,11 +267,11 @@ export class RichTextRules { // [[fieldKey]] => show field // [[fieldKey:Doc]] => show field of doc new InputRule( - new RegExp(/\[\[([a-zA-Z_@\? \-0-9]*)(=[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 rawdocid = match[3]?.substring(1); - const docid = rawdocid ? (!rawdocid.includes("@") ? normalizeEmail(Doc.CurrentUserEmail) + "@" + rawdocid : rawdocid) : undefined; + const rawdocid = match[3]; + const docid = rawdocid ? normalizeEmail((!rawdocid.includes("@") ? Doc.CurrentUserEmail + rawdocid : rawdocid.substring(1))) : undefined; const value = match[2]?.substring(1); if (!fieldKey) { const linkId = Utils.GenerateGuid(); -- cgit v1.2.3-70-g09d2 From a722aab6a65ad8d222ec3d576497ce9687cac966 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 8 Oct 2020 00:44:43 -0400 Subject: fixed adding/removing schema columns. fixed showing text/ink tools in menu at right time. cleaned up schema view a bit and fixed drag bar from disappearing when shown in full tab. --- src/client/views/collections/CollectionMenu.tsx | 4 +- .../views/collections/CollectionSchemaView.scss | 5 +- .../views/collections/CollectionSchemaView.tsx | 148 +++++++-------------- src/client/views/collections/SchemaTable.tsx | 6 +- src/client/views/globalCssVariables.scss | 2 + src/client/views/globalCssVariables.scss.d.ts | 1 + .../views/nodes/formattedText/FormattedTextBox.tsx | 1 + .../views/nodes/formattedText/RichTextMenu.tsx | 4 +- src/server/websocket.ts | 4 +- 9 files changed, 63 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 4bdb233c9..429764154 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -528,9 +528,7 @@ export class CollectionFreeFormViewChrome extends React.Component = new Map([ @observer export class CollectionSchemaView extends CollectionSubView(doc => doc) { private _previewCont?: HTMLDivElement; - private DIVIDER_WIDTH = 4; - - @observable previewDoc: Doc | undefined = undefined; - @observable private _focusedTable: Doc = this.props.Document; - - @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } - @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } - @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH - this.previewWidth(); } - @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } + @observable _previewDoc: Doc | undefined = undefined; + @observable _focusedTable: Doc = this.props.Document; + @observable _col: any = ""; @observable _menuWidth = 0; @observable _headerOpen = false; @observable _headerIsEditing = false; - @observable _col: any = ""; @observable _menuHeight = 0; @observable _pointerX = 0; @observable _pointerY = 0; @observable _openTypes: boolean = false; + + @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } + @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } + @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); } + @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } + @computed get scale() { return this.props.ScreenToLocalTransform().Scale; } + @computed get columns() { return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); } + set columns(columns: SchemaHeaderField[]) { this.props.Document._schemaHeaders = new List(columns); } + @computed get menuCoordinates() { let searchx = 0; let searchy = 0; @@ -81,15 +83,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { return this.props.ScreenToLocalTransform().transformPoint(x, y); } - @computed get scale() { return this.props.ScreenToLocalTransform().Scale; } - - @computed get columns() { - return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); - } - set columns(columns: SchemaHeaderField[]) { - this.props.Document._schemaHeaders = new List(columns); - } - get documentKeys() { const docs = this.childDocs; const keys: { [key: string]: boolean } = {}; @@ -104,27 +97,12 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { this.columns.forEach(key => keys[key.heading] = true); return Array.from(Object.keys(keys)); } - @computed get possibleKeys() { return this.documentKeys.filter(key => this.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1); } @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing; - - @action - changeColumnType = (type: ColumnType, col: any): void => { - this._openTypes = false; - this.setColumnType(col, type); - } - - changeColumnSort = (desc: boolean | undefined, col: any): void => { - this.setColumnSort(col, desc); - } - - changeColumnColor = (color: string, col: any): void => { - this.setColumnColor(col, color); - } - @undoBatch setColumnType = (columnField: SchemaHeaderField, type: ColumnType): void => { + this._openTypes = false; if (columnTypes.get(columnField.heading)) return; const columns = this.columns; @@ -165,42 +143,42 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { const type = col.type; - const anyType =
this.changeColumnType(ColumnType.Any, col)}> + const anyType =
this.setColumnType(col, ColumnType.Any)}> Any
; - const numType =
this.changeColumnType(ColumnType.Number, col)}> + const numType =
this.setColumnType(col, ColumnType.Number)}> Number
; - const textType =
this.changeColumnType(ColumnType.String, col)}> + const textType =
this.setColumnType(col, ColumnType.String)}> Text
; - const boolType =
this.changeColumnType(ColumnType.Boolean, col)}> + const boolType =
this.setColumnType(col, ColumnType.Boolean)}> Checkbox
; - const listType =
this.changeColumnType(ColumnType.List, col)}> + const listType =
this.setColumnType(col, ColumnType.List)}> List
; - const docType =
this.changeColumnType(ColumnType.Doc, col)}> + const docType =
this.setColumnType(col, ColumnType.Doc)}> Document
; - const imageType =
this.changeColumnType(ColumnType.Image, col)}> + const imageType =
this.setColumnType(col, ColumnType.Image)}> Image
; - const dateType =
this.changeColumnType(ColumnType.Date, col)}> + const dateType =
this.setColumnType(col, ColumnType.Date)}> Date
; @@ -239,15 +217,15 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
-
this.changeColumnSort(true, col)}> +
this.setColumnSort(col, true)}> Sort descending
-
this.changeColumnSort(false, col)}> +
this.setColumnSort(col, false)}> Sort ascending
-
this.changeColumnSort(undefined, col)}> +
this.setColumnSort(col, undefined)}> Clear sorting
@@ -270,12 +248,12 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
-
this.changeColumnColor(pink!, col)}>
-
this.changeColumnColor(purple!, col)}>
-
this.changeColumnColor(blue!, col)}>
-
this.changeColumnColor(yellow!, col)}>
-
this.changeColumnColor(red!, col)}>
-
this.changeColumnColor(gray, col)}>
+
this.setColumnColor(col, pink!)}>
+
this.setColumnColor(col, purple!)}>
+
this.setColumnColor(col, blue!)}>
+
this.setColumnColor(col, yellow!)}>
+
this.setColumnColor(col, red!)}>
+
this.setColumnColor(col, gray)}>
); @@ -320,8 +298,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @action closeHeader = () => { this._headerOpen = false; } - - @undoBatch @action deleteColumn = (key: string) => { @@ -351,15 +327,12 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { onWheel(e: React.WheelEvent) { const scale = this.props.ScreenToLocalTransform().Scale; this.props.active(true) && e.stopPropagation(); - //this.menuCoordinates[0] -= e.screenX / scale; - //this.menuCoordinates[1] -= e.screenY / scale; } @computed get renderMenuContent() { TraceMobx(); return
{this.renderTypes(this._col)} - {/* {this.renderSorting(this._col)} */} {this.renderColors(this._col)}