From 92bccbcd1cefca43807541858a7be58d8c3c53c7 Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Wed, 30 Sep 2020 22:47:12 -0600 Subject: fix 3DCarouselView mis-aligned slides --- .../views/collections/CollectionCarousel3DView.tsx | 318 ++++++++++----------- 1 file changed, 159 insertions(+), 159 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 4f1ef6e61..550a2f708 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -19,163 +19,163 @@ const Carousel3DDocument = makeInterface(documentSchema, collectionSchema); @observer export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocument) { - @computed get scrollSpeed() { - return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed - } - - private _dropDisposer?: DragManager.DragDropDisposer; - - componentWillUnmount() { this._dropDisposer?.(); } - - protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view - this._dropDisposer?.(); - if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); - } - } - - panelWidth = () => this.props.PanelWidth() / 3; - panelHeight = () => this.props.PanelHeight() * 0.6; - onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); - @computed get content() { - const currentIndex = NumCast(this.layoutDoc._itemIndex); - const displayDoc = (childPair: { layout: Doc, data: Doc }) => { - const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout }); - const onChildClick = script && (() => script); - return ; - }; - - return (this.childLayoutPairs.map((childPair, index) => { - return ( -
- {displayDoc(childPair)} -
); - })); - } - - changeSlide = (direction: number) => { - this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length; - } - - onArrowClick = (e: React.MouseEvent, direction: number) => { - e.stopPropagation(); - this.changeSlide(direction); - !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = (direction === 1) ? "fwd" : "back"); // while autoscroll is on, keep the other autoscroll button hidden - !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on - } - - interval?: number; - startAutoScroll = (direction: number) => { - this.interval = window.setInterval(() => { - this.changeSlide(direction); - }, this.scrollSpeed); - } - - stopAutoScroll = () => { - window.clearInterval(this.interval); - this.interval = undefined; - this.fadeScrollButton(); - } - - toggleAutoScroll = (direction: number) => { - this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true; - this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll(); - } - - fadeScrollButton = () => { - window.setTimeout(() => { - !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = "none"); //fade away after 1.5s if it's not clicked. - }, 1500); - } - - _downX = 0; - _downY = 0; - onPointerDown = (e: React.PointerEvent) => { - this._downX = e.clientX; - this._downY = e.clientY; - document.addEventListener("pointerup", this.onpointerup); - } - private _lastTap: number = 0; - private _doubleTap = false; - onpointerup = (e: PointerEvent) => { - this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); - this._lastTap = Date.now(); - } - - onClick = (e: React.MouseEvent) => { - if (this._doubleTap) { - e.stopPropagation(); - this.props.Document.isLightboxOpen = true; - } - } - - @computed get buttons() { - if (!this.props.active()) return null; - return
-
this.onArrowClick(e, -1)} - > - -
-
this.onArrowClick(e, 1)} - > - -
- {this.autoScrollButton} -
; - } - - @computed get autoScrollButton() { - const whichButton = this.layoutDoc.showScrollButton; - return <> -
this.toggleAutoScroll(-1)}> - {this.layoutDoc.autoScrollOn ? : } -
-
this.toggleAutoScroll(1)}> - {this.layoutDoc.autoScrollOn ? : } -
- ; - } - - @computed get dots() { - return (this.childLayoutPairs.map((_child, index) => { - return
this.layoutDoc._itemIndex = index} />; - })); - } - - render() { - const index = NumCast(this.layoutDoc._itemIndex); - const translateX = (1 - index) / this.childLayoutPairs.length * 100; - - return
-
- {this.content} -
- {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)} -
- {this.dots} -
-
; - } + @computed get scrollSpeed() { + return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed + } + + private _dropDisposer?: DragManager.DragDropDisposer; + + componentWillUnmount() { this._dropDisposer?.(); } + + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + this._dropDisposer?.(); + if (ele) { + this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); + } + } + + panelWidth = () => this.props.PanelWidth() / 3; + panelHeight = () => this.props.PanelHeight() * 0.6; + onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); + @computed get content() { + const currentIndex = NumCast(this.layoutDoc._itemIndex); + const displayDoc = (childPair: { layout: Doc, data: Doc }) => { + const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout }); + const onChildClick = script && (() => script); + return ; + }; + + return (this.childLayoutPairs.map((childPair, index) => { + return ( +
+ {displayDoc(childPair)} +
); + })); + } + + changeSlide = (direction: number) => { + this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length; + } + + onArrowClick = (e: React.MouseEvent, direction: number) => { + e.stopPropagation(); + this.changeSlide(direction); + !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = (direction === 1) ? "fwd" : "back"); // while autoscroll is on, keep the other autoscroll button hidden + !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on + } + + interval?: number; + startAutoScroll = (direction: number) => { + this.interval = window.setInterval(() => { + this.changeSlide(direction); + }, this.scrollSpeed); + } + + stopAutoScroll = () => { + window.clearInterval(this.interval); + this.interval = undefined; + this.fadeScrollButton(); + } + + toggleAutoScroll = (direction: number) => { + this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true; + this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll(); + } + + fadeScrollButton = () => { + window.setTimeout(() => { + !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = "none"); //fade away after 1.5s if it's not clicked. + }, 1500); + } + + _downX = 0; + _downY = 0; + onPointerDown = (e: React.PointerEvent) => { + this._downX = e.clientX; + this._downY = e.clientY; + document.addEventListener("pointerup", this.onpointerup); + } + private _lastTap: number = 0; + private _doubleTap = false; + onpointerup = (e: PointerEvent) => { + this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); + this._lastTap = Date.now(); + } + + onClick = (e: React.MouseEvent) => { + if (this._doubleTap) { + e.stopPropagation(); + this.props.Document.isLightboxOpen = true; + } + } + + @computed get buttons() { + if (!this.props.active()) return null; + return
+
this.onArrowClick(e, -1)} + > + +
+
this.onArrowClick(e, 1)} + > + +
+ {this.autoScrollButton} +
; + } + + @computed get autoScrollButton() { + const whichButton = this.layoutDoc.showScrollButton; + return <> +
this.toggleAutoScroll(-1)}> + {this.layoutDoc.autoScrollOn ? : } +
+
this.toggleAutoScroll(1)}> + {this.layoutDoc.autoScrollOn ? : } +
+ ; + } + + @computed get dots() { + return (this.childLayoutPairs.map((_child, index) => { + return
this.layoutDoc._itemIndex = index} />; + })); + } + + render() { + const index = NumCast(this.layoutDoc._itemIndex); + const translateX = 33 * (1 - index); + + return
+
+ {this.content} +
+ {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)} +
+ {this.dots} +
+
; + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 3c44131f75fe0c311363b36e824604c91f1babc8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 1 Oct 2020 11:15:41 -0400 Subject: fixed closed library flyout view to not render a DocumentView. fixed sidebar panels to not be selectable. fixed changing view of sidebar panel to only affect that panel --- src/client/util/CurrentUserUtils.ts | 14 ++--- src/client/util/SearchUtil.ts | 2 +- src/client/views/MainView.tsx | 69 +++++++++++++------------ src/client/views/collections/CollectionMenu.tsx | 3 +- 4 files changed, 46 insertions(+), 42 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 7cc35d67a..d45a2c90a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -566,7 +566,7 @@ export class CurrentUserUtils { title: "menuItemPanel", childDropAction: "alias", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - _backgroundColor: "black", + _backgroundColor: "black", ignoreClick: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled", system: true @@ -729,7 +729,7 @@ export class CurrentUserUtils { if (doc.myTools === undefined) { const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], { - title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true, _stayInCollection: true, _hideContextMenu: true, + title: "My Tools", _width: 500, _yMargin: 20, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true, _stayInCollection: true, _hideContextMenu: true, })) as any as Doc; doc.myTools = toolsStack; @@ -743,7 +743,7 @@ export class CurrentUserUtils { doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "My Dashboards", _height: 400, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, + treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true })); const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`); @@ -759,7 +759,7 @@ export class CurrentUserUtils { doc.myPresentations = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "My Presentations", _height: 100, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, + treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true })); const newPresentations = ScriptField.MakeScript(`createNewPresentation()`); @@ -777,7 +777,7 @@ export class CurrentUserUtils { doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "Recently Closed", _height: 500, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, + treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true })); const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); @@ -792,7 +792,7 @@ export class CurrentUserUtils { doc.myFilter = new PrefetchProxy(Docs.Create.FilterDocument({ title: "FilterDoc", _height: 500, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "none", - treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, + treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true })); const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`); @@ -808,7 +808,7 @@ export class CurrentUserUtils { doc.treeViewExpandedView = "fields"; doc.myUserDoc = new PrefetchProxy(Docs.Create.TreeDocument([doc], { treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, title: "My UserDoc", - treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, + treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true })) as any as Doc; } diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 08ad49dcc..79759a71d 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -44,7 +44,7 @@ export namespace SearchUtil { const header = query.match(/_[atnb]?:/) ? replacedQuery : "DEFAULT:" + replacedQuery; replacedQuery = `{!join from=id to=proto_i}* AND ${header}`; } - console.log("Q: " + replacedQuery + " fq: " + options.fq); + //console.log("Q: " + replacedQuery + " fq: " + options.fq); const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } }); const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten); if (!returnDocs) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5193c3c02..8e30eba2a 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -312,39 +312,40 @@ export class MainView extends React.Component { } @computed get flyout() { - return
-
- "lightgrey"} - /> -
- {this.docButtons} -
; + return !this._flyoutWidth ?
: +
+
+ "lightgrey"} + /> +
+ {this.docButtons} +
; } @computed get menuPanel() { @@ -394,6 +395,8 @@ export class MainView extends React.Component { SearchBox.Instance._searchFullDB = "My Stuff"; SearchBox.Instance.enter(undefined); break; + case "Help": + break; default: this.expandFlyout(button); } diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 51d1d5559..e9cb57fed 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -234,8 +234,9 @@ export class CollectionViewBaseChrome extends React.Component { + const target = this.document !== Doc.UserDoc().sidebar ? this.document : this.document.proto as Doc; //@ts-ignore - this.document._viewType = e.target.selectedOptions[0].value; + target._viewType = e.target.selectedOptions[0].value; } commandChanged = (e: React.ChangeEvent) => { -- cgit v1.2.3-70-g09d2 From e7a6895ed4da4760c5e13c02eb08aaf7f0ffdb74 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 1 Oct 2020 11:25:59 -0400 Subject: fixed tabs in carousel 3D view --- .../views/collections/CollectionCarousel3DView.tsx | 318 ++++++++++----------- 1 file changed, 159 insertions(+), 159 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 550a2f708..4e30709a6 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -19,163 +19,163 @@ const Carousel3DDocument = makeInterface(documentSchema, collectionSchema); @observer export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocument) { - @computed get scrollSpeed() { - return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed - } - - private _dropDisposer?: DragManager.DragDropDisposer; - - componentWillUnmount() { this._dropDisposer?.(); } - - protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view - this._dropDisposer?.(); - if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); - } - } - - panelWidth = () => this.props.PanelWidth() / 3; - panelHeight = () => this.props.PanelHeight() * 0.6; - onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); - @computed get content() { - const currentIndex = NumCast(this.layoutDoc._itemIndex); - const displayDoc = (childPair: { layout: Doc, data: Doc }) => { - const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout }); - const onChildClick = script && (() => script); - return ; - }; - - return (this.childLayoutPairs.map((childPair, index) => { - return ( -
- {displayDoc(childPair)} -
); - })); - } - - changeSlide = (direction: number) => { - this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length; - } - - onArrowClick = (e: React.MouseEvent, direction: number) => { - e.stopPropagation(); - this.changeSlide(direction); - !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = (direction === 1) ? "fwd" : "back"); // while autoscroll is on, keep the other autoscroll button hidden - !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on - } - - interval?: number; - startAutoScroll = (direction: number) => { - this.interval = window.setInterval(() => { - this.changeSlide(direction); - }, this.scrollSpeed); - } - - stopAutoScroll = () => { - window.clearInterval(this.interval); - this.interval = undefined; - this.fadeScrollButton(); - } - - toggleAutoScroll = (direction: number) => { - this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true; - this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll(); - } - - fadeScrollButton = () => { - window.setTimeout(() => { - !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = "none"); //fade away after 1.5s if it's not clicked. - }, 1500); - } - - _downX = 0; - _downY = 0; - onPointerDown = (e: React.PointerEvent) => { - this._downX = e.clientX; - this._downY = e.clientY; - document.addEventListener("pointerup", this.onpointerup); - } - private _lastTap: number = 0; - private _doubleTap = false; - onpointerup = (e: PointerEvent) => { - this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); - this._lastTap = Date.now(); - } - - onClick = (e: React.MouseEvent) => { - if (this._doubleTap) { - e.stopPropagation(); - this.props.Document.isLightboxOpen = true; - } - } - - @computed get buttons() { - if (!this.props.active()) return null; - return
-
this.onArrowClick(e, -1)} - > - -
-
this.onArrowClick(e, 1)} - > - -
- {this.autoScrollButton} -
; - } - - @computed get autoScrollButton() { - const whichButton = this.layoutDoc.showScrollButton; - return <> -
this.toggleAutoScroll(-1)}> - {this.layoutDoc.autoScrollOn ? : } -
-
this.toggleAutoScroll(1)}> - {this.layoutDoc.autoScrollOn ? : } -
- ; - } - - @computed get dots() { - return (this.childLayoutPairs.map((_child, index) => { - return
this.layoutDoc._itemIndex = index} />; - })); - } - - render() { - const index = NumCast(this.layoutDoc._itemIndex); - const translateX = 33 * (1 - index); - - return
-
- {this.content} -
- {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)} -
- {this.dots} -
-
; - } + @computed get scrollSpeed() { + return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed + } + + private _dropDisposer?: DragManager.DragDropDisposer; + + componentWillUnmount() { this._dropDisposer?.(); } + + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + this._dropDisposer?.(); + if (ele) { + this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); + } + } + + panelWidth = () => this.props.PanelWidth() / 3; + panelHeight = () => this.props.PanelHeight() * 0.6; + onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); + @computed get content() { + const currentIndex = NumCast(this.layoutDoc._itemIndex); + const displayDoc = (childPair: { layout: Doc, data: Doc }) => { + const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout }); + const onChildClick = script && (() => script); + return ; + }; + + return (this.childLayoutPairs.map((childPair, index) => { + return ( +
+ {displayDoc(childPair)} +
); + })); + } + + changeSlide = (direction: number) => { + this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length; + } + + onArrowClick = (e: React.MouseEvent, direction: number) => { + e.stopPropagation(); + this.changeSlide(direction); + !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = (direction === 1) ? "fwd" : "back"); // while autoscroll is on, keep the other autoscroll button hidden + !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on + } + + interval?: number; + startAutoScroll = (direction: number) => { + this.interval = window.setInterval(() => { + this.changeSlide(direction); + }, this.scrollSpeed); + } + + stopAutoScroll = () => { + window.clearInterval(this.interval); + this.interval = undefined; + this.fadeScrollButton(); + } + + toggleAutoScroll = (direction: number) => { + this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true; + this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll(); + } + + fadeScrollButton = () => { + window.setTimeout(() => { + !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = "none"); //fade away after 1.5s if it's not clicked. + }, 1500); + } + + _downX = 0; + _downY = 0; + onPointerDown = (e: React.PointerEvent) => { + this._downX = e.clientX; + this._downY = e.clientY; + document.addEventListener("pointerup", this.onpointerup); + } + private _lastTap: number = 0; + private _doubleTap = false; + onpointerup = (e: PointerEvent) => { + this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); + this._lastTap = Date.now(); + } + + onClick = (e: React.MouseEvent) => { + if (this._doubleTap) { + e.stopPropagation(); + this.props.Document.isLightboxOpen = true; + } + } + + @computed get buttons() { + if (!this.props.active()) return null; + return
+
this.onArrowClick(e, -1)} + > + +
+
this.onArrowClick(e, 1)} + > + +
+ {this.autoScrollButton} +
; + } + + @computed get autoScrollButton() { + const whichButton = this.layoutDoc.showScrollButton; + return <> +
this.toggleAutoScroll(-1)}> + {this.layoutDoc.autoScrollOn ? : } +
+
this.toggleAutoScroll(1)}> + {this.layoutDoc.autoScrollOn ? : } +
+ ; + } + + @computed get dots() { + return (this.childLayoutPairs.map((_child, index) => { + return
this.layoutDoc._itemIndex = index} />; + })); + } + + render() { + const index = NumCast(this.layoutDoc._itemIndex); + const translateX = 33 * (1 - index); + + return
+
+ {this.content} +
+ {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)} +
+ {this.dots} +
+
; + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 3c7f85dbcddca0ffacd82c2d39e88bba8c4b3f3a Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 1 Oct 2020 23:04:31 -0400 Subject: various fixes to new sharing / email normalization --- src/client/documents/Documents.ts | 12 ++++----- src/client/util/CurrentUserUtils.ts | 9 ++++--- src/client/util/GroupManager.tsx | 2 +- src/client/util/SharingManager.tsx | 31 +++++++++++----------- src/client/views/DocComponent.tsx | 4 +-- src/client/views/PropertiesView.tsx | 11 ++------ src/client/views/collections/CollectionMenu.tsx | 4 +-- src/client/views/collections/CollectionView.tsx | 4 +-- .../views/nodes/formattedText/RichTextRules.ts | 8 +++--- 9 files changed, 40 insertions(+), 45 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 47fa7067d..7ee8267f8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -574,7 +574,7 @@ export namespace Docs { * only when creating a DockDocument from the current user's already existing * main document. */ - export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data") { + export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data", protoId?: string) { const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys, "^_"); protoProps.system = delegateProps.system; @@ -590,7 +590,7 @@ export namespace Docs { protoProps.isPrototype = true; - const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey); + const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey, protoId); const viewDoc = Doc.MakeDelegate(dataDoc, delegId); // so that the list of annotations is already initialised, prevents issues in addonly. @@ -620,8 +620,8 @@ export namespace Docs { * @param options initial values to apply to this new delegate * @param value the data to store in this new delegate */ - function MakeDataDelegate(proto: Doc, options: DocumentOptions, value?: D, fieldKey: string = "data") { - const deleg = Doc.MakeDelegate(proto); + function MakeDataDelegate(proto: Doc, options: DocumentOptions, value?: D, fieldKey: string = "data", id: string | undefined = undefined) { + const deleg = Doc.MakeDelegate(proto, id); if (value !== undefined) { deleg[fieldKey] = value; } @@ -807,8 +807,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", dontRegisterChildViews: true, ...options, _viewType: CollectionViewType.Tree }, id); } - export function StackingDocument(documents: Array, options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Stacking }, id); + export function StackingDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Stacking }, id, undefined, protoId); } export function MulticolumnDocument(documents: Array, options: DocumentOptions) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cff07d48e..ec550c15a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -30,6 +30,7 @@ import { Scripting } from "./Scripting"; import { SearchUtil } from "./SearchUtil"; import { SelectionManager } from "./SelectionManager"; import { UndoManager } from "./UndoManager"; +import { SharingPermissions } from "../../fields/util"; const headerViewVersion = "0.1"; @@ -874,11 +875,13 @@ export class CurrentUserUtils { // Sharing sidebar is where shared documents are contained static async setupSharingSidebar(doc: Doc, sharingDocumentId: string) { if (doc.mySharedDocs === undefined) { - let sharedDocs = await DocServer.GetRefField(sharingDocumentId); + let sharedDocs = await DocServer.GetRefField(sharingDocumentId + "outer"); if (!sharedDocs) { sharedDocs = Docs.Create.StackingDocument([], { - title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, _showTitle: "title", ignoreClick: true, lockedPosition: true - }, sharingDocumentId); + title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, + _showTitle: "title", ignoreClick: true, lockedPosition: true, + }, sharingDocumentId + "outer", sharingDocumentId); + (sharedDocs as Doc)["acl-Public"] = Doc.GetProto(sharedDocs as Doc)["acl-Public"] = SharingPermissions.Add; } if (sharedDocs instanceof Doc) { sharedDocs.userColor = sharedDocs.userColor || "#12121233"; diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 70ea48ab8..e81c95d83 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -66,7 +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.mySharedDocs, Doc, null); + const notificationDoc = await Cast(userSharingDocument.data, Doc, null); runInAction(() => notificationDoc && this.users.push(user.email)); } }); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 0cf6cc87c..c67ec2db5 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -47,7 +47,7 @@ const groupType = "!groupType/"; const storage = "data"; /** - * A user who also has a notificationDoc. + * A user who also has a sharing doc. */ interface ValidatedUser { user: User; // database minimal info to identify / communicate with a user (email, sharing doc id) @@ -59,7 +59,7 @@ interface ValidatedUser { export class SharingManager extends React.Component<{}> { public static Instance: SharingManager; @observable private isOpen = false; // whether the SharingManager modal is open or not - @observable public users: ValidatedUser[] = []; // the list of users with notificationDocs + @observable public users: ValidatedUser[] = []; // the list of users with sharing docs @observable private targetDoc: Doc | undefined; // the document being shared @observable private targetDocView: DocumentView | undefined; // the DocumentView of the document being shared // @observable private copied = false; @@ -163,9 +163,9 @@ export class SharingManager extends React.Component<{}> { // if documents have been shared, add the doc to that list if it doesn't already exist, otherwise create a new list with the doc group.docsShared ? Doc.IndexOf(doc, DocListCast(group.docsShared)) === -1 && (group.docsShared as List).push(doc) : group.docsShared = new List([doc]); - users.forEach(({ user, sharingDoc: notificationDoc }) => { - if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); // add the doc to the notificationDoc if it hasn't already been added - else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists + users.forEach(({ user, sharingDoc }) => { + if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(sharingDoc[storage])) === -1 && Doc.AddDocToList(sharingDoc, storage, doc); // add the doc to the sharingDoc if it hasn't already been added + else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(sharingDoc[storage])) !== -1 && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists }); } }); @@ -228,7 +228,7 @@ export class SharingManager extends React.Component<{}> { const members: string[] = JSON.parse(StrCast(group.members)); const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); - users.forEach(({ sharingDoc: notificationDoc }) => Doc.RemoveDocFromList(notificationDoc, storage, doc)); + users.forEach(({ sharingDoc }) => Doc.RemoveDocFromList(sharingDoc, storage, doc)); }); } } @@ -237,19 +237,18 @@ export class SharingManager extends React.Component<{}> { * Shares the document with a user. */ setInternalSharing = (recipient: ValidatedUser, permission: string, targetDoc?: Doc) => { - const { user, sharingDoc: notificationDoc } = recipient; + const { user, sharingDoc } = recipient; const target = targetDoc || this.targetDoc!; - const key = normalizeEmail(user.email); - const acl = `acl-${key}`; + const acl = `acl-${normalizeEmail(user.email)}`; + const myAcl = `acl-${Doc.CurrentUserEmailNormalized}`; const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document); - docs.forEach(doc => { - doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc); + doc.author === Doc.CurrentUserEmail && !doc[myAcl] && distributeAcls(myAcl, SharingPermissions.Admin, doc); distributeAcls(acl, permission as SharingPermissions, doc); - if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); - else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc)); + if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(sharingDoc[storage])) === -1 && Doc.AddDocToList(sharingDoc, storage, doc); + else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(sharingDoc[storage])) !== -1 && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc)); }); } @@ -449,7 +448,7 @@ export class SharingManager extends React.Component<{}> { const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym]?.[AclSym] && Object.keys(doc[DataSym][AclSym]))); // the list of users shared with - const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email).map(({ user, sharingDoc: notificationDoc, userColor }) => { + const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email).map(({ user, sharingDoc, userColor }) => { const userKey = `acl-${normalizeEmail(user.email)}`; const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey]); const permissions = uniform ? StrCast(targetDoc?.[userKey]) : "-multiple-"; @@ -465,7 +464,7 @@ export class SharingManager extends React.Component<{}> { @@ -516,7 +515,7 @@ export class SharingManager extends React.Component<{}> { // the list of groups shared with - const groupListMap: (Doc | { groupName: string })[] = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`acl-${StrCast(groupName).replace('.', '_')}`) : true); + const groupListMap: (Doc | { groupName: string })[] = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(StrCast(groupName))}`) : true); groupListMap.unshift({ groupName: "Public" }, { groupName: "Override" }); const groupListContents = groupListMap.map(group => { const groupKey = `acl-${StrCast(group.groupName)}`; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 893b74d75..b3fbe418b 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -7,7 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { List } from '../../fields/List'; import { DateField } from '../../fields/DateField'; import { ScriptField } from '../../fields/ScriptField'; -import { GetEffectiveAcl, SharingPermissions, distributeAcls } from '../../fields/util'; +import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail } from '../../fields/util'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) @@ -166,7 +166,7 @@ export function ViewBoxAnnotatableComponent

{ for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - if (d.author === key.substring(4).replace("_", ".") && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); + if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true); // else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index b30691ff5..f3241e8d9 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -10,7 +10,7 @@ import { Id } from "../../fields/FieldSymbols"; import { InkField } from "../../fields/InkField"; import { ComputedField } from "../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../fields/Types"; -import { GetEffectiveAcl, SharingPermissions } from "../../fields/util"; +import { GetEffectiveAcl, SharingPermissions, denormalizeEmail } from "../../fields/util"; import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne } from "../../Utils"; import { DocumentType } from "../documents/DocumentTypes"; import { DocumentManager } from "../util/DocumentManager"; @@ -409,7 +409,7 @@ export class PropertiesView extends React.Component { // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => { if (commonKeys.length) { for (const key of commonKeys) { - const name = key.substring(4).replace("_", "."); + const name = denormalizeEmail(key.substring(4)); const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key] : doc?.[DataSym]?.[AclSym]?.[key] === docs[0]?.[DataSym]?.[AclSym]?.[key]); if (name !== Doc.CurrentUserEmail && name !== target.author && name !== "Public" && name !== "Override"/* && sidebarUsersDisplayed![name] !== false*/) { tableEntries.push(this.sharingItem(name, showAdmin, uniform ? AclMap.get(this.layoutDocAcls ? target[AclSym][key] : target[DataSym][AclSym][key])! : "-multiple-")); @@ -417,13 +417,6 @@ export class PropertiesView extends React.Component { } } - // if (Doc.UserDoc().sidebarUsersDisplayed) { - // for (const [name, value] of Object.entries(sidebarUsersDisplayed!)) { - // if (value === true && !this.selectedDoc![`acl-${name.substring(8).replace(".", "_")}`]) tableEntries.push(this.sharingItem(name.substring(8), effectiveAcl, SharingPermissions.None)); - // } - // } - // }) - const ownerSame = Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author); // shifts the current user, owner, public to the top of the doc. tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-")); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index e9cb57fed..09ff3bb0c 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -894,14 +894,14 @@ export class CollectionStackingViewChrome extends React.Component key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || - (key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "acl" && key[0] !== "_")); + (key[0].toUpperCase() === key[0] && key[0] !== "_")); return keys.filter(key => key.toLowerCase().indexOf(val) > -1); } else { const keys = new Set(); docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || - (key[0]?.toUpperCase() === key[0] && key.substring(0, 3) !== "acl" && key[0] !== "_")); + (key[0]?.toUpperCase() === key[0] && key[0] !== "_")); return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 522f46280..2bdc8e2f3 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -10,7 +10,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; +import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx, normalizeEmail, denormalizeEmail } from '../../../fields/util'; import { returnFalse, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -143,7 +143,7 @@ export class CollectionView extends Touchable { for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - if (d.author === key.substring(4).replace("_", ".") && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); + if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true); //else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); } diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 921c0e128..72b91c955 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -3,7 +3,8 @@ import { NodeSelection, TextSelection } from "prosemirror-state"; import { DataSym, Doc } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { ComputedField } from "../../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../../fields/Types"; +import { NumCast, StrCast } from "../../../../fields/Types"; +import { normalizeEmail } from "../../../../fields/util"; import { returnFalse, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -11,7 +12,6 @@ import { FormattedTextBox } from "./FormattedTextBox"; import { wrappingInputRule } from "./prosemirrorPatches"; import { RichTextMenu } from "./RichTextMenu"; import { schema } from "./schema_rts"; -import { List } from "../../../../fields/List"; export class RichTextRules { public Document: Doc; @@ -271,7 +271,7 @@ export class RichTextRules { (state, match, start, end) => { const fieldKey = match[1]; const rawdocid = match[3]?.substring(1); - const docid = rawdocid ? (!rawdocid.includes("@") ? Doc.CurrentUserEmail + "@" + rawdocid : rawdocid).replace(".", "_") : undefined; + const docid = rawdocid ? (!rawdocid.includes("@") ? normalizeEmail(Doc.CurrentUserEmail) + "@" + rawdocid : rawdocid) : undefined; const value = match[2]?.substring(1); if (!fieldKey) { const linkId = Utils.GenerateGuid(); @@ -304,7 +304,7 @@ export class RichTextRules { const fieldKey = match[1] || ""; const fieldParam = match[2]?.replace("…", "...") || ""; const rawdocid = match[3]?.substring(1); - const docid = rawdocid ? (!rawdocid.includes("@") ? Doc.CurrentUserEmail + "@" + rawdocid : rawdocid).replace(".", "_") : undefined; + const docid = rawdocid ? (!rawdocid.includes("@") ? normalizeEmail(Doc.CurrentUserEmail) + "@" + rawdocid : rawdocid) : undefined; if (!fieldKey && !docid) return state.tr; docid && DocServer.GetRefField(docid).then(docx => { if (!(docx instanceof Doc && docx)) { -- cgit v1.2.3-70-g09d2 From 1dee63242684f02543cf7667b53baa00d10ab6c1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 2 Oct 2020 00:34:30 -0400 Subject: fixed email (de)normalization. fixed sharing to hide objects whose permissions have been revoked --- src/client/views/collections/CollectionSubView.tsx | 7 +++++-- src/client/views/nodes/FontIconBox.tsx | 2 +- src/fields/util.ts | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 649b8c175..fa80c8062 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,6 +1,6 @@ import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx"; import CursorField from "../../../fields/CursorField"; -import { Doc, Opt, Field, DocListCast } from "../../../fields/Doc"; +import { Doc, Opt, Field, DocListCast, AclPrivate } from "../../../fields/Doc"; import { Id, ToString } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; @@ -101,7 +101,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: get childLayoutPairs(): { layout: Doc; data: Doc; }[] { const { Document, DataDoc } = this.props; - const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout); + 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 validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types } get childDocList() { diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 6e96513c7..156256fe5 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -105,7 +105,7 @@ export class FontIconBadge extends React.Component { render() { if (!(this.props.collection instanceof Doc)) return (null); - const length = DocListCast(this.props.collection.data).length; + const length = DocListCast(this.props.collection.data).filter(d => 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/fields/util.ts b/src/fields/util.ts index 6c92aef81..4da9fce74 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -117,10 +117,10 @@ export function OVERRIDE_acl(val: boolean) { } export function normalizeEmail(email: string) { - return email.replace('.', '__'); + return email.replace(/\./g, '__'); } export function denormalizeEmail(email: string) { - return email.replace('__', '.'); + return email.replace(/__/g, '.'); } // playground mode allows the user to add/delete documents or make layout changes without them saving to the server -- cgit v1.2.3-70-g09d2