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 --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') 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 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/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') 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 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/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') 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/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') 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 4148b34504b51fade019389d7592cf825ddc0fa9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 8 Oct 2020 13:32:27 -0400 Subject: fixes for getting pdfs and previews to scroll properly --- src/client/util/DocumentManager.ts | 6 +++++- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 2 +- .../formattedText/FormattedTextBoxComment.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 23 +++++++++++++++++----- 5 files changed, 26 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ce4e1e378..178daf5f0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -10,6 +10,8 @@ import { DocumentView } from '../views/nodes/DocumentView'; import { LinkManager } from './LinkManager'; import { Scripting } from './Scripting'; import { SelectionManager } from './SelectionManager'; +import { LinkDocPreview } from '../views/nodes/LinkDocPreview'; +import { FormattedTextBoxComment } from '../views/nodes/formattedText/FormattedTextBoxComment'; export type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; @@ -187,7 +189,7 @@ export class DocumentManager { highlight(); } else { // otherwise try to get a view of the context of the target const targetDocContextView = getFirstDocView(targetDocContext); - targetDocContext._scrollY = NumCast(targetDocContext._scrollTop, 0); // this will force PDFs to activate and load their annotations / allow scrolling + targetDocContext._scrollY = targetDocContext._scrollPY = NumCast(targetDocContext._scrollTop, 0); // this will force PDFs to activate and load their annotations / allow scrolling if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first.. targetDocContext._viewTransition = "transform 500ms"; targetDocContextView.props.focus(targetDocContextView.props.Document, willZoom); @@ -224,6 +226,8 @@ export class DocumentManager { } public async FollowLink(link: Opt, doc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) { + LinkDocPreview.TargetDoc = undefined; + FormattedTextBoxComment.linkDoc = undefined; const linkDocs = link ? [link] : DocListCast(doc.links); 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 diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 382929861..5236fab27 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -901,7 +901,7 @@ export class CollectionFreeFormView extends CollectionSubView 5 ? 1000 : 0; !dontCenter && delay && this.props.focus(this.props.Document); afterFocus && setTimeout(afterFocus, delay); diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index d14157c09..8f9cb5b0e 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -64,7 +64,7 @@ export class LinkDocPreview extends React.Component { this._toolTipText = ""; LinkDocPreview.TargetDoc = this._targetDoc = target; if (anchor !== this._targetDoc && anchor && this._targetDoc) { - this._targetDoc._scrollY = NumCast(anchor?.y); + this._targetDoc._scrollPY = NumCast(anchor?.y); } }); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 5183e193b..f96fda861 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -260,7 +260,7 @@ export class FormattedTextBoxComment { const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; if (anchor !== target && anchor && target) { - target._scrollY = NumCast(anchor?.y); + target._scrollPY = NumCast(anchor?.y); } if (target?.author) { FormattedTextBoxComment.showCommentbox("", view, nbef); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 606d3e550..c669a5e5f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -179,12 +179,25 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { if (scrollY !== undefined) { (this._showCover || this._showWaiting) && this.setupPdfJsViewer(); - if ((this.props.renderDepth === -1 || (!LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc)) && this._mainCont.current) { - smoothScroll(1000, this._mainCont.current, scrollY || 0); - } else if (!LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) { // wait for mainCont and try again to scroll - setTimeout(() => this._mainCont.current && smoothScroll(1000, this._mainCont.current, scrollY || 0), 250); + if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) { + const delay = this._mainCont.current ? 0 : 250; // wait for mainCont and try again to scroll + setTimeout(() => this._mainCont.current && smoothScroll(1000, this._mainCont.current, Math.abs(scrollY || 0)), delay); + setTimeout(() => { this.Document._scrollTop = scrollY; this.Document._scrollY = undefined; }, 1000 + delay); + } + } + }, + { fireImmediately: true } + ); + this._disposers.scrollPY = reaction( + () => Cast(this.Document._scrollPY, "number", null), + (scrollY) => { + if (scrollY !== undefined) { + (this._showCover || this._showWaiting) && this.setupPdfJsViewer(); + if (this.props.renderDepth === -1 && scrollY >= 0) { + if (!this._mainCont.current) setTimeout(() => smoothScroll(1000, this._mainCont.current!, scrollY || 0)); + else smoothScroll(1000, this._mainCont.current, scrollY || 0); + this.Document._scrollPY = undefined; } - setTimeout(() => { this.Document._scrollTop = scrollY; this.Document._scrollY = undefined; }, 1000); } }, { fireImmediately: true } -- cgit v1.2.3-70-g09d2 From c150d0afa46c2c45e413a5269d26bc46b64ba765 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 8 Oct 2020 23:21:04 -0400 Subject: fixed dragging bottom of some pdfs not to grow wildly. stopped writing renderContentBounds to annotation views. fixed texts sidebar notes to not add extra chars on creation. --- src/client/views/DocumentDecorations.tsx | 2 +- .../views/collections/CollectionStackingViewFieldColumn.tsx | 8 ++++---- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 066cfd95a..66f0dd99d 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -450,7 +450,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> height = !height || isNaN(height) ? 20 : height; const scale = docView.props.ScreenToLocalTransform().Scale * docView.props.ContentScaling(); if (nwidth && nheight) { - if (nwidth / nheight !== width / height) { + if (nwidth / nheight !== width / height && !dragBottom) { height = nheight / nwidth * width; } if (e.ctrlKey || (!dragBottom || !docView.layoutDoc._fitWidth)) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 74ea824cd..b7562c45e 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -132,12 +132,12 @@ export class CollectionStackingViewFieldColumn extends React.Component { - return this.addDocument(char, false); + return this.addDocument("", false, true); } @action - addDocument = (value: string, shiftDown?: boolean) => { - if (!value) return false; + addDocument = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { + if (!value && !forceEmptyNote) return false; const key = StrCast(this.props.parent.props.Document._pivotField); const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, title: value, _autoHeight: true }); newDoc[key] = this.getValue(this.props.heading); @@ -145,7 +145,7 @@ export class CollectionStackingViewFieldColumn extends React.Component this.Document._renderContentBounds = new List([this.contentBounds.x, this.contentBounds.y, this.contentBounds.r, this.contentBounds.b]), 0); + !this.fitToContent && !this.props.annotationsKey && this._layoutElements?.length && setTimeout(() => this.Document._renderContentBounds = new List([this.contentBounds.x, this.contentBounds.y, this.contentBounds.r, this.contentBounds.b]), 0); return
Date: Sat, 10 Oct 2020 17:56:34 -0400 Subject: fixed scrolling down to annotations that have no height (but really do -- eg pdf selections) to at least show 50 pixels. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 796765a8d..d48961849 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -896,7 +896,7 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc.y)) { scrollTo = NumCast(doc.y); } -- cgit v1.2.3-70-g09d2 From 3256d0f42401b8dd8745e7f32c25033e118b444b Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 11 Oct 2020 17:22:03 -0400 Subject: removed setting fields to undefined when Acl is Private in hopes of not losing data when permissions are changed. prevented server writes on startup by making renderContentBounds setting a reaction, and making linearView not resize if documents are still promises and make text boxes not flip-flop their height all the time. --- src/client/views/collections/CollectionLinearView.tsx | 4 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 15 +++++++++++++-- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 3 +-- src/fields/Doc.ts | 10 +++++----- 4 files changed, 21 insertions(+), 11 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index 859ee9362..0eac5136a 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -38,8 +38,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { componentDidMount() { // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported). - this._widthDisposer = reaction(() => this.props.Document[HeightSym]() + this.childDocs.length + (this.props.Document.linearViewIsExpanded ? 1 : 0), - () => this.props.Document._width = 5 + (this.props.Document.linearViewIsExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), + this._widthDisposer = reaction(() => 5 + (this.props.Document.linearViewIsExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), + width => this.childDocs.length && (this.props.Document._width = width), { fireImmediately: true } ); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d48961849..4d9906f93 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -7,7 +7,7 @@ import { Id } from "../../../../fields/FieldSymbols"; import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { RichTextField } from "../../../../fields/RichTextField"; -import { createSchema, makeInterface } from "../../../../fields/Schema"; +import { createSchema, makeInterface, listSpec } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; @@ -88,6 +88,7 @@ export class CollectionFreeFormView extends CollectionSubView(); private _layoutSizeData = new ObservableMap(); private _cachedPool: Map = new Map(); @@ -1159,12 +1160,22 @@ export class CollectionFreeFormView extends CollectionSubView this.doLayoutComputation, (elements) => this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); + if (!this.props.annotationsKey) { + this._boundsReaction = reaction(() => this.contentBounds, + bounds => (!this.fitToContent && this._layoutElements?.length) && setTimeout(() => { + const rbounds = Cast(this.Document._renderContentBounds, listSpec("number"), [0, 0, 0, 0]); + if (rbounds[0] !== bounds.x || rbounds[1] !== bounds.y || rbounds[2] !== bounds.r || rbounds[3] !== bounds.b) { + this.Document._renderContentBounds = new List([bounds.x, bounds.y, bounds.r, bounds.b]); + } + })); + } this._marqueeRef.current?.addEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); } componentWillUnmount() { this._layoutComputeReaction?.(); + this._boundsReaction?.(); this._marqueeRef.current?.removeEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); } @@ -1438,10 +1449,10 @@ export class CollectionFreeFormView extends CollectionSubView this.Document._renderContentBounds = new List([this.contentBounds.x, this.contentBounds.y, this.contentBounds.r, this.contentBounds.b]), 0); return
limitHeight) { @@ -1545,7 +1544,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.rootDoc[this.fieldKey + "-height"] = finalHeight; } catch (e) { console.log("Error in tryUpdateHeight"); } } - } + } else this.rootDoc[this.fieldKey + "-height"] = 0; } @computed get audioHandle() { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 7dd894ec4..086b7777f 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -240,11 +240,11 @@ export class Doc extends RefField { if (prev === AclPrivate && GetEffectiveAcl(this) !== AclPrivate) { DocServer.GetRefField(this[Id], true); } - if (prev !== AclPrivate && GetEffectiveAcl(this) === AclPrivate) { - this[UpdatingFromServer] = true; - this[FieldsSym](true); - this[UpdatingFromServer] = false; - } + // if (prev !== AclPrivate && GetEffectiveAcl(this) === AclPrivate) { + // this[UpdatingFromServer] = true; + // this[FieldsSym](true); + // this[UpdatingFromServer] = false; + // } }; if (sameAuthor || fKey.startsWith("acl") || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { delete this[CachedUpdates][fKey]; -- cgit v1.2.3-70-g09d2 From 27635402ad810b910557eb1a86c7e85fa281aaee Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 12 Oct 2020 01:05:13 -0400 Subject: switched fonticonbox and colelctionsubview to test GetEffectiveAcl to determine if document is available (instead of hack of testing 'author'). made GetEffectiveAcl a computedFn. No longer create a pushpin when an annotation that's linked to text is dragged off a PDF. fixed undo of pushpin navigation (used to call finish() twice). fixed pushpin navigation to conistenly pan & sensibly toggle target --- src/client/util/DocumentManager.ts | 9 +++++---- src/client/views/collections/CollectionSubView.tsx | 5 +++-- src/client/views/collections/CollectionView.tsx | 3 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 +++++++++++++-------- src/client/views/nodes/FontIconBox.tsx | 5 +++-- src/client/views/pdf/Annotation.tsx | 2 ++ src/client/views/pdf/PDFViewer.tsx | 2 +- src/fields/util.ts | 14 ++++++++++---- 8 files changed, 39 insertions(+), 22 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 178daf5f0..b37181e57 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -164,13 +164,14 @@ export class DocumentManager { const sameContext = annotatedDoc && annotatedDoc === originatingDoc?.context; if (originatingDoc?.isPushpin) { 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); + 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 + if (notfocused || docView.props.Document.hidden) { + docView.props.Document.hidden = !docView.props.Document.hidden; + } 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?.(); + //finished?.(); } else { docView.select(false); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 493018093..b282d1e27 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -103,7 +103,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: const { Document, DataDoc } = this.props; const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)). filter(pair => { // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys - return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && Object.keys(pair.layout.proto).length)); + return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length)); }); return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types } @@ -134,7 +134,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: rawdocs = rootDoc && !this.props.annotationsKey ? [Doc.GetProto(rootDoc)] : []; } - const docs = rawdocs.filter(d => !(d instanceof Promise) && Object.keys(d).length).map(d => d as Doc); + const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(d) !== AclPrivate).map(d => d as Doc); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; @@ -502,4 +502,5 @@ import { SelectionManager } from "../../util/SelectionManager"; import { OverlayView } from "../OverlayView"; import { setTimeout } from "timers"; import { Hypothesis } from "../../util/HypothesisUtils"; +import { GetEffectiveAcl } from "../../../fields/util"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 80e9b41ad..cfd24545b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -159,7 +159,8 @@ export class CollectionView extends Touchable [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 hasContextAnchor = DocListCast(doc.links).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context)); + if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { const pushpin = Docs.Create.FontIconDocument({ title: "pushpin", label: "", icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), _backgroundColor: "#0000003d", color: "#ACCEF7", diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4d9906f93..4df90e8ea 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -893,21 +893,24 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc.y)) { - scrollTo = NumCast(doc.y); + scrollTo = Math.max(0, NumCast(doc.y) - 50); } - if (curScroll !== scrollTo) { + if (curScroll !== scrollTo || this.props.Document._viewTransition) { this.props.Document._scrollPY = this.props.Document._scrollY = scrollTo; delay = Math.abs(scrollTo - curScroll) > 5 ? 1000 : 0; - !dontCenter && delay && this.props.focus(this.props.Document); + !dontCenter && this.props.focus(this.props.Document); afterFocus && setTimeout(afterFocus, delay); + } else { + !dontCenter && delay && this.props.focus(this.props.Document); // @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 + afterFocus(true); // bcz: TODO Aragh -- need to add a parameter to afterFocus() functions to indicate whether the focus function didn't need to scroll + + } } } else { @@ -929,14 +932,16 @@ export class CollectionFreeFormView extends CollectionSubView { - if (afterFocus?.()) { + // @ts-ignore + if (afterFocus?.(notFocused)) { // bcz: TODO Aragh -- need to add a parameter to afterFocus() functions to indicate whether the focus function didn't need to scroll this.Document._panX = savedState.px; this.Document._panY = savedState.py; this.Document[this.scaleFieldKey] = savedState.s; this.Document._viewTransition = savedState.pt; } - }, 500); + }, notFocused ? 0 : 500); } } diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 156256fe5..276c66bb1 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -8,11 +8,12 @@ import { FieldView, FieldViewProps } from './FieldView'; import { StrCast, Cast, ScriptCast } from '../../../fields/Types'; import { Utils, setupMoveUpEvents, returnFalse, emptyFunction } from "../../../Utils"; import { runInAction, observable, reaction, IReactionDisposer } from 'mobx'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, AclPrivate } from '../../../fields/Doc'; import { ContextMenu } from '../ContextMenu'; import { ScriptField } from '../../../fields/ScriptField'; import { Tooltip } from '@material-ui/core'; import { DragManager } from '../../util/DragManager'; +import { GetEffectiveAcl } from '../../../fields/util'; const FontIconSchema = createSchema({ icon: "string", }); @@ -105,7 +106,7 @@ export class FontIconBadge extends React.Component { render() { if (!(this.props.collection instanceof Doc)) return (null); - const length = DocListCast(this.props.collection.data).filter(d => Object.keys(d).length).length; // filter out any documents that we can't read + const length = DocListCast(this.props.collection.data).filter(d => GetEffectiveAcl(d) !== AclPrivate).length; // Object.keys(d).length).length; // filter out any documents that we can't read return
0 ? { "display": "initial" } : { "display": "none" }} onPointerDown={this.onPointerDown} > diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index e7f901091..a071abd21 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -71,6 +71,7 @@ class RegionAnnotation extends React.Component { this._reactionDisposer && this._reactionDisposer(); } + @undoBatch deleteAnnotation = () => { const annotation = DocListCast(this.props.dataDoc[this.props.fieldKey + "-annotations"]); const group = FieldValue(Cast(this.props.document.group, Doc)); @@ -86,6 +87,7 @@ class RegionAnnotation extends React.Component { PDFMenu.Instance.fadeOut(true); } + @undoBatch pinToPres = () => { const group = FieldValue(Cast(this.props.document.group, Doc)); const isPinned = group && Doc.isDocPinned(group) ? true : false; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 78b95b385..d8be3defd 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -194,7 +194,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent= 0) { - if (!this._mainCont.current) setTimeout(() => smoothScroll(1000, this._mainCont.current!, scrollY || 0)); + if (!this._mainCont.current) setTimeout(() => this._mainCont.current && smoothScroll(1000, this._mainCont.current, scrollY || 0)); else smoothScroll(1000, this._mainCont.current, scrollY || 0); this.Document._scrollPY = undefined; } diff --git a/src/fields/util.ts b/src/fields/util.ts index 881f301f3..b68d961b1 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -13,6 +13,7 @@ import { returnZero } from "../Utils"; import CursorField from "./CursorField"; import { List } from "./List"; import { SnappingManager } from "../client/util/SnappingManager"; +import { computedFn } from "mobx-utils"; function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); @@ -139,7 +140,7 @@ export function denormalizeEmail(email: string) { * * Edit: a user with edit access to a document can remove/edit that document, add/remove/edit annotations (depending on permissions), but not change any access rights to that document. * - * Add: a user with add access to a document can add documents/annotations to that document but cannot edit or delete anything. + * Add: a user with add access to a document can augment documents/annotations to that document but cannot edit or delete anything. * * View: a user with view access to a document can only view it - they cannot add/remove/edit anything. * @@ -148,7 +149,7 @@ export function denormalizeEmail(email: string) { export enum SharingPermissions { Admin = "Admin", Edit = "Can Edit", - Add = "Can Add", + Add = "Can Augment", View = "Can View", None = "Not Shared" } @@ -157,6 +158,11 @@ export enum SharingPermissions { * Calculates the effective access right to a document for the current user. */ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, user?: string): symbol { + return computedFn(function (target: any, in_prop?: string | symbol | number, user?: string) { + return getEffectiveAcl(target, in_prop, user); + }, true)(target, in_prop, user); +} +function getEffectiveAcl(target: any, in_prop?: string | symbol | number, user?: string): symbol { if (!target) return AclPrivate; // all changes received fromt the server must be processed as Admin @@ -219,7 +225,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc const HierarchyMapping = new Map([ ["Not Shared", 0], ["Can View", 1], - ["Can Add", 2], + ["Can Augment", 2], ["Can Edit", 3], ["Admin", 4] ]); @@ -281,7 +287,7 @@ export function setter(target: any, in_prop: string | symbol | number, value: an // if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't if (typeof prop === "string" && prop.startsWith("acl") && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined, "None"].includes(value))) return true; - // if (typeof prop === "string" && prop.startsWith("acl") && !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value)) return true; + // if (typeof prop === "string" && prop.startsWith("acl") && !["Can Edit", "Can Augment", "Can View", "Not Shared", undefined].includes(value)) return true; if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { if (!prop.startsWith("_")) { -- cgit v1.2.3-70-g09d2 From 9f6dba274539a78a541afd398c73a17dec996319 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 12 Oct 2020 01:34:00 -0400 Subject: capped zoom in at a factor of 20. fixed zoom in not to pan when it hits its zoom in limit. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4df90e8ea..71519f2b9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -783,10 +783,14 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? (1 / 1.05) : 1.05; if (deltaScale < 0) deltaScale = -deltaScale; const [x, y] = this.getTransform().transformPoint(pointX, pointY); + const invTransform = this.getLocalTransform().inverse(); + if (deltaScale * invTransform.Scale > 20) { + deltaScale = 20 / invTransform.Scale; + } const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y); if (localTransform.Scale >= 0.15 || localTransform.Scale > this.zoomScaling()) { - const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40); + const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 20); this.props.Document[this.scaleFieldKey] = Math.abs(safeScale); this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale); } -- cgit v1.2.3-70-g09d2