From 7278aaa71a13f57cdc371bd771f5fcc6419707b7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 26 Aug 2022 13:25:23 -0400 Subject: added x,y,w,h view pinning for all documents. --- src/client/views/DocumentButtonBar.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 40fc8dae6..76e2d64a2 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -26,6 +26,7 @@ import { DashFieldView } from './nodes/formattedText/DashFieldView'; import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { TemplateMenu } from './TemplateMenu'; import React = require('react'); +import { DocumentType } from '../documents/DocumentTypes'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -243,7 +244,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinDocView: true, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinDocView: !docs.some(doc => !e.shiftKey && doc.type === DocumentType.RTF), activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); }}> -- cgit v1.2.3-70-g09d2 From 72e59f37670c01d69b4570baff529f741730bf80 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Sep 2022 11:59:32 -0400 Subject: fixed border highlight for animation effects. require shift-key for all pinWithView operations --- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 24 ++++++++++++++---------- src/client/views/nodes/trails/PresBox.tsx | 27 ++++++++++++--------------- 3 files changed, 27 insertions(+), 26 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 76e2d64a2..d49c4c6c0 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -244,7 +244,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinDocView: !docs.some(doc => !e.shiftKey && doc.type === DocumentType.RTF), activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinDocView: e.shiftKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); }}> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cab0e744f..2966c2a22 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1321,7 +1321,7 @@ export class DocumentViewInternal extends DocComponent { TraceMobx(); const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); const isButton = this.props.Document.type === DocumentType.FONTICON; @@ -1343,6 +1343,7 @@ export class DocumentViewInternal extends DocComponent ) ); - } + }; render() { TraceMobx(); const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : Doc.DocBrushStatus.unbrushed) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString @@ -1369,13 +1370,20 @@ export class DocumentViewInternal extends DocComponent {!borderPath.path ? ( - internal + animRenderDoc ) : ( <> {/*
- {internal} + {animRenderDoc}
*/} - {internal} + {animRenderDoc}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 5bede448d..048a033ee 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -5,7 +5,7 @@ import { action, computed, IReactionDisposer, observable, ObservableSet, reactio import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; -import { Doc, DocListCast, DocListCastAsync, FieldResult } from '../../../../fields/Doc'; +import { Doc, DocListCast, DocListCastAsync, FieldResult, Opt } from '../../../../fields/Doc'; import { Copy } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; @@ -54,22 +54,21 @@ export class PresBox extends ViewBoxBaseComponent() { } /** - * transitions & effects for documents - * @param renderDoc - * @param layoutDoc + * returns an entrance animation effect function to wrap a JSX element + * @param presEffectDoc presentation effects document that specifies the animation effect parameters + * @returns a function that will wrap a JSX animation element wrapping any JSX element */ - static renderEffectsDoc(renderDoc: any, layoutDoc: Doc, presDoc: Doc) { + public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc) { const effectProps = { - left: presDoc.presEffectDirection === PresEffect.Left, - right: presDoc.presEffectDirection === PresEffect.Right, - top: presDoc.presEffectDirection === PresEffect.Top, - bottom: presDoc.presEffectDirection === PresEffect.Bottom, + left: presEffectDoc.presEffectDirection === PresEffect.Left, + right: presEffectDoc.presEffectDirection === PresEffect.Right, + top: presEffectDoc.presEffectDirection === PresEffect.Top, + bottom: presEffectDoc.presEffectDirection === PresEffect.Bottom, opposite: true, - delay: presDoc.presTransition, - // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, + delay: NumCast(presEffectDoc.presTransition), }; //prettier-ignore - switch (presDoc.presEffect) { + switch (StrCast(presEffectDoc.presEffect)) { default: case PresEffect.None: return renderDoc; case PresEffect.Zoom: return {renderDoc}; @@ -81,9 +80,6 @@ export class PresBox extends ViewBoxBaseComponent() { case PresEffect.Lightspeed: return {renderDoc}; } } - public static EffectsProvider(layoutDoc: Doc, renderDoc: any) { - return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc; - } private _disposers: { [name: string]: IReactionDisposer } = {}; public selectedArray = new ObservableSet(); @@ -150,6 +146,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } + isActiveItemTarget = (layoutDoc: Doc) => this.activeItem.presentationTargetDoc === layoutDoc; clearSelectedArray = () => this.selectedArray.clear(); addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc); removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc); -- cgit v1.2.3-70-g09d2 From 66829e2d9fc08688f32f48ac92e2531fd4650cb7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 20 Sep 2022 14:35:29 -0400 Subject: fixed golden layout to always leave a stack when removing splits. --- .prettierignore | 3 ++- src/client/goldenLayout.js | 35 ++++++++++++++++++++++++++-------- src/client/views/DocumentButtonBar.tsx | 2 +- 3 files changed, 30 insertions(+), 10 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/.prettierignore b/.prettierignore index a6372b8eb..5c852fcd1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ -src/client/util/CurrentUserUtils.ts \ No newline at end of file +src/client/util/CurrentUserUtils.ts +src/client/goldenLayout.js \ No newline at end of file diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index 012ee163c..e5cd50de2 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -3264,7 +3264,6 @@ if (canDelete) { rowOrCol.removeChild(stack); if (rowOrCol.contentItems.length === 1 && parRowOrCol.contentItems.length === 1 && !parRowOrCol.isRoot) { - saveScrollTops(rowOrCol.contentItems[0].element); parRowOrCol.replaceChild(rowOrCol, rowOrCol.contentItems[0]); restoreScrollTops(rowOrCol.contentItems[0].element); @@ -4724,15 +4723,35 @@ */ } else { type = isVertical ? 'column' : 'row'; - rowOrColumn = this.layoutManager.createContentItem({ type: type }, this); - this.parent.replaceChild(this, rowOrColumn); + if (this.parent.contentItems.length === 1) { + let grandparent = this.parent.parent; + let correctRowOrCol = this.layoutManager.createContentItem({ type: type }, this); + grandparent.replaceChild(this.parent, correctRowOrCol); + correctRowOrCol.addChild(contentItem, 0, true); + let newstack = this.contentItems[0]; + if (newstack.isComponent) { + newstack = this.layoutManager.createContentItem({ + type: 'stack', + header: contentItem.config.header || {} + }, this); + newstack._$init(); + newstack.addChild(this.contentItems[0]); + } + correctRowOrCol.addChild(newstack, insertBefore ? 0 : undefined, true); + newstack.config[dimension] = 50; + contentItem.config[dimension] = 50; + correctRowOrCol.callDownwards('setSize'); + } else { + rowOrColumn = this.layoutManager.createContentItem({ type: type }, this); + this.parent.replaceChild(this, rowOrColumn); - rowOrColumn.addChild(contentItem, insertBefore ? 0 : undefined, true); - rowOrColumn.addChild(this, insertBefore ? undefined : 0, true); + rowOrColumn.addChild(contentItem, insertBefore ? 0 : undefined, true); + rowOrColumn.addChild(this, insertBefore ? undefined : 0, true); - this.config[dimension] = 50; - contentItem.config[dimension] = 50; - rowOrColumn.callDownwards('setSize'); + this.config[dimension] = 50; + contentItem.config[dimension] = 50; + rowOrColumn.callDownwards('setSize'); + } } }, diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index d49c4c6c0..35c0b9a7d 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -235,7 +235,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get pinButton() { const targetDoc = this.view0?.props.Document; return !targetDoc ? null : ( - {SelectionManager.Views().length > 1 ? 'Pin multiple documents to presentation' : 'Pin to presentation'}
}> + {SelectionManager.Views().length > 1 ? 'Pin multiple documents to trail (use shift to pin with view)' : 'Pin to trail (use shift to pin with view)'}}>
Date: Wed, 21 Sep 2022 01:43:03 -0400 Subject: restyled document decorations and changed novice mode to exclude `data` in treeView --- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.scss | 189 ++++++++++++++------- src/client/views/DocumentDecorations.tsx | 13 +- src/client/views/_nodeModuleOverrides.scss | 4 +- .../views/collections/CollectionDockingView.scss | 8 + .../views/collections/CollectionTreeView.scss | 1 + src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.scss | 20 ++- src/client/views/collections/TreeView.tsx | 4 +- src/client/views/global/globalCssVariables.scss | 4 + src/client/views/nodes/button/FontIconBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 16 +- src/client/views/topbar/TopBar.tsx | 2 +- 13 files changed, 178 insertions(+), 91 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 35c0b9a7d..0bfe6e87a 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -434,7 +434,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
) : null} -
{this.recordButton}
+ {Doc.noviceMode ? null :
{this.recordButton}
} { Doc.noviceMode ? null :
{this.templateButton}
/*
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index b490278c3..2e8d31478 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -22,6 +22,129 @@ $resizeHandler: 8px; grid-template-columns: $resizeHandler 1fr $resizeHandler; pointer-events: none; + .documentDecorations-topbar { + display: flex; + grid-column-start: 1; + grid-column-end: 4; + flex-direction: row; + gap: 2px; + + + .documentDecorations-openButton { + display: flex; + align-items: center; + justify-content: center; + background: #3ce312; + border: solid 1.5px #0a620a; + color: #3ce312; + transition: 0.1s ease; + font-size: 11px; + opacity: 1; + pointer-events: all; + width: 20px; + height: 20px; + min-width: 20px; + border-radius: 100%; + cursor: pointer; + + &:hover { + color: #02600d; + } + } + + .documentDecorations-closeButton { + display: flex; + align-items: center; + justify-content: center; + background: #fb9d75; + border: solid 1.5px #a94442; + color: #fb9d75; + transition: 0.1s ease; + opacity: 1; + pointer-events: all; + width: 20px; + height: 20px; + min-width: 20px; + border-radius: 100%; + cursor: pointer; + + &:hover { + color: #a94442; + } + + > svg { + margin: 0; + } + } + + .documentDecorations-minimizeButton { + display: flex; + align-items: center; + justify-content: center; + background: #ffdd00; + border: solid 1.5px #a94442; + color: #ffdd00; + transition: 0.1s ease; + font-size: 11px; + opacity: 1; + grid-column: 2; + pointer-events: all; + width: 20px; + height: 20px; + min-width: 20px; + border-radius: 100%; + cursor: pointer; + + &:hover { + color: #a94442; + } + + > svg { + margin: 0; + } + } + + .documentDecorations-title-Dark, + .documentDecorations-title { + opacity: 1; + width: calc(100% - 60px); // = margin-left + margin-right + grid-column: 3; + pointer-events: auto; + overflow: hidden; + text-align: center; + display: flex; + height: 20px; + border-radius: 8px; + outline: none; + border: none; + + .documentDecorations-titleSpan, + .documentDecorations-titleSpan-Dark { + width: 100%; + border-radius: 8px; + background: $light-gray; + display: inline-block; + cursor: move; + } + .documentDecorations-titleSpan-Dark { + background: hsla(0, 0%, 0%, 0.412); + } + } + + .documentDecorations-title-Dark { + color: white; + background: black; + } + + .documentDecorations-titleBackground { + background: $light-gray; + border-radius: 8px; + width: 100%; + height: 100%; + position: absolute; + } + } + .documentDecorations-centerCont { grid-column: 2; background: none; @@ -225,76 +348,12 @@ $resizeHandler: 8px; cursor: ew-resize; } - .documentDecorations-title-Dark, - .documentDecorations-title { - opacity: 1; - width: calc(100% - 8px); // = margin-left + margin-right - grid-column: 2; - grid-column-end: 2; - pointer-events: auto; - overflow: hidden; - text-align: center; - display: flex; - margin-left: 6px; // closeButton width (14) - leftColumn width (8) - margin-right: 2px; - height: 20px; - position: absolute; - border-radius: 8px; - background: rgba(159, 159, 159, 0.1); - - .documentDecorations-titleSpan, - .documentDecorations-titleSpan-Dark { - width: 100%; - border-radius: 8px; - background: #ffffffa0; - position: absolute; - display: inline-block; - cursor: move; - } - .documentDecorations-titleSpan-Dark { - background: hsla(0, 0%, 0%, 0.412); - } - } - .documentDecorations-title-Dark { - color: white; - background: black; - } - - .documentDecorations-titleBackground { - background: #ffffffcf; - border-radius: 8px; - width: 100%; - height: 100%; - position: absolute; - } - .focus-visible { margin-left: 0px; } } -.documentDecorations-openButton { - display: flex; - align-items: center; - opacity: 1; - grid-column-start: 3; - pointer-events: all; - cursor: pointer; -} -.documentDecorations-closeButton { - display: flex; - align-items: center; - opacity: 1; - grid-column: 1; - pointer-events: all; - width: 14px; - cursor: pointer; - - > svg { - margin: 0; - } -} .documentDecorations-background { background: lightblue; @@ -329,7 +388,7 @@ $resizeHandler: 8px; justify-content: center; align-items: center; gap: 5px; - background: $medium-gray; + background: $light-gray; } .linkButtonWrapper { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 0fc33bdea..95025bf70 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -719,9 +719,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P width: bounds.r - bounds.x + this._resizeBorderWidth + 'px', height: bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + 'px', }}> - {hideDeleteButton ?
: topBtn('close', this.hasIcons ? 'times' : 'window-maximize', undefined, e => this.onCloseClick(this.hasIcons ? true : undefined), 'Close')} - {titleArea} - {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Tab (ctrl: as alias, shift: in new collection)')} +
+ {hideDeleteButton ?
: topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} + {hideDeleteButton ?
: topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} + {titleArea} + {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Tab (ctrl: as alias, shift: in new collection)')} +
{hideResizers ? null : ( <>
e.preventDefault()} /> @@ -738,9 +741,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P )} -
e.preventDefault()}> + {!Doc.noviceMode &&
e.preventDefault()}> {'⟲'} -
+
} {useRounding && (
li { + height: 27px !important; opacity: 1; transform: scale(1); } diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index c0561e42c..a182a72c5 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -104,6 +104,7 @@ text-overflow: ellipsis; white-space: pre-wrap; min-width: 10px; + grid-column: 2; } .docContainer-system { font-variant: all-small-caps; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index a82bd2dc8..98121f423 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -56,7 +56,9 @@ export class TabDocView extends React.Component { return this._document && Doc.Layout(this._document); } @computed get tabColor() { - return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); + let tabColor = StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); + if (tabColor === 'transparent') return 'black'; + return tabColor; } @computed get tabTextColor() { return this._document?.type === DocumentType.PRES ? 'black' : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color))); diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index ce87e6f89..cfb97709b 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -53,13 +53,16 @@ } .bullet { + grid-column: 1; + display: flex; + justify-content: center; + align-items: center; position: relative; width: $TREE_BULLET_WIDTH; + min-height: 20px; color: $medium-gray; - margin-top: 3px; - // transform: scale(1.3, 1.3); // bcz: why was this here? It makes displaying images in the treeView for documents that have icons harder. border: #80808030 1px solid; - border-radius: 4px; + border-radius: 5px; } } @@ -113,7 +116,15 @@ .treeView-header-editing, .treeView-header { border: transparent 1px solid; - display: flex; + display: grid; + align-items: center; + grid-auto-columns: 22px auto 22px; + width: 100%; + border-radius: 5px; + + &:hover { + background-color: #bdddf5; + } //align-items: center; ::-webkit-scrollbar { @@ -140,6 +151,7 @@ .treeView-rightButtons { display: flex; + grid-column: 3; align-items: center; margin-left: 0.25rem; opacity: 0.75; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 833e364b3..b489b5214 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -736,7 +736,7 @@ export class TreeView extends React.Component { }} /> )} - {this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( + {Doc.noviceMode ? null : this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( {this.treeViewExpandedView} @@ -953,7 +953,7 @@ export class TreeView extends React.Component {
() { icon = 'globe-asia'; text = 'User Default'; } - noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking]; + noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; } else if (script?.script.originalScript.startsWith('setFont')) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; text = StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index ab59e6112..7f0f13437 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -2321,8 +2321,8 @@ export class PresBox extends ViewBoxBaseComponent() { const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; const isMini: boolean = this.toolbarWidth <= 100; return ( -
- {isMini ? null : ( +
+ {isMini || Doc.noviceMode ? null : ( )}
@@ -2653,14 +2651,14 @@ export class PresBox extends ViewBoxBaseComponent() { ) : null}
- { + {/* { // if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack {'Click on document to pin to presentaiton or make a marquee selection to pin your desired view'}
}> - } + } */}
); diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index bbdb4621e..2fe0c6e79 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -52,7 +52,7 @@ export class TopBar extends React.Component { browndash
} - {Doc.ActiveDashboard &&
}>
(DocumentV size="sm" style={{ WebkitAnimation: animation, MozAnimation: animation }} icon={(() => { + // prettier-ignore switch (this.openHover) { default: - case UtilityButtonState.Default: - return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch; - case UtilityButtonState.OpenRight: - return 'arrow-alt-circle-right'; - case UtilityButtonState.OpenExternally: - return 'share'; + case UtilityButtonState.Default: return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch; + case UtilityButtonState.OpenRight: return 'arrow-alt-circle-right'; + case UtilityButtonState.OpenExternally: return 'share'; } })()} /> @@ -231,21 +223,66 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } + @observable expandPin = false; + @observable subPin = ''; @computed get pinButton() { const targetDoc = this.view0?.props.Document; + const pinBtn = (pinDocLayout: boolean, pinDocContent: boolean, icon: IconProp) => { + const tooltip = `Pin Document and Save ${this.subPin} to trail`; + return !tooltip ? null : ( + {tooltip}
}> +
+ + (this.subPin = + (pinDocLayout ? 'Layout' : '') + + (pinDocLayout && pinDocContent ? ' &' : '') + + (pinDocContent ? ' Content View' : '') + + (pinDocLayout && pinDocContent ? '(shift+alt)' : pinDocLayout ? '(shift)' : pinDocContent ? '(alt)' : '')) + )} + onPointerLeave={action(e => (this.subPin = ''))} + onClick={e => { + const docs = this.props + .views() + .filter(v => v) + .map(dv => dv!.rootDoc); + TabDocView.PinDoc(docs, { pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + e.stopPropagation(); + }} + /> +
+ + ); + }; return !targetDoc ? null : ( - {SelectionManager.Views().length > 1 ? 'Pin multiple documents to trail (use shift to pin with view)' : 'Pin to trail (use shift to pin with view)'}
}> + {`Pin Document ${SelectionManager.Views().length > 1 ? 'multiple documents' : ''} to Trail`}
}>
(this.expandPin = true))} + onPointerLeave={action(e => (this.expandPin = false))} onClick={e => { const docs = this.props .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinDocView: e.shiftKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + e.stopPropagation(); }}> + {this.expandPin ? ( +
+ {pinBtn(true, false, 'window-maximize')} + {pinBtn(false, true, 'address-card')} + {pinBtn(true, true, 'id-card')} +
+ ) : null}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 4675571c2..3e0de6d15 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -678,8 +678,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P bounds.r = Math.max(bounds.x, Math.max(leftBounds, Math.min(window.innerWidth, bounds.r + borderRadiusDraggerWidth + this._resizeBorderWidth / 2) - this._resizeBorderWidth / 2 - borderRadiusDraggerWidth)); bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); - // Rotation constants: Only allow rotation on ink and images - const useRotation = seldoc.ComponentView instanceof InkingStroke || seldoc.ComponentView instanceof ImageBox || seldoc.ComponentView instanceof VideoBox; + const useRotation = true; // when do we want an object to not rotate? const rotation = NumCast(seldoc.rootDoc._jitterRotation); const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : ''; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 857a5522c..350883f70 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -303,6 +303,7 @@ export class MainView extends React.Component { fa.faStop, fa.faCalculator, fa.faWindowMaximize, + fa.faIdCard, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft, diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index b1f57f3fd..c4da70371 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -233,7 +233,7 @@ export class TabDocView extends React.Component { pinDoc.presentationTargetDoc = doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the alias' layout are the presentation slide children. the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data - pinDoc.presMovement = pinProps?.pinDocView && !pinProps?.pinWithView ? PresMovement.None : PresMovement.Zoom; + pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; pinDoc.groupWithUp = false; pinDoc.context = curPres; // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index c34a6faaa..640984ad6 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -782,7 +782,7 @@ export class TreeView extends React.Component { onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); - refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document); + refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document, {}); ignoreEvent = (e: any) => { if (this.props.isContentActive(true)) { e.stopPropagation(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7b6944e1e..8824c2b01 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1719,7 +1719,7 @@ export class CollectionFreeFormView extends CollectionSubView (this.Document._fitContentsToBox = !this.fitContentsToBox), icon: !this.fitContentsToBox ? 'expand-arrows-alt' : 'compress-arrows-alt', }); - appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, { pinDocView: true, panelWidth: this.props.PanelWidth(), panelHeight: this.props.PanelHeight() }), icon: 'map-pin' }); + appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); this.props.ContainingCollectionView && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); @@ -2249,6 +2249,6 @@ ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { ScriptingGlobals.add(function prevKeyFrame(readOnly: boolean) { !readOnly && (SelectionManager.Views()[0].ComponentView as CollectionFreeFormView)?.changeKeyFrame(true); }); -ScriptingGlobals.add(function pinWithView(readOnly: boolean) { - !readOnly && SelectionManager.Views().forEach(view => TabDocView.PinDoc(view.rootDoc, { pinDocView: true, panelWidth: view.props.PanelWidth(), panelHeight: view.props.PanelHeight() })); +ScriptingGlobals.add(function pinWithView(readOnly: boolean, pinDocContent: boolean) { + !readOnly && SelectionManager.Views().forEach(view => TabDocView.PinDoc(view.rootDoc, { pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) })); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 8a8b528f6..488f51d77 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -1,11 +1,11 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from "@material-ui/core"; -import { observer } from "mobx-react"; -import { unimplementedFunction } from "../../../../Utils"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { SelectionManager } from "../../../util/SelectionManager"; -import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"; +import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Tooltip } from '@material-ui/core'; +import { observer } from 'mobx-react'; +import { unimplementedFunction } from '../../../../Utils'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { SelectionManager } from '../../../util/SelectionManager'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; @observer export class MarqueeOptionsMenu extends AntimodeMenu { @@ -25,44 +25,34 @@ export class MarqueeOptionsMenu extends AntimodeMenu { } render() { - const presPinWithViewIcon = ; + const presPinWithViewIcon = ; const buttons = [ Create a Collection
} placement="bottom"> - , Create a Grouping
} placement="bottom"> -
, Summarize Documents} placement="bottom"> - , Delete Documents} placement="bottom"> - , - Pin with selected region} placement="bottom"> - , ]; return this.getElement(buttons); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 584c9690f..a020b67cd 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -18,7 +18,7 @@ import { Transform } from '../../../util/Transform'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; -import { PinViewProps, PresBox } from '../../nodes/trails/PresBox'; +import { PresBox } from '../../nodes/trails/PresBox'; import { VideoBox } from '../../nodes/VideoBox'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { PreviewCursor } from '../../PreviewCursor'; @@ -61,6 +61,11 @@ export interface MarqueeViewBounds { @observer export class MarqueeView extends React.Component { + public static CurViewBounds(pinDoc: Doc, panelWidth: number, panelHeight: number) { + const ps = NumCast(pinDoc._viewScale, 1); + return { left: NumCast(pinDoc._panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps }; + } + private _commandExecuted = false; @observable _lastX: number = 0; @observable _lastY: number = 0; @@ -426,10 +431,7 @@ export class MarqueeView extends React.Component { const doc = this.props.Document; - const viewOptions: PinViewProps = { - bounds: this.Bounds, - }; - TabDocView.PinDoc(doc, { pinWithView: viewOptions, pinDocView: true }); + TabDocView.PinDoc(doc, { pinViewport: this.Bounds }); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); }; diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index f6eb2fce4..92f6bbb64 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -208,7 +208,7 @@ export class CollectionLinearView extends CollectionSubView() { checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle} onChange={action(e => { - ScriptCast(this.Document.onClick).script.run({ + ScriptCast(this.Document.onClick)?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ba061ce8f..913d5a7ef 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -577,6 +577,7 @@ export class DocumentViewInternal extends DocComponent this.onClickHandler.script.run( { @@ -602,6 +603,7 @@ export class DocumentViewInternal extends DocComponent { @@ -480,6 +481,10 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { + return undefined; + }; + getSuggestedParams(pos: number) { const firstScript = this.rawText.slice(0, pos); const indexP = firstScript.lastIndexOf('.'); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0c4d514cd..18441aace 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -31,19 +31,16 @@ import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentVie import { FieldView, FieldViewProps } from '../FieldView'; import './PresBox.scss'; import { PresEffect, PresMovement, PresStatus } from './PresEnums'; +import { privateEncrypt } from 'crypto'; +import { ScriptingBox } from '../ScriptingBox'; export interface PinProps { audioRange?: boolean; activeFrame?: number; hidePresBox?: boolean; - pinWithView?: PinViewProps; - pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document - panelWidth?: number; // panel width and height of the document (used to compute the bounds of the pinned view area) - panelHeight?: number; -} - -export interface PinViewProps { - bounds: MarqueeViewBounds; + pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected) + pinDocLayout?: boolean; // pin layout info (width/height/x/y) + pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text) } @observer @@ -268,6 +265,7 @@ export class PresBox extends ViewBoxBaseComponent() { // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode this.nextSlide(0); } + return this.itemIndex; }; // Called when the user activates 'back' - to move to the previous part of the pres. trail @@ -298,6 +296,7 @@ export class PresBox extends ViewBoxBaseComponent() { // Case 3: Pres loop is on so it should go to the last slide this.gotoDocument(this.childDocs.length - 1, activeItem); } + return this.itemIndex; }; //The function that is called when a document is clicked or reached through next or back. @@ -351,7 +350,7 @@ export class PresBox extends ViewBoxBaseComponent() { const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform); const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any); const clippable = [DocumentType.COMPARISON].includes(target.type as any); - const dataview = [DocumentType.INK].includes(target.type as any) && target.activeFrame === undefined; + const dataview = [DocumentType.INK, DocumentType.COL].includes(target.type as any) && target.activeFrame === undefined; const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined; return { scrollable, pannable, temporal, clippable, dataview, textview }; } @@ -383,7 +382,7 @@ export class PresBox extends ViewBoxBaseComponent() { const dv = DocumentManager.Instance.getDocumentView(bestTarget); if (dv) { const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height); - activeItem.presMovement === 'zoom' && (bestTarget._viewScale = activeItem.presZoom !== undefined ? computedScale : Math.min(computedScale, NumCast(bestTarget._viewScale))); + activeItem.presMovement === 'zoom' && (bestTarget._viewScale = computedScale); dv.ComponentView?.brushView?.(viewport); } } else { @@ -400,47 +399,40 @@ export class PresBox extends ViewBoxBaseComponent() { /// target doc when navigating to it. @action static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined, targetDoc: Doc) { - if (pinProps?.pinWithView) { - // If pinWithView option set then update scale and x / y props of slide - const bounds = pinProps.pinWithView.bounds; - pinDoc.presPinView = true; - pinDoc.presPinViewX = bounds.left + bounds.width / 2; - pinDoc.presPinViewY = bounds.top + bounds.height / 2; - pinDoc.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); - } - if (pinProps?.pinDocView) { - const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc); - pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined; + const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc); + if (pinProps?.pinDocLayout) { + pinDoc.presPinLayout = true; pinDoc.presX = NumCast(targetDoc.x); pinDoc.presY = NumCast(targetDoc.y); pinDoc.presRot = NumCast(targetDoc.jitterRotation); pinDoc.presWidth = NumCast(targetDoc.width); pinDoc.presHeight = NumCast(targetDoc.height); - - if (scrollable) { - pinDoc.presPinViewScroll = pinDoc._scrollTop; - } + } + if (pinProps?.pinDocContent) { + pinDoc.presPinData = scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined; + if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text; + if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop; if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth; + if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data; + if (pannable) { + pinDoc.presPinViewX = NumCast(pinDoc._panX); + pinDoc.presPinViewY = NumCast(pinDoc._panY); + pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1); + } if (temporal) { pinDoc.presStartTime = pinDoc._currentTimecode; const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(pinDoc.presStartTime) + 0.1); pinDoc.presEndTime = NumCast(pinDoc.clipEnd, duration); } - if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text; - if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data; - if (pannable || scrollable) { - const panX = NumCast(pinDoc._panX); - const panY = NumCast(pinDoc._panY); - const pw = NumCast(pinProps.panelWidth); - const ph = NumCast(pinProps.panelHeight); - const ps = NumCast(pinDoc._viewScale, 1); - if (pw && ph && ps) { - pinDoc.presPinViewBounds = new List([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]); - } - pinDoc.presPinViewX = panX; - pinDoc.presPinViewY = panY; - pinDoc.presPinViewScale = ps; - } + } + if (pinProps?.pinViewport) { + // If pinWithView option set then update scale and x / y props of slide + const bounds = pinProps.pinViewport; + pinDoc.presPinView = true; + pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1); + pinDoc.presPinViewX = bounds.left + bounds.width / 2; + pinDoc.presPinViewY = bounds.top + bounds.height / 2; + pinDoc.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); } } @@ -497,7 +489,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) { - if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) { + if ((activeItem.presPinLayout || activeItem.presPinView) && DocCast(targetDoc.context)?._currentFrame === undefined) { const transTime = NumCast(activeItem.presTransition, 500); const presTransitionTime = `all ${transTime}ms`; targetDoc._dataTransition = presTransitionTime; @@ -514,11 +506,13 @@ export class PresBox extends ViewBoxBaseComponent() { } else if (targetDoc && activeItem.presMovement !== PresMovement.None) { LightboxView.SetLightboxDoc(undefined); const zooming = activeItem.presMovement !== PresMovement.Pan; - DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom)); + DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom, 1)); + } else if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { + (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); } // After navigating to the document, if it is added as a presPinView then it will // adjust the pan and scale to that of the pinView when it was added. - if (activeItem.presPinView) { + if (activeItem.presPinData || activeItem.presPinView) { clearTimeout(PresBox._navTimer); // targetDoc may or may not be displayed. this gets the first available document (or alias) view that matches targetDoc const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document; @@ -615,42 +609,19 @@ export class PresBox extends ViewBoxBaseComponent() { //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc @action startAutoPres = (startSlide: number) => { - this.updateCurrentPresentation(); - let activeItem: Doc = this.activeItem; - let targetDoc: Doc = this.targetDoc; - let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition); - const timer = (ms: number) => new Promise(res => (this._presTimer = setTimeout(res, ms))); - const load = async () => { - // Wrap the loop into an async function for this to work - for (var i = startSlide; i < this.childDocs.length; i++) { - activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); - duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition); - if (duration < 100) { - duration = 2500; - } - if (NumCast(targetDoc.lastFrame) > 0) { - for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) { - await timer(duration / NumCast(targetDoc.lastFrame)); - this.next(); - } - } - - await timer(duration); - this.next(); // then the created Promise can be awaited - if (i === this.childDocs.length - 1) { - setTimeout(() => { - clearTimeout(this._presTimer); - if (this.layoutDoc.presStatus === 'auto' && !this.layoutDoc.presLoop) this.layoutDoc.presStatus = PresStatus.Manual; - else if (this.layoutDoc.presLoop) this.startAutoPres(0); - }, duration); - } - } - }; this.layoutDoc.presStatus = PresStatus.Autoplay; this.startPresentation(startSlide); - this.gotoDocument(startSlide, activeItem); - load(); + clearTimeout(this._presTimer); + const func = (itemIndex: number) => { + if (itemIndex === this.next()) this.layoutDoc.presStatus = PresStatus.Manual; + else + this._presTimer = setTimeout( + () => this.layoutDoc.presStatus !== PresStatus.Manual && func(this.itemIndex), + NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition) + ); + }; + + func(this.itemIndex); }; // The function pauses the auto presentation @@ -659,7 +630,6 @@ export class PresBox extends ViewBoxBaseComponent() { if (this.layoutDoc.presStatus === PresStatus.Autoplay) { if (this._presTimer) clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; - this.layoutDoc.presLoop = false; this.childDocs.forEach(this.stopTempMedia); } }; @@ -667,7 +637,6 @@ export class PresBox extends ViewBoxBaseComponent() { //The function that resets the presentation by removing every action done by it. It also //stops the presentaton. resetPresentation = () => { - this.rootDoc._itemIndex = 0; this.childDocs .map(doc => Cast(doc.presentationTargetDoc, Doc, null)) .filter(doc => doc instanceof Doc) @@ -706,8 +675,7 @@ export class PresBox extends ViewBoxBaseComponent() { * @param startIndex: index that the presentation will start at */ startPresentation = (startIndex: number) => { - this.updateCurrentPresentation(); - this.childDocs.map(doc => { + this.childDocs.forEach(doc => { const tagDoc = doc.presentationTargetDoc as Doc; if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) { tagDoc.opacity = 0; @@ -716,6 +684,7 @@ export class PresBox extends ViewBoxBaseComponent() { tagDoc.opacity = 0; } }); + this.gotoDocument(startIndex, this.activeItem); }; /** @@ -996,7 +965,7 @@ export class PresBox extends ViewBoxBaseComponent() { break; case 'Spacebar': case ' ': - if (this.layoutDoc.presStatus === PresStatus.Manual) this.startAutoPres(this.itemIndex); + if (this.layoutDoc.presStatus === PresStatus.Manual) this.startOrPause(true); else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer); handled = true; break; @@ -1254,7 +1223,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (activeItem && targetDoc) { const type = targetDoc.type; const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; - const zoom = activeItem.presZoom ? NumCast(activeItem.presZoom) * 100 : 75; + const zoom = NumCast(activeItem.presZoom, 1) * 100; let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2; if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); const effect = this.activeItem.presEffect ? this.activeItem.presEffect : 'None'; @@ -1808,6 +1777,11 @@ export class PresBox extends ViewBoxBaseComponent() { ); } + scrollFocus = () => { + this.startOrPause(false); + return undefined; + }; + // Case in which the document has keyframes to navigate to next key frame @action nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => { @@ -2480,7 +2454,7 @@ export class PresBox extends ViewBoxBaseComponent() { {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}}> -
+
this.startOrPause(true)}>
@@ -2529,7 +2503,8 @@ export class PresBox extends ViewBoxBaseComponent() { } @action - startOrPause = () => { + startOrPause = (makeActive = true) => { + makeActive && this.updateCurrentPresentation(); if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex); else this.pauseAutoPres(); }; @@ -2613,7 +2588,7 @@ export class PresBox extends ViewBoxBaseComponent() {
{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}}> -
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}> +
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.startOrPause(true), false, false)}>
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index e6d08cd53..fe2668492 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -26,6 +26,7 @@ import { PresMovement } from './PresEnums'; import React = require('react'); import { InkField } from '../../../../fields/InkField'; import { RichTextField } from '../../../../fields/RichTextField'; +import { MarqueeView } from '../../collections/collectionFreeForm'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. @@ -142,7 +143,6 @@ export class PresElementBox extends ViewBoxBaseComponent() { this.presExpandDocumentClick(); }}>
{`${ind + 1}.`}
- {/* style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }} */}
() { */ @undoBatch @action - updateView = (targetDoc: Doc, activeItem: Doc) => { + updateCapturedContainerLayout = (targetDoc: Doc, activeItem: Doc) => { + activeItem.presX = NumCast(targetDoc.x); + activeItem.presY = NumCast(targetDoc.y); + activeItem.presRot = NumCast(targetDoc.jitterRotation); + activeItem.presWidth = NumCast(targetDoc.width); + activeItem.presHeight = NumCast(targetDoc.height); + }; + /** + * Method called for updating the view of the currently selected document + * + * @param targetDoc + * @param activeItem + */ + @undoBatch + @action + updateCapturedViewContents = (targetDoc: Doc, activeItem: Doc) => { switch (targetDoc.type) { case DocumentType.PDF: case DocumentType.WEB: @@ -326,20 +341,22 @@ export class PresElementBox extends ViewBoxBaseComponent() { const clipWidth = targetDoc._clipWidth; activeItem.presPinClipWidth = clipWidth; break; + case DocumentType.COL: default: - const x = targetDoc._panX; - const y = targetDoc._panY; - const scale = targetDoc._viewScale; - activeItem.presPinViewX = x; - activeItem.presPinViewY = y; - activeItem.presPinViewScale = scale; + const bestView = DocumentManager.Instance.getFirstDocumentView(targetDoc); + if (activeItem.presPinViewBounds && bestView) { + const bounds = MarqueeView.CurViewBounds(targetDoc, bestView.props.PanelWidth(), bestView.props.PanelHeight()); + activeItem.presPinView = true; + activeItem.presPinViewScale = NumCast(targetDoc._viewScale, 1); + activeItem.presPinViewX = bounds.left + bounds.width / 2; + activeItem.presPinViewY = bounds.top + bounds.height / 2; + activeItem.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); + } else { + activeItem.presPinViewX = targetDoc._panX; + activeItem.presPinViewY = targetDoc._panY; + activeItem.presPinViewScale = targetDoc._viewScale; + } } - - activeItem.presX = NumCast(targetDoc.x); - activeItem.presY = NumCast(targetDoc.y); - activeItem.presRot = NumCast(targetDoc.jitterRotation); - activeItem.presWidth = NumCast(targetDoc.width); - activeItem.presHeight = NumCast(targetDoc.height); }; @computed get recordingIsInOverlay() { @@ -506,16 +523,23 @@ export class PresElementBox extends ViewBoxBaseComponent() { {/*
{"Movement speed"}
}>
{this.transition}
*/} {/*
{"Duration"}
}>
{this.duration}
*/}
- Update view
}> -
this.updateView(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinView ? 'flex' : 'none' }}> - V + Update captured doc layout
}> +
this.updateCapturedContainerLayout(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinLayout ? 'flex' : 'none' }}> + L
- {!Doc.noviceMode && {this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}
}> -
(this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}> - e.stopPropagation()} /> + Update captured doc content
}> +
this.updateCapturedViewContents(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinData || activeItem.presPinView ? 'flex' : 'none' }}> + C
- } + + {!Doc.noviceMode && ( + {this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}
}> +
(this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}> + e.stopPropagation()} /> +
+
+ )} {activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}}>
Date: Mon, 31 Oct 2022 13:26:52 -0400 Subject: cleaning up link count icon to be part of documentLinks view and to appear on tab views that have links. --- src/client/views/DocumentButtonBar.tsx | 31 ++-------- src/client/views/GlobalKeyHandler.ts | 5 -- src/client/views/nodes/DocumentLinksButton.scss | 34 +++++------ src/client/views/nodes/DocumentLinksButton.tsx | 67 ++++++++++----------- src/client/views/nodes/DocumentView.scss | 2 +- src/client/views/nodes/DocumentView.tsx | 80 ++++++++++++------------- 6 files changed, 93 insertions(+), 126 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index d42ff436f..ce77b7446 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -317,24 +317,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } - - @computed - get moreButton() { - const targetDoc = this.view0?.props.Document; - return !targetDoc ? null : ( - -
{`${SettingsManager.propertiesWidth > 0 ? 'Close' : 'Open'} Properties Panel`}
- - }> -
(SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250))}> - -
-
- ); - } - @computed get metadataButton() { const view0 = this.view0; @@ -463,6 +445,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const considerPush = isText && this.considerGoogleDocsPush; return (
+
+ +
@@ -475,11 +460,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV { Doc.noviceMode ? null :
{this.templateButton}
/*
- {this.metadataButton} -
-
- {this.contextButton} -
*/ + {this.metadataButton} +
*/ } {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
@@ -493,9 +475,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV {this.considerGoogleDocsPull}
{this.menuButton}
- {/* {Doc.noviceMode ? (null) :
- {this.moreButton} -
} */} ); } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 8e9c18cf3..c19e6831f 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -151,11 +151,6 @@ export class KeyManager { SelectionManager.DeselectAll(); } else DocumentDecorations.Instance.onCloseClick(true); }, 'backspace'); - // const selected = SelectionManager.Views().filter(dv => !dv.topMost); - // UndoManager.RunInBatch(() => { - // SelectionManager.DeselectAll(); - // selected.map(dv => !dv.props.Document._stayInCollection && dv.props.removeDocument?.(dv.props.Document)); - // }, "delete"); return { stopPropagation: true, preventDefault: true }; } break; diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index 0f3eb14bc..6da0b73ba 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -1,8 +1,9 @@ -@import "../global/globalCssVariables.scss"; +@import '../global/globalCssVariables.scss'; .documentLinksButton-wrapper { transform-origin: top left; width: 100%; + height: 100%; } .documentLinksButton-menu { @@ -21,6 +22,16 @@ position: absolute; } +.documentLinksButton-showCount { + position: absolute; + border-radius: 50%; + opacity: 0.9; + pointer-events: auto; + display: flex; + align-items: center; + background-color: $light-blue; + color: black; +} .documentLinksButton, .documentLinksButton-endLink, .documentLinksButton-startLink { @@ -34,6 +45,7 @@ text-transform: uppercase; letter-spacing: 2px; font-size: 10px; + transform-origin: top left; transition: transform 0.2s; text-align: center; display: flex; @@ -46,13 +58,10 @@ cursor: pointer; } } - .documentLinksButton { background-color: $dark-gray; color: $white; font-weight: bold; - width: 80%; - height: 80%; font-size: 100%; font-family: 'Roboto'; transition: 0.2s ease all; @@ -61,31 +70,20 @@ background-color: $black; } } - .documentLinksButton.startLink { background-color: $medium-blue; + width: 75%; + height: 75%; color: $white; font-weight: bold; - width: 80%; - height: 80%; font-size: 100%; transition: 0.2s ease all; - - &:hover { - background-color: $black; - } } .documentLinksButton-endLink { border: $medium-blue 2px dashed; color: $medium-blue; background-color: none !important; - width: 80%; - height: 80%; font-size: 100%; transition: 0.2s ease all; - - &:hover { - background-color: $light-blue; - } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 9ffbf8e37..1d455ad08 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -4,19 +4,18 @@ import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; -import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnFalse, setupMoveUpEvents, StopEvent } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { Hypothesis } from '../../util/HypothesisUtils'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; -import { Colors } from '../global/globalEnums'; import './DocumentLinksButton.scss'; import { DocumentView } from './DocumentView'; import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { TaskCompletionBox } from './TaskCompletedBox'; import React = require('react'); +import _ = require('lodash'); const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; @@ -24,10 +23,12 @@ export const Flyout = higflyout.default; interface DocumentLinksButtonProps { View: DocumentView; - Offset?: (number | undefined)[]; + Bottom?: boolean; AlwaysOn?: boolean; InMenu?: boolean; + OnHover?: boolean; StartLink?: boolean; //whether the link HAS been started (i.e. now needs to be completed) + ShowCount?: boolean; scaling?: () => number; // how uch doc is scaled so that link buttons can invert it } @observer @@ -119,7 +120,6 @@ export class DocumentLinksButton extends React.Component Doc.BrushDoc(this.props.View.Document)); } }; @@ -256,28 +256,32 @@ export class DocumentLinksButton extends React.Component; + const btnDim = 30; const isActive = DocumentLinksButton.StartLink === this.props.View.props.Document && this.props.StartLink; - return !this.props.InMenu ? ( -
-
- {Array.from(this.filteredLinks).length} -
+ const scaling = Math.min(1, this.props.scaling?.() || 1); + const showLinkCount = (onHover?: boolean, offset?: boolean) => ( +
+ {Array.from(this.filteredLinks).length}
+ ); + return this.props.ShowCount ? ( + showLinkCount(this.props.OnHover, this.props.Bottom) ) : (
- {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node + {this.props.StartLink ? ( //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again +
+ +
+ ) : null} + {!this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node
) : null} - {this.props.InMenu && this.props.StartLink ? ( //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again -
- -
- ) : null}
); } render() { - TraceMobx(); - const menuTitle = this.props.StartLink ? 'Drag or tap to start link' : 'Tap to complete link'; const buttonTitle = 'Tap to view links; double tap to open link collection'; - const title = this.props.InMenu ? menuTitle : buttonTitle; + const title = this.props.ShowCount ? buttonTitle : menuTitle; //render circular tooltip if it isn't set to invisible and show the number of doc links the node has, and render inner-menu link button for starting/stopping links if currently in menu return !Array.from(this.filteredLinks).length && !this.props.AlwaysOn ? null : (
- {(this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) || (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ? ( - {title}
}>{this.linkButtonInner} - ) : ( - this.linkButtonInner - )} + {title}
: <>}>{this.linkButtonInner}
); } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 6cadeec41..5c95177c5 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -209,7 +209,7 @@ .contentFittingDocumentView { position: relative; - display: flex; + display: block; width: 100%; height: 100%; transition: inherit; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b5dde211b..50b76896e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,7 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Document } from '../../../fields/documentSchemas'; @@ -198,6 +198,7 @@ export interface DocumentViewInternalProps extends DocumentViewProps { NativeWidth: () => number; NativeHeight: () => number; isSelected: (outsideReaction?: boolean) => boolean; + isHovering: () => boolean; select: (ctrlPressed: boolean) => void; DocumentView: () => DocumentView; viewPath: () => DocumentView[]; @@ -257,9 +258,6 @@ export class DocumentViewInternal extends DocComponent (this.props.NativeDimScaling?.() || 1) * this.props.DocumentView().screenToLocalTransform().Scale; get audioAnnoState() { return this.dataDoc.audioAnnoState ?? 'stopped'; } @@ -1066,7 +1063,7 @@ export class DocumentViewInternal extends DocComponent{audioTextAnnos?.lastElement()}}>
@@ -1074,15 +1071,6 @@ export class DocumentViewInternal extends DocComponent ); } - @computed get linkCountView() { - return this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (!this.props.isSelected() && !this._isHovering) || this.hideLinkButton ? null : ( - - ); - } @computed get contents() { TraceMobx(); return ( @@ -1119,7 +1107,7 @@ export class DocumentViewInternal extends DocComponent {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints} - {this.linkCountView} {this.audioAnnoView}
); @@ -1149,16 +1136,13 @@ export class DocumentViewInternal extends DocComponent this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + // prettier-ignore switch (property) { - case StyleProp.ShowTitle: - return ''; - case StyleProp.PointerEvents: - return 'none'; - case StyleProp.LinkSource: - return this.props.Document; // pass the LinkSource to the LinkAnchorBox - default: - return this.props.styleProvider?.(doc, props, property); + case StyleProp.ShowTitle: return ''; + case StyleProp.PointerEvents: return 'none'; + case StyleProp.LinkSource: return this.props.Document; // pass the LinkSource to the LinkAnchorBox } + return this.props.styleProvider?.(doc, props, property); }; // We need to use allrelatedLinks to get not just links to the document as a whole, but links to // anchors that are not rendered as DocumentViews (marked as 'unrendered' with their 'annotationOn' set to this document). e.g., @@ -1360,10 +1344,7 @@ export class DocumentViewInternal extends DocComponent ); } - isHovering = () => this._isHovering; - @observable _isHovering = false; @observable _: string = ''; - _hoverTimeout: any = undefined; renderDoc = (style: object) => { TraceMobx(); const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); @@ -1374,17 +1355,6 @@ export class DocumentViewInternal extends DocComponent { - clearTimeout(this._hoverTimeout); - this._isHovering = true; - })} - onPointerLeave={action(() => { - clearTimeout(this._hoverTimeout); - this._hoverTimeout = setTimeout( - action(() => (this._isHovering = false)), - 500 - ); - })} style={{ ...style, background: isButton || thumb ? undefined : this.backgroundColor, @@ -1535,6 +1505,18 @@ export class DocumentView extends React.Component { return this.props.fitWidth?.(this.rootDoc) || this.layoutDoc.fitWidth; } + @computed get hideLinkButton() { + return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.isSelected() ? ':selected' : '')); + } + linkButtonInverseScaling = () => (this.props.NativeDimScaling?.() || 1) * this.screenToLocalTransform().Scale; + + @computed get linkCountView() { + return (this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (this.isSelected() && this.props.renderDepth) || !this._isHovering || this.hideLinkButton) && + DocumentLinksButton.LinkEditorDocView?.rootDoc !== this.rootDoc ? null : ( + + ); + } + @computed get docViewPath(): DocumentView[] { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; } @@ -1680,6 +1662,9 @@ export class DocumentView extends React.Component { Object.values(this._disposers).forEach(disposer => disposer?.()); !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } + _hoverTimeout: any = undefined; + isHovering = () => this._isHovering; + @observable _isHovering = false; render() { TraceMobx(); @@ -1687,7 +1672,19 @@ export class DocumentView extends React.Component { const yshift = Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined; const isButton = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear; return ( -
+
{ + clearTimeout(this._hoverTimeout); + this._isHovering = true; + })} + onPointerLeave={action(() => { + clearTimeout(this._hoverTimeout); + this._hoverTimeout = setTimeout( + action(() => (this._isHovering = false)), + 500 + ); + })}> {!this.props.Document || !this.props.PanelWidth() ? null : (
{ NativeDimScaling={this.NativeDimScaling} isSelected={this.isSelected} select={this.select} + isHovering={this.isHovering} ScreenToLocalTransform={this.screenToLocalTransform} focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} />
)} + + {this.linkCountView}
); } -- cgit v1.2.3-70-g09d2 From bbc993dd70d105c3de078208763e6415eedb1ff7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Nov 2022 11:18:46 -0500 Subject: partial fix for previewing multiple links to different sidebar notes. fixed opening sidebar to create an annotation the first time. fixed honoring dashFieldView's non-editable flag. moved isLinkButton setter to expert and make isLinkButton default for Buttons. fixed following Links with Zoom to reset view. fixed view for editing onClick for documents --- src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/LinkFollower.ts | 5 +++-- src/client/views/DocumentButtonBar.tsx | 4 ++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 12 +++++++----- src/client/views/nodes/formattedText/DashFieldView.tsx | 3 +++ src/client/views/nodes/formattedText/FormattedTextBox.tsx | 13 ++++++++----- src/fields/Proxy.ts | 2 +- 10 files changed, 28 insertions(+), 19 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d789d4ee3..f1b8c3034 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1607,7 +1607,7 @@ export namespace DocUtils { const iconViews = DocListCast(Cast(Doc.UserDoc()['template-icons'], Doc, null)?.data); const templBtns = DocListCast(Cast(Doc.UserDoc()['template-buttons'], Doc, null)?.data); const noteTypes = DocListCast(Cast(Doc.UserDoc()['template-notes'], Doc, null)?.data); - const clickFuncs = DocListCast(Cast(Doc.UserDoc().clickFuncs, Doc, null)?.data); + const clickFuncs = DocListCast(Cast(Doc.UserDoc()['template-clickFuncs'], Doc, null)?.data); const allTemplates = iconViews .concat(templBtns) .concat(noteTypes) diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f2d851a40..d13209c4f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -267,7 +267,7 @@ export class CurrentUserUtils { {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _showSidebar: true, }}, {key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }}, {key: "WebCam", creator: opts => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, recording:true, system: true, cloneFieldFilter: new List(["system"]) }}, - {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }}, + {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, _isLinkButton: true }}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, // {key: "DataViz", creator: opts => Docs.Create.DataVizDocument(opts), opts: { _width: 300, _height: 300 }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,}}, diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index ea0531fa2..43b2caf88 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -48,9 +48,10 @@ export class LinkFollower { }, }); } else { - res(where !== 'inPlace' ? ViewAdjustment.resetView : ViewAdjustment.doNothing); // for 'inPlace' resetting the initial focus&zoom would negate the zoom into the target + finished?.(); + res(where !== 'inPlace' || BoolCast(sourceDoc.followLinkZoom) ? ViewAdjustment.resetView : ViewAdjustment.doNothing); // for 'inPlace' resetting the initial focus&zoom would negate the zoom into the target } - }); + }, 100); }); if (!sourceDoc.followLinkZoom) { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index ce77b7446..3f12c7c9d 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -356,7 +356,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV {'Click to record 5 second annotation'}
}>
{ this._isRecording = true; @@ -463,7 +463,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV {this.metadataButton}
*/ } - {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
} + {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : ( diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index cec03c991..3fac137fe 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); const useLock = bounds.r - bounds.x > 135 && seldocview.props.CollectionFreeFormDocumentView; - const useRotation = seldocview.rootDoc.type !== DocumentType.EQUATION; // when do we want an object to not rotate? + const useRotation = seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.props.CollectionFreeFormDocumentView; // when do we want an object to not rotate? const rotation = NumCast(seldocview.rootDoc._rotation); const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : ''; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4ee871ba2..973363f78 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -618,7 +618,7 @@ export class DocumentViewInternal extends DocComponent { _linkDocRef = React.createRef(); @observable public static LinkInfo: Opt; @observable _targetDoc: Opt; + @observable _markerTargetDoc: Opt; @observable _linkDoc: Opt; @observable _linkSrc: Opt; @observable _toolTipText = ''; @@ -57,9 +58,9 @@ export class LinkDocPreview extends React.Component { } if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { // want to show annotation context document if annotation is not text - linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._targetDoc = anno))); + linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._markerTargetDoc = this._targetDoc = anno))); } else { - this._targetDoc = linkTarget; + this._markerTargetDoc = this._targetDoc = linkTarget; } this._toolTipText = ''; } @@ -105,10 +106,11 @@ export class LinkDocPreview extends React.Component { // automatic links specify the target in the link info, not the source const linkTarget = anchor; this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget); - this._targetDoc = linkTarget; + this._markerTargetDoc = this._targetDoc = linkTarget; } else { this._linkSrc = anchor; const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); + this._markerTargetDoc = linkTarget; this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; } this._toolTipText = ''; @@ -175,10 +177,10 @@ export class LinkDocPreview extends React.Component { return Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)); }; @computed get previewHeader() { - return !this._linkDoc || !this._targetDoc || !this._linkSrc ? null : ( + return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : (
- {StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + '...' : StrCast(this._targetDoc.title)} + {StrCast(this._markerTargetDoc.title).length > 16 ? StrCast(this._markerTargetDoc.title).substr(0, 16) + '...' : StrCast(this._markerTargetDoc.title)}

{StrCast(this._linkDoc.description)}

diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 39b38add2..41b92a3c7 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -171,6 +171,9 @@ export class DashFieldViewInternal extends React.Component this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection'); + getAnchor = () => this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection', false); @action setupAnchorMenu = () => { @@ -239,7 +239,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { !this.layoutDoc.showSidebar && this.toggleSidebar(); - this._sidebarRef.current?.anchorMenuClick(this.getAnchor()); + setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection', true))); // give time for sidebarRef to be created }; AnchorMenu.Instance.OnAudio = (e: PointerEvent) => { !this.layoutDoc.showSidebar && this.toggleSidebar(); @@ -891,9 +891,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type.name === schema.marks.splitter.name)) { const allAnchors = [{ href, title, anchorId: anchor[Id] }]; allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.linkAnchor.name)?.attrs.allAnchors ?? [])); - const link = state.schema.marks.linkAnchor.create({ allAnchors, title, location }); + const link = state.schema.marks.linkAnchor.create({ allAnchors, title, location, noPreview }); tr = tr.addMark(pos, pos + node.nodeSize, link); + selectedText += (node as Node).textContent; } }); this.dataDoc[ForceServerWrite] = this.dataDoc[UpdatingFromServer] = true; // need to allow permissions for adding links to readonly/augment only documents this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter)); this.dataDoc[UpdatingFromServer] = this.dataDoc[ForceServerWrite] = false; + anchor.text = selectedText; return anchor; } return anchorDoc ?? this.rootDoc; @@ -1471,7 +1474,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent node that wraps the hyerlink while (target && !target.dataset?.targethrefs) target = target.parentElement; - FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview); + FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true'); } if (e.button === 0 && this.props.isSelected(true) && !e.altKey) { diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index e924ef7a3..72ae13035 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -66,7 +66,7 @@ export class ProxyField extends ObjectField { const cached = DocServer.GetCachedRefField(this.fieldId) as T; if (cached !== undefined) { - this.cache = cached; + setTimeout(action(() => (this.cache = cached))); } else if (!this.promise) { this.promise = DocServer.GetRefField(this.fieldId).then( action((field: any) => { -- cgit v1.2.3-70-g09d2 From 7bde06fc756684d47c89c65199492daef5fe5b63 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 14 Nov 2022 09:51:49 -0500 Subject: made audio anno recording last as long as record button is pressed. added a Hide option to allow an pres item to be animated but not visible (used to setup state for subsequent activity)) --- src/client/views/DocumentButtonBar.tsx | 36 ++++++++++--------- src/client/views/nodes/DocumentView.tsx | 10 +++--- src/client/views/nodes/trails/PresBox.tsx | 60 ++++++++++++++++++------------- 3 files changed, 61 insertions(+), 45 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 3f12c7c9d..a110bf51a 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -6,7 +6,7 @@ import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; import { Cast, NumCast } from '../../fields/Types'; -import { emptyFunction, setupMoveUpEvents, simulateMouseClick } from '../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { Docs } from '../documents/Documents'; @@ -14,7 +14,7 @@ import { DragManager } from '../util/DragManager'; import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; -import { undoBatch } from '../util/UndoManager'; +import { undoBatch, UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { TabDocView } from './collections/TabDocView'; import './DocumentButtonBar.scss'; @@ -349,28 +349,30 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV } @observable _isRecording = false; + _stopFunc: () => void = emptyFunction; @computed get recordButton() { const targetDoc = this.view0?.props.Document; return !targetDoc ? null : ( - {'Click to record 5 second annotation'}
}> + Press to record audio annotation
}>
{ - this._isRecording = true; - this.props.views().map( - view => - view && - DocumentViewInternal.recordAudioAnnotation( - view.dataDoc, - view.LayoutFieldKey, - action(() => (this._isRecording = false)) - ) - ); - }) - )}> + onPointerDown={action((e: React.PointerEvent) => { + this._isRecording = true; + this.props.views().map( + view => + view && + DocumentViewInternal.recordAudioAnnotation( + view.dataDoc, + view.LayoutFieldKey, + stopFunc => (this._stopFunc = stopFunc), + action(() => (this._isRecording = false)) + ) + ); + const b = UndoManager.StartBatch('Recording'); + setupMoveUpEvents(this, e, returnFalse, () => this._stopFunc(), emptyFunction); + })}>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6b96362bf..c669d2b96 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1208,7 +1208,7 @@ export class DocumentViewInternal extends DocComponent void) { + static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { let gumStream: any; let recorder: any; navigator.mediaDevices @@ -1245,12 +1245,14 @@ export class DocumentViewInternal extends DocComponent (dataDoc.audioAnnoState = 'recording')); recorder.start(); - setTimeout(() => { + const stopFunc = () => { recorder.stop(); DictationManager.Controls.stop(false); runInAction(() => (dataDoc.audioAnnoState = 'stopped')); gumStream.getAudioTracks()[0].stop(); - }, 5000); + }; + if (onRecording) onRecording(stopFunc); + else setTimeout(stopFunc, 5000); }); } @@ -1385,7 +1387,7 @@ export class DocumentViewInternal extends DocComponent() { this.startTempMedia(targetDoc, activeItem); } if (targetDoc) { - Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc); + // Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc); targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500))); setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10); } @@ -392,12 +392,7 @@ export class PresBox extends ViewBoxBaseComponent() { () => StrListCast(activeItem.presPinLayoutData) .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) - .forEach( - action(data => { - const doc = DocServer.GetCachedRefField(data.id) as Doc; - doc._dataTransition = undefined; - }) - ), + .forEach(action(data => ((DocServer.GetCachedRefField(data.id) as Doc)._dataTransition = undefined))), transTime + 10 ); } @@ -616,26 +611,29 @@ export class PresBox extends ViewBoxBaseComponent() { if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1; } else { - if (curDoc.presHideBefore) { - if (itemIndexes.length > 1 && curInd !== 0) { + const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex); + if (curDoc.presHideBefore && index === hidingIndBef) { + if (index > this.itemIndex) { + tagDoc.opacity = 0; + } else if (index === this.itemIndex || !curDoc.presHideAfter) { tagDoc.opacity = 1; - } else { - if (index > this.itemIndex) { - tagDoc.opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideAfter) { - tagDoc.opacity = 1; - } } } - if (curDoc.presHideAfter) { - if (itemIndexes.length > 1 && curInd !== itemIndexes.length - 1) { + const hidingIndAft = itemIndexes + .slice() + .reverse() + .find(item => item < this.itemIndex); + if (curDoc.presHideAfter && index === hidingIndAft) { + if (index < this.itemIndex) { + tagDoc.opacity = 0; + } else if (index === this.itemIndex || !curDoc.presHideBefore) { tagDoc.opacity = 1; - } else { - if (index < this.itemIndex) { - tagDoc.opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideBefore) { - tagDoc.opacity = 1; - } + } + } + const hidingInd = itemIndexes.find(item => item === this.itemIndex); + if (curDoc.presHide && index === hidingInd) { + if (index === this.itemIndex) { + tagDoc.opacity = 0; } } } @@ -1180,6 +1178,13 @@ export class PresBox extends ViewBoxBaseComponent() { this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); }; + @undoBatch + @action + updateHide = (activeItem: Doc) => { + activeItem.presHide = !activeItem.presHide; + this.selectedArray.forEach(doc => (doc.presHide = activeItem.presHide)); + }; + @undoBatch @action updateHideAfter = (activeItem: Doc) => { @@ -1317,7 +1322,7 @@ export class PresBox extends ViewBoxBaseComponent() { - {inputter('0.1', '0.1', '10', transitionSpeed, [PresMovement.Pan, PresMovement.Zoom].includes(activeItem.presMovement as any), this.setTransitionTime)} + {inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)}
Fast
Medium
@@ -1334,6 +1339,13 @@ export class PresBox extends ViewBoxBaseComponent() {
)} + {isPresCollection ? null : ( + {'Hide while presented'}}> +
this.updateHide(activeItem)}> + Hide +
+
+ )} {isPresCollection ? null : ( {'Hide after presented'}}>
this.updateHideAfter(activeItem)}> -- cgit v1.2.3-70-g09d2 From 3d8bd17fa4f031f2223840b336c313a18e7e87aa Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 14 Nov 2022 14:29:48 -0500 Subject: fixed following link 'inPlace' from within lightbox to do same thing as if out of lightbox. fixed contentActive behavior for multicolumn view. removed progressivize from presbox. --- src/client/documents/Documents.ts | 1 - src/client/util/DocumentManager.ts | 24 +- src/client/util/LinkFollower.ts | 7 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/LightboxView.tsx | 8 +- src/client/views/MainView.tsx | 2 +- src/client/views/PropertiesView.tsx | 14 - src/client/views/collections/TabDocView.tsx | 9 +- .../collectionFreeForm/CollectionFreeFormView.scss | 50 --- .../collectionFreeForm/CollectionFreeFormView.tsx | 54 +-- .../CollectionMulticolumnView.tsx | 10 +- .../CollectionMultirowView.tsx | 8 +- src/client/views/nodes/DocumentView.scss | 6 +- src/client/views/nodes/trails/PresBox.tsx | 475 +-------------------- 14 files changed, 75 insertions(+), 595 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f1b8c3034..e44004f45 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -259,7 +259,6 @@ export class DocumentOptions { appearFrame?: number; // the frame in which the document appears presTransition?: number; //the time taken for the transition TO a document presDuration?: number; //the duration of the slide in presentation view - presProgressivize?: boolean; borderRounding?: string; boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow data?: any; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index b046d950f..01ca24439 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -131,6 +131,7 @@ export class DocumentManager { return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); }; public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { + if (LightboxView.LightboxDoc) return DocumentManager.Instance.getLightboxDocumentView(toFind, originatingDoc); const views = this.getDocumentViews(toFind).filter(view => view.rootDoc !== originatingDoc); return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); }; @@ -168,8 +169,7 @@ export class DocumentManager { presZoomScale?: number ): void => { originalTarget = originalTarget ?? targetDoc; - const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; - const docView = getFirstDocView(targetDoc, originatingDoc); + const docView = this.getFirstDocumentView(targetDoc, originatingDoc); const annotatedDoc = Cast(targetDoc.annotationOn, Doc, null); const resolvedTarget = targetDoc.type === DocumentType.MARKER ? annotatedDoc ?? docView?.rootDoc ?? targetDoc : docView?.rootDoc ?? targetDoc; // if target is a marker, then focus toggling should apply to the document it's on since the marker itself doesn't have a hidden field var wasHidden = resolvedTarget.hidden; @@ -206,11 +206,11 @@ export class DocumentManager { } finished?.(); }; - const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc); + const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && this.getFirstDocumentView(annotatedDoc); const contextDocs = docContext.length ? DocListCast(docContext[0].data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext.lastElement() : undefined; const targetDocContext = contextDoc || annotatedDoc; - const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) || (wasHidden && annoContainerView); // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above + const targetDocContextView = (targetDocContext && this.getFirstDocumentView(targetDocContext)) || (wasHidden && annoContainerView); // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView; if (annoContainerView) { if (annoContainerView.props.Document.layoutKey === 'layout_icon') { @@ -281,7 +281,7 @@ export class DocumentManager { } else { // no timecode means we need to find the context view and focus on our target const findView = (delay: number) => { - const retryDocView = getFirstDocView(resolvedTarget); // test again for the target view snce we presumably created the context above by focusing on it + const retryDocView = this.getFirstDocumentView(resolvedTarget); // test again for the target view snce we presumably created the context above by focusing on it if (retryDocView) { // we found the target in the context. Doc.linkFollowHighlight(retryDocView.rootDoc); @@ -316,10 +316,20 @@ export class DocumentManager { } } // there's no context view so we need to create one first and try again when that finishes - const finishFunc = () => this.jumpToDocument(targetDoc, true, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished, originalTarget); createViewFunc( targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target - finishFunc + () => + this.jumpToDocument( + targetDoc, + true, + (doc: Doc, finished?: () => void) => doc !== targetDocContext && createViewFunc(doc, finished), + docContext, + linkDoc, + true /* if target not found, get rid of context just created */, + undefined, + finished, + originalTarget + ) ); } } diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 1608a77f2..c09c9d1c5 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -30,11 +30,10 @@ export class LinkFollower { const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { const createTabForTarget = (didFocus: boolean) => new Promise(res => { - const where = LightboxView.LightboxDoc ? 'lightbox' : StrCast(sourceDoc.followLinkLocation, followLoc); + const where = LightboxView.LightboxDoc ? 'inPlace' : StrCast(sourceDoc.followLinkLocation, followLoc); docViewProps.addDocTab(doc, where); setTimeout(() => { - const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; - const targDocView = getFirstDocView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. + const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. if (targDocView) { targDocView.props.focus(doc, { willZoom: BoolCast(sourceDoc.followLinkZoom, false), @@ -110,7 +109,7 @@ export class LinkFollower { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; } const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; - DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'lightbox'), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished); + DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished); } } else { allFinished(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a110bf51a..36875290e 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -458,7 +458,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
) : null} - {Doc.noviceMode ? null :
{this.recordButton}
} { Doc.noviceMode ? null :
{this.templateButton}
/*
@@ -467,6 +466,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV } {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
+
{this.recordButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : (
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 91773419a..5660a34e9 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -4,7 +4,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { InkTool } from '../../fields/InkField'; -import { Cast, NumCast, StrCast } from '../../fields/Types'; +import { List } from '../../fields/List'; +import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../Utils'; import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; @@ -141,6 +142,11 @@ export class LightboxView extends React.Component { } } public static AddDocTab = (doc: Doc, location: string, layoutTemplate?: Doc, openInTabFunc?: any) => { + const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + if (inPlaceView) { + inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } LightboxView.openInTabFunc = openInTabFunc; SelectionManager.DeselectAll(); return LightboxView.SetLightboxDoc( diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9648a7807..987bfc23d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -690,11 +690,11 @@ export class MainView extends React.Component { switch (locationFields[0]) { default: case 'inPlace': + case 'lightbox': return LightboxView.AddDocTab(doc, location); case 'add': return CollectionDockingView.AddSplit(doc, locationParams); case 'dashboard': return DashboardView.openDashboard(doc); case 'close': return CollectionDockingView.CloseSplit(doc, locationParams); case 'fullScreen': return CollectionDockingView.OpenFullScreen(doc); - case 'lightbox': return LightboxView.AddDocTab(doc, location); case 'toggle': return CollectionDockingView.ToggleSplit(doc, locationParams); } }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 842664402..1f161c01b 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -95,7 +95,6 @@ export class PropertiesView extends React.Component { //Pres Trails booleans: @observable openPresTransitions: boolean = false; - @observable openPresProgressivize: boolean = false; @observable openAddSlide: boolean = false; @observable openSlideOptions: boolean = false; @@ -1651,19 +1650,6 @@ export class PropertiesView extends React.Component { {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null}
)} - {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) :
-
this.openPresProgressivize = !this.openPresProgressivize)} - style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}> -     Progressivize -
- -
-
- {this.openPresProgressivize ?
- {PresBox.Instance.progressivizeDropdown} -
: null} -
} */} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : (
{ // // TabDocView.PinDoc(doc, { hidePresBox: true }); // return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); // } + case 'inPlace': + const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + if (inPlaceView) { + inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } case 'lightbox': return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); case 'toggle': return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack); - case 'inPlace': case 'add': default: return CollectionDockingView.AddSplit(doc, locationParams, this.stack); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index d80fcdfc3..7a7ae3f40 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -96,37 +96,6 @@ border-color: #69a5db; } -.progressivizeButton { - position: absolute; - display: grid; - grid-template-columns: auto 20px auto; - transform: translate(-105%, 0); - align-items: center; - border: black solid 1px; - border-radius: 3px; - justify-content: center; - width: 40; - z-index: 30000; - height: 20; - overflow: hidden; - background-color: #d5dce2; - transition: all 1s; - - .progressivizeButton-prev:hover { - color: #5a9edd; - } - - .progressivizeButton-frame { - justify-self: center; - text-align: center; - width: 15px; - } - - .progressivizeButton-next:hover { - color: #5a9edd; - } -} - .resizable { background: rgba(0, 0, 0, 0.2); width: 100px; @@ -178,25 +147,6 @@ } } -.progressivizeMove-frame { - width: 20px; - border-radius: 2px; - z-index: 100000; - color: white; - text-align: center; - background-color: #5a9edd; - transform: translate(-110%, 110%); -} - -.progressivizeButton:hover { - box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5); - - .progressivizeButton-frame { - background-color: #5a9edd; - color: white; - } -} - .collectionFreeform-customText { position: absolute; text-align: center; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d44c2f160..e24b116d0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,5 +1,5 @@ import { Bezier } from 'bezier-js'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -71,6 +71,9 @@ export class CollectionFreeFormView extends CollectionSubView (CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.getPaths(this.rootDoc) : null); + @computed get marqueeView() { TraceMobx(); return ( @@ -1912,8 +1917,7 @@ export class CollectionFreeFormView extends CollectionSubView @@ -2039,8 +2043,7 @@ interface CollectionFreeFormViewPannableContentsProps { viewDefDivClick?: ScriptField; children: () => JSX.Element[]; transition?: string; - presPaths?: boolean; - progressivize?: boolean; + presPaths: () => JSX.Element | null; presPinView?: boolean; isAnnotationOverlay: boolean | undefined; isAnnotationOverlayScrollable: boolean | undefined; @@ -2093,42 +2096,11 @@ class CollectionFreeFormViewPannableContents extends React.Component -
-
-
-
-
-
-
- ); - } - } - - @computed get zoomProgressivize() { - return PresBox.Instance?.activeItem?.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : null; - } - - @computed get progressivize() { - return PresBox.Instance && this.props.progressivize ? PresBox.Instance.progressivizeChildDocs : null; - } - @computed get presPaths() { - const presPaths = 'presPaths' + (this.props.presPaths ? '' : '-hidden'); - return !PresBox.Instance || !this.props.presPaths ? null : ( + return !this.props.presPaths() ? null : ( <> -
{PresBox.Instance.order}
- +
{PresBox.Instance?.order}
+ @@ -2140,7 +2112,7 @@ class CollectionFreeFormViewPannableContents extends React.Component - {PresBox.Instance.paths} + {this.props.presPaths()} ); @@ -2180,8 +2152,6 @@ class CollectionFreeFormViewPannableContents extends React.Component )} {this.presPaths} - {this.progressivize} - {this.zoomProgressivize}
); } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 465dbfe6d..e5a2d9007 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -9,7 +9,7 @@ import { DragManager, dropActionType } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; -import { DocumentView } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; import ResizeBar from './MulticolumnResizer'; @@ -241,9 +241,9 @@ export class CollectionMulticolumnView extends CollectionSubView() { } return this.props.addDocTab(doc, where); }; - isContentActive = () => this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => - ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; + focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options); + isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); + isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false); getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return ( this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => - ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; + focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options); + isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); + isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false); getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return ( .documentView-titleWrapper-hover { display: inline-block; } - } - - > .documentView-styleWrapper { + > .documentView-contentsView { + opacity: 0.5; + } > .documentView-captionWrapper { opacity: 1; } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 9e3b42cf6..b495a9399 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -93,7 +93,6 @@ export class PresBox extends ViewBoxBaseComponent() { @observable _expandBoolean: boolean = false; @observable _transitionTools: boolean = false; @observable _newDocumentTools: boolean = false; - @observable _progressivizeTools: boolean = false; @observable _openMovementDropdown: boolean = false; @observable _openEffectDropdown: boolean = false; @observable _presentTools: boolean = false; @@ -206,8 +205,7 @@ export class PresBox extends ViewBoxBaseComponent() { targetDoc._viewTransition = 'all 1s'; setTimeout(() => (targetDoc._viewTransition = undefined), 1010); this.nextKeyframe(targetDoc, activeItem); - if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc); - else targetDoc.keyFrameEditing = true; + targetDoc.keyFrameEditing = true; }; _mediaTimer!: [NodeJS.Timeout, Doc]; @@ -246,22 +244,13 @@ export class PresBox extends ViewBoxBaseComponent() { // Called when the user activates 'next' - to move to the next part of the pres. trail @action next = () => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const lastFrame = Cast(targetDoc?.lastFrame, 'number', null); - const curFrame = NumCast(targetDoc?._currentFrame); - let internalFrames: boolean = false; - if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true; - if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) { - // Case 1: There are still other frames and should go through all frames before going to next slide - this.nextInternalFrame(targetDoc, activeItem); - } else if (this.childDocs[this.itemIndex + 1] !== undefined) { - // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide + if (this.childDocs[this.itemIndex + 1] !== undefined) { + // Case 1: No more frames in current doc and next slide is defined, therefore move to next slide const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]); const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex; this.nextSlide(curLast + 1); } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { - // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode + // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode this.nextSlide(0); } return this.itemIndex; @@ -551,51 +540,6 @@ export class PresBox extends ViewBoxBaseComponent() { } } - /** - * Uses the viewfinder to progressivize through the different views of a single collection. - * @param activeItem: document for which internal zoom is used - */ - zoomProgressivizeNext = (activeItem: Doc) => { - const targetDoc: Doc = this.targetDoc; - const srcContext = Cast(targetDoc?.context, Doc, null); - const docView = DocumentManager.Instance.getDocumentView(targetDoc); - const vfLeft = this.checkList(targetDoc, activeItem['viewfinder-left-indexed']); - const vfWidth = this.checkList(targetDoc, activeItem['viewfinder-width-indexed']); - const vfTop = this.checkList(targetDoc, activeItem['viewfinder-top-indexed']); - const vfHeight = this.checkList(targetDoc, activeItem['viewfinder-height-indexed']); - // Case 1: document that is not a Golden Layout tab - if (srcContext) { - const srcDocView = DocumentManager.Instance.getDocumentView(srcContext); - if (srcDocView) { - const layoutdoc = Doc.Layout(targetDoc); - const panelWidth: number = srcDocView.props.PanelWidth(); - const panelHeight: number = srcDocView.props.PanelHeight(); - const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2; - const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2; - const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight); - srcContext._panX = newPanX + (vfLeft + vfWidth / 2); - srcContext._panY = newPanY + (vfTop + vfHeight / 2); - srcContext._viewScale = newScale; - } - } - // Case 2: document is the containing collection - if (docView && !srcContext) { - const panelWidth: number = docView.props.PanelWidth(); - const panelHeight: number = docView.props.PanelHeight(); - const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight); - targetDoc._panX = vfLeft + vfWidth / 2; - targetDoc._panY = vfTop + vfWidth / 2; - targetDoc._viewScale = newScale; - } - const resize = document.getElementById('resizable'); - if (resize) { - resize.style.width = vfWidth + 'px'; - resize.style.height = vfHeight + 'px'; - resize.style.top = vfTop + 'px'; - resize.style.left = vfLeft + 'px'; - } - }; - /** * For 'Hide Before' and 'Hide After' buttons making sure that * they are hidden each time the presentation is updated. @@ -643,6 +587,7 @@ export class PresBox extends ViewBoxBaseComponent() { //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc @action startAutoPres = async (startSlide: number) => { + if (!this.childDocs.length) return; this.layoutDoc.presStatus = PresStatus.Autoplay; this.startPresentation(startSlide + 1 === this.childDocs.length ? 0 : startSlide); clearTimeout(this._presTimer); @@ -682,14 +627,9 @@ export class PresBox extends ViewBoxBaseComponent() { }; // The function allows for viewing the pres path on toggle - @action togglePath = (srcContext: Doc, off?: boolean) => { - if (off) { - this._pathBoolean = false; - srcContext.presPathView = false; - } else { - runInAction(() => (this._pathBoolean = !this._pathBoolean)); - srcContext.presPathView = this._pathBoolean; - } + @action togglePath = (off?: boolean) => { + this._pathBoolean = off ? false : !this._pathBoolean; + CollectionFreeFormView.ShowPresPaths = this._pathBoolean; }; // The function allows for expanding the view of pres on toggle @@ -1014,17 +954,6 @@ export class PresBox extends ViewBoxBaseComponent() { } }; - /** - * - */ - @action - viewPaths = () => { - const srcContext = Cast(this.rootDoc.presCollection, Doc, null); - if (srcContext) { - this.togglePath(srcContext); - } - }; - getAllIndexes = (arr: Doc[], val: Doc) => arr.map((doc, i) => (doc === val ? i : -1)).filter(i => i !== -1); // Adds the index in the pres path graphically @@ -1104,16 +1033,14 @@ export class PresBox extends ViewBoxBaseComponent() { */ @computed get paths() { let pathPoints = ''; - const presCollection = Cast(this.rootDoc.presCollection, Doc, null); this.childDocs.forEach((doc, index) => { const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); - const srcContext = Cast(tagDoc?.context, Doc, null); - if (tagDoc && presCollection === srcContext) { + if (tagDoc) { const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2; const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2; if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; - } else if (doc.presPinView && presCollection === tagDoc) { + } else if (doc.presPinView) { const n1x = NumCast(doc.presPinViewX); const n1y = NumCast(doc.presPinViewY); if ((index = 0)) pathPoints = n1x + ',' + n1y; @@ -1137,6 +1064,7 @@ export class PresBox extends ViewBoxBaseComponent() { /> ); } + getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection // Converts seconds to ms and updates presTransition setTransitionTime = (number: String, change?: number) => { @@ -1840,7 +1768,6 @@ export class PresBox extends ViewBoxBaseComponent() { // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0); // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); } - // if (tagDoc.editScrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame); CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc); tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1); tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame)); @@ -1882,123 +1809,6 @@ export class PresBox extends ViewBoxBaseComponent() { @observable private openActiveColorPicker: boolean = false; @observable private openViewedColorPicker: boolean = false; - @computed get progressivizeDropdown() { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - if (activeItem && targetDoc) { - const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black'; - const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black'; - return ( -
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> -
- {this.stringType} selected -
-
- Contents -
-
- Edit -
-
-
-
Active text color
-
{ - this.openActiveColorPicker = !this.openActiveColorPicker; - })}>
-
- {this.activeColorPicker} -
-
Viewed font color
-
(this.openViewedColorPicker = !this.openViewedColorPicker))}>
-
- {this.viewedColorPicker} -
-
- Zoom -
-
- Edit -
-
-
-
- Scroll -
-
- Edit -
-
-
-
- Frames -
-
-
{ - e.stopPropagation(); - this.prevKeyframe(targetDoc, activeItem); - }}> - -
-
(targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}> - {NumCast(targetDoc._currentFrame)} -
-
{ - e.stopPropagation(); - this.nextKeyframe(targetDoc, activeItem); - }}> - -
-
- -
{'Last frame'}
- - }> -
{NumCast(targetDoc.lastFrame)}
-
-
-
- {this.frameListHeader} - {this.frameList} -
-
console.log(' TODO: play frames')}> - Play -
-
-
- ); - } - } - @undoBatch @action switchActive = (color: ColorState) => { @@ -2033,262 +1843,7 @@ export class PresBox extends ViewBoxBaseComponent() { } @action - turnOffEdit = (paths?: boolean) => { - // Turn off paths - if (paths) { - const srcContext = Cast(this.rootDoc.presCollection, Doc, null); - if (srcContext) this.togglePath(srcContext, true); - } - // Turn off the progressivize editors for each document - this.childDocs.forEach(doc => { - doc.editSnapZoomProgressivize = false; - doc.editZoomProgressivize = false; - const targetDoc = Cast(doc.presentationTargetDoc, Doc, null); - if (targetDoc) { - targetDoc.editZoomProgressivize = false; - // targetDoc.editScrollProgressivize = false; - } - }); - }; - - //Toggle whether the user edits or not - @action - editZoomProgressivize = (e: React.MouseEvent) => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - if (!targetDoc.editZoomProgressivize) { - if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; - targetDoc.zoomProgressivize = true; - targetDoc.editZoomProgressivize = true; - activeItem.editZoomProgressivize = true; - } else { - targetDoc.editZoomProgressivize = false; - activeItem.editZoomProgressivize = false; - } - }; - - //Toggle whether the user edits or not - @action - editScrollProgressivize = (e: React.MouseEvent) => { - const targetDoc: Doc = this.targetDoc; - if (!targetDoc.editScrollProgressivize) { - if (!targetDoc.scrollProgressivize) { - targetDoc.scrollProgressivize = true; - this.activeItem.scrollProgressivize = true; - } - targetDoc.editScrollProgressivize = true; - } else { - targetDoc.editScrollProgressivize = false; - } - }; - - //Progressivize Zoom - @action - progressivizeScroll = (e: React.MouseEvent) => { - e.stopPropagation(); - this.activeItem.scrollProgressivize = !this.activeItem.scrollProgressivize; - const targetDoc: Doc = this.targetDoc; - targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize; - // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame)); - if (targetDoc.editScrollProgressivize) { - targetDoc.editScrollProgressivize = false; - targetDoc._currentFrame = 0; - targetDoc.lastFrame = 0; - } - }; - - //Progressivize Zoom - @action - progressivizeZoom = (e: React.MouseEvent) => { - e.stopPropagation(); - const activeItem: Doc = this.activeItem; - activeItem.zoomProgressivize = !activeItem.zoomProgressivize; - const targetDoc: Doc = this.targetDoc; - targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize; - CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc); - if (activeItem.editZoomProgressivize) { - activeItem.editZoomProgressivize = false; - targetDoc._currentFrame = 0; - targetDoc.lastFrame = 0; - } - }; - - //Progressivize Child Docs - @action - editProgressivize = (e: React.MouseEvent) => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - targetDoc._currentFrame = targetDoc.lastFrame; - if (!targetDoc.editProgressivize) { - if (!activeItem.presProgressivize) { - activeItem.presProgressivize = true; - targetDoc.presProgressivize = true; - } - targetDoc.editProgressivize = true; - } else { - targetDoc.editProgressivize = false; - } - }; - - @action - progressivizeChild = (e: React.MouseEvent) => { - e.stopPropagation(); - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); - if (!activeItem.presProgressivize) { - targetDoc.keyFrameEditing = false; - activeItem.presProgressivize = true; - targetDoc.presProgressivize = true; - targetDoc._currentFrame = 0; - docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true)); - targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1; - } else { - // targetDoc.editProgressivize = false; - activeItem.presProgressivize = false; - targetDoc.presProgressivize = false; - targetDoc._currentFrame = 0; - targetDoc.keyFrameEditing = true; - } - }; - - @action - checkMovementLists = (doc: Doc, xlist: any, ylist: any) => { - const x: List = xlist; - const y: List = ylist; - const tags: JSX.Element[] = []; - let pathPoints = ''; //List of all of the pathpoints that need to be added - for (let i = 0; i < x.length - 1; i++) { - if (y[i] || x[i]) { - if (i === 0) pathPoints = x[i] - 11 + ',' + (y[i] + 33); - else pathPoints = pathPoints + ' ' + (x[i] - 11) + ',' + (y[i] + 33); - tags.push( -
- {i} -
- ); - } - } - tags.push( - - - - ); - return tags; - }; - - @observable - toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement); - - @action - checkList = (doc: Doc, list: any): number => { - const x: List = list; - if (x?.length >= NumCast(doc._currentFrame) + 1) { - return x[NumCast(doc._currentFrame)]; - } else if (x) { - x.length = NumCast(doc._currentFrame) + 1; - x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1]; - return x[NumCast(doc._currentFrame)]; - } - return 100; - }; - - @computed get progressivizeChildDocs() { - const targetDoc: Doc = this.targetDoc; - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); - const tags: JSX.Element[] = []; - docs.forEach((doc, index) => { - if (doc['x-indexed'] && doc['y-indexed']) { - tags.push(
{this.checkMovementLists(doc, doc['x-indexed'], doc['y-indexed'])}
); - } - tags.push( -
{ - if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; - }} - onPointerOver={() => { - if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; - }} - onClick={e => { - this.toggleDisplayMovement(doc); - e.stopPropagation(); - }} - style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : '#c8c8c8', top: NumCast(doc.y), left: NumCast(doc.x) }}> -
- { - e.stopPropagation(); - this.prevAppearFrame(doc, index); - }} - /> -
-
{NumCast(doc.appearFrame)}
-
- { - e.stopPropagation(); - this.nextAppearFrame(doc, index); - }} - /> -
-
- ); - }); - return tags; - } - - @action - nextAppearFrame = (doc: Doc, i: number) => { - doc.appearFrame = (Cast(doc.appearFrame, 'number', null) ?? 0) + 1; - this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); - }; - - @action - prevAppearFrame = (doc: Doc, i: number) => { - doc.appearFrame = Math.max(0, (Cast(doc.appearFrame, 'number', null) ?? 0) - 1); - this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); - }; - - @action - updateOpacityList = (list: any, frame: number) => { - const x: List = list; - if (x && x.length >= frame) { - for (let i = 0; i < x.length; i++) { - if (i < frame) { - x[i] = 0; - } else if (i >= frame) { - x[i] = 1; - } - } - list = x; - } else { - x.length = frame + 1; - for (let i = 0; i < x.length; i++) { - if (i < frame) { - x[i] = 0; - } else if (i >= frame) { - x[i] = 1; - } - } - list = x; - } - }; + turnOffEdit = (paths?: boolean) => paths && this.togglePath(true); // Turn off paths @computed get toolbarWidth(): number { @@ -2311,11 +1866,11 @@ export class PresBox extends ViewBoxBaseComponent() {
*/} - {'View paths'}
}> + View paths
}>
1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }} + style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }} className={'toolbar-button'} - onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}> + onClick={this.childDocs.length > 1 ? () => this.togglePath() : undefined}>
-- cgit v1.2.3-70-g09d2 From 19f317bd43a7cc8df0daf1c0642011cc8754e14b Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 15 Nov 2022 12:49:53 -0500 Subject: made InPlace container tool button apply more settings to be more like a template. added followAllLInks flag. added image anchors to save pan zoom. added follow link button bar option for follow all links. added hideDecorations flag and property --- src/client/documents/Documents.ts | 5 ++ src/client/util/LinkFollower.ts | 11 ++-- src/client/views/DocumentButtonBar.scss | 31 ++++++++++- src/client/views/DocumentButtonBar.tsx | 60 +++++++++++++++------- src/client/views/DocumentDecorations.tsx | 19 +++---- src/client/views/PropertiesButtons.tsx | 17 ++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/linking/LinkEditor.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/ImageBox.tsx | 52 ++++++++++++++++--- src/client/views/nodes/trails/PresBox.tsx | 3 +- 11 files changed, 154 insertions(+), 50 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e44004f45..8f45802fe 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -257,6 +257,7 @@ export class DocumentOptions { lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide) activeFrame?: number; // the active frame of a document in a frame base collection appearFrame?: number; // the frame in which the document appears + viewTransitionTime?: number; // transition duration for view parameters presTransition?: number; //the time taken for the transition TO a document presDuration?: number; //the duration of the slide in presentation view borderRounding?: string; @@ -1047,6 +1048,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); } + export function ImageanchorDocument(options: DocumentOptions = {}, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); + } + export function HTMLAnchorDocument(documents: Array, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), options, id); } diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index c09c9d1c5..c6fc7b372 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,6 +1,7 @@ import { action, runInAction } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { BoolCast, Cast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, DocCast, StrCast } from '../../fields/Types'; +import { DocumentType } from '../documents/DocumentTypes'; import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; import { DocumentViewSharedProps, ViewAdjustment } from '../views/nodes/DocumentView'; @@ -76,11 +77,11 @@ export class LinkFollower { const linkDocs = link ? [link] : DocListCast(sourceDoc.links); const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor1 const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor2 - const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0); - const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0); + const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor2 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor2 as Doc).annotationOn) : (d.anchor2 as Doc)).length === 0); + const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor1 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor1 as Doc).annotationOn) : (d.anchor1 as Doc)).length === 0); const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView; - const linkDocList = linkWithoutTargetDoc ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs; - const followLinks = sourceDoc.isPushpin ? linkDocList : linkDocList.slice(0, 1); + const linkDocList = linkWithoutTargetDoc && !sourceDoc.followAllLinks ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs; + const followLinks = sourceDoc.isPushpin || sourceDoc.followAllLinks ? linkDocList : linkDocList.slice(0, 1); var count = 0; const allFinished = () => ++count === followLinks.length && finished?.(); followLinks.forEach(async linkDoc => { diff --git a/src/client/views/DocumentButtonBar.scss b/src/client/views/DocumentButtonBar.scss index 1e93ba5e2..f9c988fdd 100644 --- a/src/client/views/DocumentButtonBar.scss +++ b/src/client/views/DocumentButtonBar.scss @@ -18,15 +18,44 @@ $linkGap: 3px; cursor: pointer; } +.documentButtonBar-followTypes, .documentButtonBar-pinTypes { position: absolute; - display: flex; + display: none; width: 60px; top: -14px; background: black; height: 20px; align-items: center; } +.documentButtonBar-followTypes { + width: 20px; + display: none; +} +.documentButtonBar-followIcon { + align-items: center; + display: flex; + height: 100%; + &:hover { + background-color: lightblue; + } +} +.documentButtonBar-follow { + &:hover { + .documentButtonBar-followTypes { + display: flex; + } + } +} +.documentButtonBar-pin { + color: white; + &:hover { + .documentButtonBar-pinTypes { + display: flex; + } + } +} + .documentButtonBar-pinIcon { &:hover { background-color: lightblue; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 36875290e..794b51cc5 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -5,7 +5,7 @@ import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; -import { Cast, NumCast } from '../../fields/Types'; +import { BoolCast, Cast, NumCast } from '../../fields/Types'; import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; @@ -209,21 +209,52 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } + @observable subFollow = ''; @computed get followLinkButton() { const targetDoc = this.view0?.props.Document; + const followBtn = (allDocs: boolean, click: (doc: Doc) => void, isSet: (doc?: Doc) => boolean, icon: IconProp) => { + const tooltip = `Follow ${this.subPin}documents`; + return !tooltip ? null : ( + {tooltip}
}> +
+ (this.subPin = allDocs ? 'All ' : ''))} + onPointerLeave={action(e => (this.subPin = ''))} + onClick={e => { + this.props.views().forEach(dv => click(dv!.rootDoc)); + e.stopPropagation(); + }} + /> +
+ + ); + }; return !targetDoc ? null : ( - {'Set onClick to follow primary link'}
}> + Set onClick to follow primary link}>
this.props.views().map(view => view?.docView?.toggleFollowLink(undefined, undefined, false)))}> +
+ {followBtn( + true, + (doc: Doc) => (doc.followAllLinks = !doc.followAllLinks), + (doc?: Doc) => (doc?.followAllLinks ? true : false), + 'window-maximize' + )} +
); } - @observable expandPin = false; + @observable subPin = ''; @computed get pinButton() { @@ -264,10 +295,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV return !targetDoc ? null : ( {`Pin Document ${SelectionManager.Views().length > 1 ? 'multiple documents' : ''} to Trail`}}>
(this.expandPin = true))} - onPointerLeave={action(e => (this.expandPin = false))} + className="documentButtonBar-icon documentButtonBar-pin" onClick={e => { const docs = this.props .views() @@ -276,13 +304,11 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV TabDocView.PinDoc(docs, { pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); e.stopPropagation(); }}> - {this.expandPin ? ( -
- {pinBtn(true, false, 'window-maximize')} - {pinBtn(false, true, 'address-card')} - {pinBtn(true, true, 'id-card')} -
- ) : null} +
+ {pinBtn(true, false, 'window-maximize')} + {pinBtn(false, true, 'address-card')} + {pinBtn(true, true, 'id-card')} +
@@ -460,9 +486,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ) : null} { Doc.noviceMode ? null :
{this.templateButton}
- /*
- {this.metadataButton} -
*/ + /*
{this.metadataButton}
*/ } {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3fac137fe..3efb5fb37 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -708,24 +708,25 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } render() { - const { b, c, r, x, y } = this.Bounds; - const bounds = { b, c, r, x, y }; + const { b, r, x, y } = this.Bounds; + const bounds = { b, r, x, y }; const seldocview = SelectionManager.Views().slice(-1)[0]; if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { return null; } // hide the decorations if the parent chooses to hide it or if the document itself hides it - const hideResizers = seldocview.props.hideResizeHandles || seldocview.rootDoc.hideResizeHandles || seldocview.rootDoc._isGroup || this._isRounding || this._isRotating; - const hideTitle = seldocview.props.hideDecorationTitle || seldocview.rootDoc.hideDecorationTitle || this._isRounding || this._isRotating; - const hideDocumentButtonBar = seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating; + const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations; + const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.hideResizeHandles || seldocview.rootDoc._isGroup || this._isRounding || this._isRotating; + const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.hideDecorationTitle || this._isRounding || this._isRotating; + const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating; // if multiple documents have been opened at the same time, then don't show open button - const hideOpenButton = + const hideOpenButton =hideDecorations || seldocview.props.hideOpenButton || seldocview.rootDoc.hideOpenButton || SelectionManager.Views().some(docView => docView.props.Document._stayInCollection || docView.props.Document.isGroup || docView.props.Document.hideOpenButton) || this._isRounding || this._isRotating; - const hideDeleteButton = + const hideDeleteButton =hideDecorations || this._isRounding || this._isRotating || seldocview.props.hideDeleteButton || @@ -767,7 +768,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); const useLock = bounds.r - bounds.x > 135 && seldocview.props.CollectionFreeFormDocumentView; - const useRotation = seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.props.CollectionFreeFormDocumentView; // when do we want an object to not rotate? + const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.props.CollectionFreeFormDocumentView; // when do we want an object to not rotate? const rotation = NumCast(seldocview.rootDoc._rotation); const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : ''; @@ -837,7 +838,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
{hideDeleteButton ?
: topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} {hideResizers || hideDeleteButton ?
: topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} - {titleArea} + {hideTitle ? null : titleArea} {hideOpenButton ?
: topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
{hideResizers ? null : ( diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 5992b3eb9..d27848a90 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -121,15 +121,24 @@ export class PropertiesButtons extends React.Component<{}, {}> { onClick => { SelectionManager.Views().forEach(dv => { const containerDoc = dv.rootDoc; - containerDoc.noShadow = containerDoc.noHighlighting = containerDoc._isLinkButton = containerDoc._fitContentsToBox = containerDoc._forceActive = containerDoc._isInPlaceContainer = !containerDoc._isInPlaceContainer; + containerDoc.followAllLinks = + containerDoc.noShadow = + containerDoc.noHighlighting = + containerDoc._isLinkButton = + containerDoc._fitContentsToBox = + containerDoc._forceActive = + containerDoc._isInPlaceContainer = + !containerDoc._isInPlaceContainer; containerDoc.followLinkLocation = containerDoc._isInPlaceContainer ? 'inPlace' : undefined; containerDoc._xPadding = containerDoc._yPadding = containerDoc._isInPlaceContainer ? 10 : undefined; const menuDoc = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]).lastElement(); if (menuDoc) { - menuDoc._forceActive = menuDoc._fitContentsToBox = menuDoc._isLinkButton = menuDoc._noShadow = menuDoc.noHighlighting = containerDoc._isInPlaceContainer; - DocUtils.MakeLink({ doc: dv.rootDoc }, { doc: menuDoc }, 'back link to container'); + menuDoc.hideDecorations = menuDoc._forceActive = menuDoc._fitContentsToBox = menuDoc._isLinkButton = menuDoc._noShadow = menuDoc.noHighlighting = containerDoc._isInPlaceContainer; + if (!dv.allLinks.find(link => link.anchor1 === menuDoc || link.anchor2 === menuDoc)) { + DocUtils.MakeLink({ doc: dv.rootDoc }, { doc: menuDoc }, 'back link to container'); + } DocListCast(menuDoc[Doc.LayoutFieldKey(menuDoc)]).forEach(menuItem => { - menuItem._isLinkButton = true; + menuItem.followAllLinks = menuItem._isLinkButton = true; menuItem._followLinkLocation = 'inPlace'; }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e24b116d0..8fe5ad63f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1157,7 +1157,7 @@ export class CollectionFreeFormView extends CollectionSubView { @computed get editAudioFollow() { //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS - console.log('AudioFollow:' + this.audioFollow); return (
Play Target Audio:
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7accd49a4..76d6d3532 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -166,7 +166,8 @@ export interface DocumentViewSharedProps { // these props are specific to DocuentViews export interface DocumentViewProps extends DocumentViewSharedProps { // properties specific to DocumentViews but not to FieldView - hideResizeHandles?: boolean; // whether to suppress DocumentDecorations when this document is selected + hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected + hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings hideDecorationTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings hideDocumentButtonBar?: boolean; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d0df41023..d67481b22 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -14,7 +14,7 @@ import { TraceMobx } from '../../../fields/util'; import { emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; -import { DocUtils } from '../../documents/Documents'; +import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; @@ -49,21 +49,58 @@ export class ImageBox extends ViewBoxAnnotatableComponent) => Opt = () => undefined; @observable _curSuffix = ''; @observable _uploadIcon = uploadIcons.idle; + @observable _focusViewScale: number | undefined = 1; + @observable _focusPanX: number | undefined = 0; + @observable _focusPanY: number | undefined = 0; + get viewScale() { + return this._focusViewScale || StrCast(this.layoutDoc._viewScale); + } + get panX() { + return this._focusPanX || StrCast(this.layoutDoc._panX); + } + get panY() { + return this._focusPanY || StrCast(this.layoutDoc._panY); + } protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document)); }; - setViewSpec = (anchor: Doc, preview: boolean) => {}; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document + + @action + setViewSpec = (anchor: Doc, preview: boolean) => { + if (preview && anchor._viewScale !== undefined) { + this._focusViewScale = Cast(anchor._viewScale, 'number', null); + this._focusPanX = Cast(anchor._panX, 'number', null); + this._focusPanY = Cast(anchor._panX, 'number', null); + } else if (anchor._viewScale !== undefined) { + const smoothTime = NumCast(anchor.viewTransitionTime); + this.layoutDoc.viewTransition = `all ${smoothTime}ms`; + this.layoutDoc._panX = NumCast(anchor._panX, NumCast(this.layoutDoc._panY)); + this.layoutDoc._panY = NumCast(anchor._panY, NumCast(this.layoutDoc._panX)); + this.layoutDoc._viewScale = NumCast(anchor._viewScale, NumCast(this.layoutDoc._viewScale)); + if (anchor.type === DocumentType.MARKER) { + this.dataDoc[this.annotationKey] = new List(DocListCast(anchor._annotations)); + } + clearTimeout(this._transitioning); + this._transitioning = setTimeout(() => (this.layoutDoc.viewTransition = undefined), smoothTime); + } + }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document getAnchor = () => { - const anchor = this._getAnchor?.(this._savedAnnotations); - anchor && this.addDocument(anchor); - return anchor ?? this.rootDoc; + const zoomedAnchor = () => Docs.Create.ImageanchorDocument({ viewTransitionTime: 1000, _viewScale: NumCast(this.layoutDoc._viewScale), _panX: NumCast(this.layoutDoc._panX), _panY: NumCast(this.layoutDoc._panY) }); + const anchor = this._getAnchor?.(this._savedAnnotations) ?? (this.layoutDoc.viewScale ? zoomedAnchor() : undefined); + if (anchor) { + anchor._annotations = new List(DocListCast(this.dataDoc[this.annotationKey])); + this.addDocument(anchor); + return anchor; + } + return this.rootDoc; }; componentDidMount() { @@ -90,6 +127,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent disposer?.()); } @@ -283,9 +321,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { this._uploadIcon = idle; - if (data) { - dataDoc[this.fieldKey] = data; - } + data && (dataDoc[this.fieldKey] = data); }), 2000 ); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index b495a9399..8d805c663 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -509,8 +509,7 @@ export class PresBox extends ViewBoxBaseComponent() { static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) { if ((activeItem.presPinLayout || activeItem.presPinView) && DocCast(targetDoc.context)?._currentFrame === undefined) { const transTime = NumCast(activeItem.presTransition, 500); - const presTransitionTime = `all ${transTime}ms`; - targetDoc._dataTransition = presTransitionTime; + targetDoc._dataTransition = `all ${transTime}ms`; targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x)); targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y)); targetDoc.rotation = NumCast(activeItem.presRot, NumCast(targetDoc.rotation)); -- cgit v1.2.3-70-g09d2 From ae324ff50865929be836edf3bbf129207638a9c9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 16 Nov 2022 16:26:31 -0500 Subject: big changes to make link following use the same code as pinning docs for trails. --- src/client/documents/Documents.ts | 1 + src/client/util/DocumentManager.ts | 30 ++--- src/client/util/LinkFollower.ts | 7 +- src/client/views/DocumentButtonBar.tsx | 6 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/MarqueeAnnotator.tsx | 1 + src/client/views/StyleProvider.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 18 ++- src/client/views/nodes/ComparisonBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 8 +- src/client/views/nodes/ImageBox.tsx | 60 ++++------ src/client/views/nodes/PDFBox.tsx | 16 ++- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 131 +++++++++++++-------- src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 11 +- 18 files changed, 178 insertions(+), 129 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8f45802fe..e68b9e27b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -237,6 +237,7 @@ export class DocumentOptions { childContextMenuScripts?: List; childContextMenuLabels?: List; childContextMenuIcons?: List; + followLinkZoom?: boolean; // whether to zoom to the target of a link hideLinkButton?: boolean; // whether the blue link counter button should be hidden hideDecorationTitle?: boolean; hideOpenButton?: boolean; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 9336717c0..a60c1ed6b 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -151,6 +151,21 @@ export class DocumentManager { return toReturn; } + static playAudioAnno(doc: Doc) { + const anno = Cast(doc[Doc.LayoutFieldKey(doc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement(); + if (anno) { + if (anno instanceof AudioField) { + new Howl({ + src: [anno.url.href], + format: ['mp3'], + autoplay: true, + loop: false, + volume: 0.5, + }); + } + } + } + static addView = (doc: Doc, finished?: () => void) => { CollectionDockingView.AddSplit(doc, 'right'); finished?.(); @@ -189,20 +204,6 @@ export class DocumentManager { } else { finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined); !noSelect && docView?.select(false); - if (originatingDoc?.followLinkAudio) { - const anno = Cast(finalTargetDoc[Doc.LayoutFieldKey(finalTargetDoc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement(); - if (anno) { - if (anno instanceof AudioField) { - new Howl({ - src: [anno.url.href], - format: ['mp3'], - autoplay: true, - loop: false, - volume: 0.5, - }); - } - } - } } finished?.(); }; @@ -233,6 +234,7 @@ export class DocumentManager { } if (focusView) { !noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox + if (originatingDoc?.followLinkAudio) DocumentManager.playAudioAnno(focusView.rootDoc); const doFocus = (forceDidFocus: boolean) => focusView.focus(originalTarget ?? targetDoc, { originalTarget, diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index c6fc7b372..68716a207 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -6,6 +6,7 @@ import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; import { DocumentViewSharedProps, ViewAdjustment } from '../views/nodes/DocumentView'; import { DocumentManager } from './DocumentManager'; +import { LinkManager } from './LinkManager'; import { UndoManager } from './UndoManager'; type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; @@ -25,7 +26,7 @@ export class LinkFollower { // follows a link - if the target is on screen, it highlights/pans to it. // if the target isn't onscreen, then it will open up the target in the lightbox, or in place // depending on the followLinkLocation property of the source (or the link itself as a fallback); - public static FollowLink = (linkDoc: Opt, sourceDoc: Doc, docViewProps: DocumentViewSharedProps, altKey: boolean, zoom: boolean = false) => { + public static FollowLink = (linkDoc: Opt, sourceDoc: Doc, docViewProps: DocumentViewSharedProps, altKey: boolean) => { const batch = UndoManager.StartBatch('follow link click'); // open up target if it's not already in view ... const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { @@ -63,7 +64,6 @@ export class LinkFollower { linkDoc, sourceDoc, createViewFunc, - BoolCast(sourceDoc.followLinkZoom, zoom), docViewProps.ContainingCollectionDoc, action(() => { batch.end(); @@ -73,7 +73,7 @@ export class LinkFollower { ); }; - public static traverseLink(link: Opt, sourceDoc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) { + public static traverseLink(link: Opt, sourceDoc: Doc, createViewFunc: CreateViewFunc, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) { const linkDocs = link ? [link] : DocListCast(sourceDoc.links); const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor1 const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor2 @@ -96,6 +96,7 @@ export class LinkFollower { : linkDoc.anchor1 ) as Doc; if (target) { + const zoom = BoolCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkZoom, false); if (target.TourMap) { const fieldKey = Doc.LayoutFieldKey(target); const tour = DocListCast(target[fieldKey]).reverse(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 794b51cc5..681349ccf 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -284,7 +284,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); e.stopPropagation(); }} /> @@ -301,7 +301,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); e.stopPropagation(); }}>
@@ -488,7 +488,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV Doc.noviceMode ? null :
{this.templateButton}
/*
{this.metadataButton}
*/ } - {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
} + {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
{this.recordButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 5a6caf995..4890d9624 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -6,7 +6,7 @@ import { Id } from '../../fields/FieldSymbols'; import { InkTool } from '../../fields/InkField'; import { List } from '../../fields/List'; import { ScriptField } from '../../fields/ScriptField'; -import { Cast, PromiseValue } from '../../fields/Types'; +import { Cast, DocCast, PromiseValue } from '../../fields/Types'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { DocumentType } from '../documents/DocumentTypes'; @@ -245,7 +245,7 @@ export class KeyManager { if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) { SelectionManager.Views()[0].ComponentView?.search?.('', false, false); } else { - const searchBtn = Doc.MySearcher; + const searchBtn = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MySearcher); if (searchBtn) { MainView.Instance.selectMenu(searchBtn); } diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index c0dd62a05..1162cde50 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -93,6 +93,7 @@ export class MarqueeAnnotator extends React.Component { dragComplete: e => { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { e.annoDragData.linkSourceDoc.isPushpin = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, }); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a04f4a4f4..8ee5ebdb6 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -236,7 +236,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : 'linear-gradient(#065fff, #85c1f9)')); diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 7bf798656..39ae470b6 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -748,7 +748,7 @@ class StackedTimelineAnchor extends React.Component time < NumCast(this.props.mark[this.props.endTag]) && this._lastTimecode < NumCast(this.props.mark[this.props.startTag]) - 1e-5 ) { - LinkFollower.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false, true); + LinkFollower.FollowLink(undefined, this.props.mark, this.props as any as DocumentViewProps, false); } this._lastTimecode = time; } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 1a9006356..e21649648 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -229,7 +229,7 @@ export class TabDocView extends React.Component { * Adds a document to the presentation view **/ @action - public static PinDoc(docs: Doc | Doc[], pinProps?: PinProps) { + public static PinDoc(docs: Doc | Doc[], pinProps: PinProps) { const docList = docs instanceof Doc ? [docs] : docs; const batch = UndoManager.StartBatch('pinning doc'); @@ -271,7 +271,7 @@ export class TabDocView extends React.Component { pinDoc.presStartTime = NumCast(doc.clipStart); pinDoc.presEndTime = NumCast(doc.clipEnd, duration); } - PresBox.pinDocView(pinDoc, pinProps, doc); + PresBox.pinDocView(pinDoc, pinProps.pinDocContent ? { ...pinProps, pinData: PresBox.pinDataTypes(doc) } : pinProps, doc); pinDoc.onClick = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)'); Doc.AddDocToList(curPres, 'data', pinDoc, presSelected); //save position diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 932bd789d..8a97797c7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1530,11 +1530,27 @@ export class CollectionFreeFormView extends CollectionSubView { + let focusSpeed: Opt; + PresBox.restoreTargetDocView( + this.rootDoc, // + { pinDocLayout: BoolCast(anchor.presPinDocLayout) }, + anchor, + (focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition)), + { + pannable: anchor.presPinData ? true : false, + } + ); + return focusSpeed; + }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document + getAnchor = () => { if (this.props.Document.annotationOn) { return this.rootDoc; } - const anchor = Docs.Create.TextanchorDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._viewType), annotationOn: this.rootDoc }); + const anchor = Docs.Create.TextanchorDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._viewType), presTransition: 500, annotationOn: this.rootDoc }); + PresBox.pinDocView(anchor, { pinData: { pannable: true } }, this.rootDoc); const proto = Doc.GetProto(anchor); proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType; proto.docFilters = ObjectField.MakeCopy(this.layoutDoc.docFilters as ObjectField) || new List([]); diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index d74da9748..dd03b9b99 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -103,7 +103,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - whichDoc !== targetDoc && r?.focus(whichDoc, {}); + whichDoc !== targetDoc && r?.focus(whichDoc, { instant: true }); }} {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit} isContentActive={returnFalse} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 84cacd919..dc468cf89 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -51,7 +51,7 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { LinkDocPreview } from './LinkDocPreview'; import { RadialMenu } from './RadialMenu'; import { ScriptingBox } from './ScriptingBox'; -import { PresBox } from './trails/PresBox'; +import { PinProps, PresBox } from './trails/PresBox'; import React = require('react'); const { Howl } = require('howler'); @@ -144,7 +144,7 @@ export interface DocumentViewSharedProps { addDocument?: (doc: Doc | Doc[]) => boolean; removeDocument?: (doc: Doc | Doc[]) => boolean; moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; - pinToPres: (document: Doc) => void; + pinToPres: (document: Doc, pinProps: PinProps) => void; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; canEmbedOnDrag?: boolean; @@ -486,7 +486,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(this.props.Document, "add:right"), icon: "trash", selected: -1 }); - RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document), icon: 'map-pin', selected: -1 }); + RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document, {}), icon: 'map-pin', selected: -1 }); RadialMenu.Instance.addItem({ description: 'Open', event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: 'trash', selected: -1 }); SelectionManager.DeselectAll(); @@ -545,7 +545,7 @@ export class DocumentViewInternal extends DocComponent (this.layoutDoc[spec.replace(ViewSpecPrefix, '')] = (field => (field instanceof ObjectField ? ObjectField.MakeCopy(field) : field))(anchor[spec]))); // after a render the general viewSpec should have created the right _componentView, so after a timeout, call the componentview to update its specific view specs setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false)); - const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant === false || !LinkDocPreview.LinkInfo); + const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant !== true && !LinkDocPreview.LinkInfo); const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing; this.props.focus(options?.docTransform ? anchor : this.rootDoc, { ...options, diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 76ba7765c..2e594d96a 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -30,6 +30,8 @@ import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; import React = require('react'); +import { PresBox } from './trails'; +import { DocumentViewProps } from './DocumentView'; export const pageSchema = createSchema({ googlePhotosUrl: 'string', @@ -49,23 +51,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent) => Opt = () => undefined; @observable _curSuffix = ''; @observable _uploadIcon = uploadIcons.idle; - @observable _focusViewScale: number | undefined = 1; - @observable _focusPanX: number | undefined = 0; - @observable _focusPanY: number | undefined = 0; - get viewScale() { - return this._focusViewScale || StrCast(this.layoutDoc._viewScale); - } - get panX() { - return this._focusPanX || StrCast(this.layoutDoc._panX); - } - get panY() { - return this._focusPanY || StrCast(this.layoutDoc._panY); - } protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); @@ -73,33 +62,30 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - if (preview && anchor._viewScale !== undefined) { - this._focusViewScale = Cast(anchor._viewScale, 'number', null); - this._focusPanX = Cast(anchor._panX, 'number', null); - this._focusPanY = Cast(anchor._panX, 'number', null); - } else if (anchor._viewScale !== undefined) { - const smoothTime = NumCast(anchor.viewTransitionTime); - this.layoutDoc.viewTransition = `all ${smoothTime}ms`; - this.layoutDoc._panX = NumCast(anchor._panX, NumCast(this.layoutDoc._panY)); - this.layoutDoc._panY = NumCast(anchor._panY, NumCast(this.layoutDoc._panX)); - this.layoutDoc._viewScale = NumCast(anchor._viewScale, NumCast(this.layoutDoc._viewScale)); - this.layoutDoc[this.fieldKey + '-useAlt'] = Cast(anchor._useAlt, 'boolean', null); - if (anchor.type === DocumentType.MARKER) { - this.dataDoc[this.annotationKey] = new List(DocListCast(anchor._annotations)); - } - clearTimeout(this._transitioning); - this._transitioning = setTimeout(() => (this.layoutDoc.viewTransition = undefined), smoothTime); - } + scrollFocus = (anchor: Doc, smooth: boolean) => { + let focusSpeed: Opt; + PresBox.restoreTargetDocView( + this.rootDoc, // + { pinDocLayout: BoolCast(anchor.presPinDocLayout) }, + anchor, + (focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition)), + !anchor.presPinData + ? {} + : { + pannable: true, + dataannos: anchor.presAnnotations !== undefined, + dataview: true, + } + ); + return focusSpeed; }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document getAnchor = () => { const anchor = this._getAnchor?.(this._savedAnnotations) ?? // use marquee anchor, otherwise, save zoom/pan as anchor - Docs.Create.ImageanchorDocument({ viewTransitionTime: 1000, unrendered: true, annotationOn: this.rootDoc, _viewScale: NumCast(this.layoutDoc._viewScale, 1), _panX: NumCast(this.layoutDoc._panX), _panY: NumCast(this.layoutDoc._panY) }); + Docs.Create.ImageanchorDocument({ presTransition: 1000, unrendered: true, annotationOn: this.rootDoc }); if (anchor) { - anchor._useAlt = Cast(this.layoutDoc[this.fieldKey + '-useAlt'], 'boolean', null); - anchor._annotations = new List(DocListCast(this.dataDoc[this.annotationKey])); + PresBox.pinDocView(anchor, { pinData: { pannable: true, dataview: true, dataannos: true } }, this.rootDoc); this.addDocument(anchor); return anchor; } @@ -130,7 +116,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent disposer?.()); } @@ -425,6 +410,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent this._savedAnnotations; + styleProvider = (doc: Opt, props: Opt, property: string): any => { + if (property === StyleProp.BoxShadow) return undefined; + return this.props.styleProvider?.(doc, props, property); + }; render() { TraceMobx(); @@ -445,6 +434,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { @@ -207,16 +208,19 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - const anchor = - this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations()) ?? - Docs.Create.TextanchorDocument({ + const docAnchor = () => { + const anchor = Docs.Create.TextanchorDocument({ title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)), - y: NumCast(this.layoutDoc._scrollTop), unrendered: true, }); + PresBox.pinDocView(anchor, { pinData: { scrollable: true, pannable: true } }, this.rootDoc); + return anchor; + }; + const anchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations()) ?? docAnchor(); this.addDocument(anchor); return anchor; }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2984feba5..fdd61463d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -686,7 +686,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.props.pinToPres(anchor); + pinToPres = (anchor: Doc) => this.props.pinToPres(anchor, {}); @undoBatch makePushpin = (anchor: Doc) => (anchor.isPushpin = !anchor.isPushpin); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 8d805c663..10f2dc016 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -12,7 +12,8 @@ import { List } from '../../../../fields/List'; import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils'; +import { AudioField } from '../../../../fields/URLField'; +import { emptyFunction, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; @@ -33,6 +34,7 @@ import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresMovement, PresStatus } from './PresEnums'; +const { Howl } = require('howler'); export interface PinProps { audioRange?: boolean; @@ -41,6 +43,17 @@ export interface PinProps { pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected) pinDocLayout?: boolean; // pin layout info (width/height/x/y) pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text) + pinAudioPlay?: boolean; // pin audio annotation + pinData?: { + scrollable?: boolean | undefined; + pannable?: boolean | undefined; + temporal?: boolean | undefined; + clippable?: boolean | undefined; + dataview?: boolean | undefined; + textview?: boolean | undefined; + poslayoutview?: boolean | undefined; + dataannos?: boolean | undefined; + }; } @observer @@ -333,26 +346,37 @@ export class PresBox extends ViewBoxBaseComponent() { this.onHideDocument(); //Handles hide after/before } }); - static pinDataTypes(target: Doc) { + static pinDataTypes(target: Doc): { scrollable?: boolean; pannable?: boolean; temporal?: boolean; clippable?: boolean; dataview?: boolean; textview?: boolean; poslayoutview?: boolean; dataannos?: boolean } { const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking; - const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform); + const pannable = [DocumentType.IMG, DocumentType.PDF].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform); const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any); const clippable = [DocumentType.COMPARISON].includes(target.type as any); const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG].includes(target.type as any) && target.activeFrame === undefined; const poslayoutview = [DocumentType.COL].includes(target.type as any) && target.activeFrame === undefined; const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined; - return { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview }; + const dataannos = false; + return { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview, dataannos }; } @action - static restoreTargetDocView(bestTarget: Doc, activeItem: Doc) { - const transTime = NumCast(activeItem.presTransition, 500); + playAnnotation = (anno: AudioField) => {}; + @action + static restoreTargetDocView(bestTarget: Doc, pinProps: PinProps | undefined, activeItem: Doc, transTime: number, pinDataTypes = this.pinDataTypes(bestTarget)) { const presTransitionTime = `all ${transTime}ms`; - const { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview } = this.pinDataTypes(bestTarget); bestTarget._viewTransition = presTransitionTime; - if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth; - if (temporal) bestTarget._currentTimecode = activeItem.presStartTime; - if (scrollable) { + if (pinProps?.pinDocLayout) { + const transTime = NumCast(activeItem.presTransition, 500); + bestTarget._dataTransition = `all ${transTime}ms`; + bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x)); + bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y)); + bestTarget.rotation = NumCast(activeItem.presRot, NumCast(bestTarget.rotation)); + bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); + bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); + } + if (pinDataTypes.clippable) bestTarget._clipWidth = activeItem.presPinClipWidth; + if (pinDataTypes.temporal) bestTarget._currentTimecode = activeItem.presStartTime; + if (pinDataTypes.scrollable) { bestTarget._scrollTop = activeItem.presPinViewScroll; const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { @@ -360,13 +384,17 @@ export class PresBox extends ViewBoxBaseComponent() { dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }); } } - if (dataview && activeItem.presData !== undefined) { + if (pinDataTypes.dataannos) { + const fkey = Doc.LayoutFieldKey(bestTarget); + Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List(DocListCast(activeItem.presAnnotations)); + } + if (pinDataTypes.dataview && activeItem.presData !== undefined) { const fkey = Doc.LayoutFieldKey(bestTarget); Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; bestTarget[fkey + '-useAlt'] = activeItem.presUseAlt; } - if (textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; - if (poslayoutview) { + if (pinDataTypes.textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; + if (pinDataTypes.poslayoutview) { StrListCast(activeItem.presPinLayoutData) .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) .forEach(data => { @@ -385,7 +413,7 @@ export class PresBox extends ViewBoxBaseComponent() { transTime + 10 ); } - if (pannable) { + if (pinDataTypes.pannable) { const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }; @@ -410,9 +438,8 @@ export class PresBox extends ViewBoxBaseComponent() { /// reserved fields on the pinDoc so that those values can be restored to the /// target doc when navigating to it. @action - static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined, targetDoc: Doc) { - const { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview } = this.pinDataTypes(pinDoc); - if (pinProps?.pinDocLayout) { + static pinDocView(pinDoc: Doc, pinProps: PinProps, targetDoc: Doc) { + if (pinProps.pinDocLayout) { pinDoc.presPinLayout = true; pinDoc.presX = NumCast(targetDoc.x); pinDoc.presY = NumCast(targetDoc.y); @@ -420,33 +447,46 @@ export class PresBox extends ViewBoxBaseComponent() { pinDoc.presWidth = NumCast(targetDoc.width); pinDoc.presHeight = NumCast(targetDoc.height); } - if (pinProps?.pinDocContent) { - pinDoc.presPinData = scrollable || temporal || pannable || clippable || dataview || textview || poslayoutview || pinProps.activeFrame !== undefined; - if (dataview) { + if (pinProps.pinAudioPlay) pinDoc.followLinkAudio = true; + if (pinProps.pinData) { + pinDoc.presPinData = + pinProps.pinData.scrollable || + pinProps.pinData.temporal || + pinProps.pinData.pannable || + pinProps.pinData.clippable || + pinProps.pinData.dataview || + pinProps.pinData.textview || + pinProps.pinData.poslayoutview || + pinProps?.activeFrame !== undefined; + if (pinProps.pinData.dataview) { const fkey = Doc.LayoutFieldKey(targetDoc); pinDoc.presUseAlt = targetDoc[fkey + '-useAlt']; pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; } - if (textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text; - if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop; - if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth; - if (poslayoutview) pinDoc.presPinLayoutData = new List(DocListCast(pinDoc.presData).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) }))); - if (pannable) { - pinDoc.presPinViewX = NumCast(pinDoc._panX); - pinDoc.presPinViewY = NumCast(pinDoc._panY); - pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1); + if (pinProps.pinData.dataannos) { + const fkey = Doc.LayoutFieldKey(targetDoc); + pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations'])); + } + if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text; + if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop; + if (pinProps.pinData.clippable) pinDoc.presPinClipWidth = targetDoc._clipWidth; + if (pinProps.pinData.poslayoutview) pinDoc.presPinLayoutData = new List(DocListCast(targetDoc.presData).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) }))); + if (pinProps.pinData.pannable) { + pinDoc.presPinViewX = NumCast(targetDoc._panX); + pinDoc.presPinViewY = NumCast(targetDoc._panY); + pinDoc.presPinViewScale = NumCast(targetDoc._viewScale, 1); } - if (temporal) { - pinDoc.presStartTime = pinDoc._currentTimecode; - const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(pinDoc.presStartTime) + 0.1); - pinDoc.presEndTime = NumCast(pinDoc.clipEnd, duration); + if (pinProps.pinData.temporal) { + pinDoc.presStartTime = targetDoc._currentTimecode; + const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(targetDoc.presStartTime) + 0.1); + pinDoc.presEndTime = NumCast(targetDoc.clipEnd, duration); } } if (pinProps?.pinViewport) { // If pinWithView option set then update scale and x / y props of slide const bounds = pinProps.pinViewport; pinDoc.presPinView = true; - pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1); + pinDoc.presPinViewScale = NumCast(targetDoc._viewScale, 1); pinDoc.presPinViewX = bounds.left + bounds.width / 2; pinDoc.presPinViewY = bounds.top + bounds.height / 2; pinDoc.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); @@ -507,35 +547,24 @@ export class PresBox extends ViewBoxBaseComponent() { }; static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) { - if ((activeItem.presPinLayout || activeItem.presPinView) && DocCast(targetDoc.context)?._currentFrame === undefined) { - const transTime = NumCast(activeItem.presTransition, 500); - targetDoc._dataTransition = `all ${transTime}ms`; - targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x)); - targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y)); - targetDoc.rotation = NumCast(activeItem.presRot, NumCast(targetDoc.rotation)); - targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width)); - targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height)); - setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10); - } // If openDocument is selected then it should open the document for the user if (activeItem.openDocument) { LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc); } else if (targetDoc && activeItem.presMovement !== PresMovement.None) { LightboxView.SetLightboxDoc(undefined); const zooming = activeItem.presMovement !== PresMovement.Pan; - DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom, 1)); + DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, activeItem, finished, undefined, true, NumCast(activeItem.presZoom, 1)); } else if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); } // After navigating to the document, if it is added as a presPinView then it will // adjust the pan and scale to that of the pinView when it was added. - if (activeItem.presPinData || activeItem.presPinView) { + const pinDocLayout = (BoolCast(activeItem.presPinLayout) || BoolCast(activeItem.presPinView)) && DocCast(targetDoc.context)?._currentFrame === undefined; + if (activeItem.presPinData || activeItem.presPinView || pinDocLayout) { clearTimeout(PresBox._navTimer); // targetDoc may or may not be displayed. this gets the first available document (or alias) view that matches targetDoc const bestTargetView = DocumentManager.Instance.getFirstDocumentView(targetDoc); - const bestTarget = bestTargetView?.props.Document; - if (bestTarget) PresBox._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem); - activeItem.presPinAudioPlay && bestTargetView?.docView?.playAnnotation(); + if (bestTargetView?.props.Document) PresBox._navTimer = PresBox.restoreTargetDocView(bestTargetView?.props.Document, { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500)); } } @@ -747,7 +776,7 @@ export class PresBox extends ViewBoxBaseComponent() { } else { if (!doc.aliasOf) { const original = Doc.MakeAlias(doc); - TabDocView.PinDoc(original); + TabDocView.PinDoc(original, {}); setTimeout(() => this.removeDocument(doc), 0); return false; } else { @@ -1316,7 +1345,7 @@ export class PresBox extends ViewBoxBaseComponent() { Effects
Play Audio Annotation
- (activeItem.presPinAudioPlay = !BoolCast(activeItem.presPinAudioPlay))} checked={BoolCast(activeItem.presPinAudioPlay)} /> + (activeItem.followLinkAudio = !BoolCast(activeItem.followLinkAudio))} checked={BoolCast(activeItem.followLinkAudio)} />
() { const presData = Cast(this.rootDoc.data, listSpec(Doc)); if (data && presData) { data.push(doc); - TabDocView.PinDoc(doc); + TabDocView.PinDoc(doc, {}); this.gotoDocument(this.childDocs.length, this.activeItem); } else { this.props.addDocTab(doc, 'add:right'); diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 9af0949eb..133b882f6 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -52,7 +52,7 @@ class RegionAnnotation extends React.Component { }; @undoBatch - pinToPres = () => this.props.pinToPres(this.annoTextRegion); + pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); @undoBatch makePushpin = () => (this.annoTextRegion.isPushpin = !this.annoTextRegion.isPushpin); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 6ff87ef9f..5a5c63c3d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -166,12 +166,12 @@ export class PDFViewer extends React.Component { // scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location, // otherwise it will scroll smoothly. - scrollFocus = (doc: Doc, smooth: boolean) => { + scrollFocus = (doc: Doc, scrollTop: number, smooth: boolean) => { const mainCont = this._mainCont.current; let focusSpeed: Opt; if (doc !== this.props.rootDoc && mainCont) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight)); + const scrollTo = doc.unrendered ? scrollTop : Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight)); if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) { if (!this._pdfViewer) this._initialScroll = scrollTo; else if (smooth) smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), mainCont, scrollTo); @@ -203,6 +203,11 @@ export class PDFViewer extends React.Component { } document.removeEventListener('pagesinit', this.pagesinit); var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : ''; + this._disposers.scale = reaction( + () => NumCast(this.props.layoutDoc._viewScale, 1), + scale => (this._pdfViewer.currentScaleValue = scale), + { fireImmediately: true } + ); this._disposers.scroll = reaction( () => Math.abs(NumCast(this.props.Document._scrollTop)), pos => { @@ -290,7 +295,7 @@ export class PDFViewer extends React.Component { @action scrollToAnnotation = (scrollToAnnotation: Doc) => { if (scrollToAnnotation) { - this.scrollFocus(scrollToAnnotation, true); + this.scrollFocus(scrollToAnnotation, NumCast(scrollToAnnotation.y), true); Doc.linkFollowHighlight(scrollToAnnotation); } }; -- cgit v1.2.3-70-g09d2 From 30e7fc1b2cb4b5c5f8d5f5e4f808b91e69629245 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Nov 2022 11:00:06 -0500 Subject: fixed pushpin behaviors by not animating when anchor viewspec already matched document. fixed recording button highlighting. switched LinkEditor to edit properties of destination insteqad of source anchor --- src/client/views/DocumentButtonBar.tsx | 22 +++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 ++-- src/client/views/linking/LinkEditor.tsx | 14 ++--- src/client/views/nodes/ImageBox.tsx | 11 ++-- src/client/views/nodes/trails/PresBox.tsx | 72 +++++++++++++++------- 5 files changed, 80 insertions(+), 50 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 681349ccf..ecf330792 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -386,18 +386,18 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV style={{ backgroundColor: this._isRecording ? Colors.ERROR_RED : Colors.DARK_GRAY, color: Colors.WHITE }} onPointerDown={action((e: React.PointerEvent) => { this._isRecording = true; - this.props.views().map( - view => - view && - DocumentViewInternal.recordAudioAnnotation( - view.dataDoc, - view.LayoutFieldKey, - stopFunc => (this._stopFunc = stopFunc), - action(() => (this._isRecording = false)) - ) - ); + this.props.views().map(view => view && DocumentViewInternal.recordAudioAnnotation(view.dataDoc, view.LayoutFieldKey, stopFunc => (this._stopFunc = stopFunc), emptyFunction)); const b = UndoManager.StartBatch('Recording'); - setupMoveUpEvents(this, e, returnFalse, () => this._stopFunc(), emptyFunction); + setupMoveUpEvents( + this, + e, + returnFalse, + action(() => { + this._isRecording = false; + this._stopFunc(); + }), + emptyFunction + ); })}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8a97797c7..57cccec4a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1532,17 +1532,18 @@ export class CollectionFreeFormView extends CollectionSubView { - let focusSpeed: Opt; - PresBox.restoreTargetDocView( + const focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition); + return PresBox.restoreTargetDocView( this.rootDoc, // { pinDocLayout: BoolCast(anchor.presPinDocLayout) }, anchor, - (focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition)), + focusSpeed, { pannable: anchor.presPinData ? true : false, } - ); - return focusSpeed; + ) + ? focusSpeed + : undefined; }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document getAnchor = () => { diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index d90a91ab7..8c4d756d2 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -297,13 +297,13 @@ export class LinkEditor extends React.Component { ); } - @computed get sourceAnchor() { + @computed get destinationAnchor() { const ldoc = this.props.linkDoc; if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) { - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); } - return this.props.sourceDoc; + return LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc) ?? this.props.sourceDoc; } @action changeEffectDropdown = () => { @@ -313,7 +313,7 @@ export class LinkEditor extends React.Component { @undoBatch changeEffect = action((follow: string) => { this.openEffectDropdown = false; - this.sourceAnchor.presEffect = follow; + this.destinationAnchor.presEffect = follow; }); @computed @@ -323,7 +323,7 @@ export class LinkEditor extends React.Component {
Transition Effect:
- {StrCast(this.sourceAnchor.presEffect, 'default')} + {StrCast(this.destinationAnchor.presEffect, 'default')}
@@ -447,7 +447,7 @@ export class LinkEditor extends React.Component {
{this.followingDropdown} {this.effectDropdown} - {PresBox.inputter('0.1', '0.1', '10', NumCast(this.sourceAnchor.presTransition) / 1000, true, (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => (this.sourceAnchor.presTransition = timeInMS)))} + {PresBox.inputter('0.1', '0.1', '10', NumCast(this.destinationAnchor.presTransition) / 1000, true, (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => (this.destinationAnchor.presTransition = timeInMS)))}
{ - let focusSpeed: Opt; - PresBox.restoreTargetDocView( + const focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition); + return PresBox.restoreTargetDocView( this.rootDoc, // { pinDocLayout: BoolCast(anchor.presPinDocLayout) }, anchor, - (focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition)), + focusSpeed, !anchor.presPinData ? {} : { @@ -76,8 +76,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 7235481e0..e19b53f50 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -365,25 +365,46 @@ export class PresBox extends ViewBoxBaseComponent() { @action static restoreTargetDocView(bestTarget: Doc, pinProps: PinProps | undefined, activeItem: Doc, transTime: number, pinDataTypes = this.pinDataTypes(bestTarget)) { const presTransitionTime = `all ${transTime}ms`; - bestTarget._viewTransition = presTransitionTime; + let changed = false; if (pinProps?.pinDocLayout) { - const transTime = NumCast(activeItem.presTransition, 500); - bestTarget._dataTransition = `all ${transTime}ms`; - bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x)); - bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y)); - bestTarget.rotation = NumCast(activeItem.presRot, NumCast(bestTarget.rotation)); - bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); - bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); - setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); + if ( + bestTarget.x !== NumCast(activeItem.presX, NumCast(bestTarget.x)) || + bestTarget.y !== NumCast(activeItem.presY, NumCast(bestTarget.y)) || + bestTarget.rotation !== NumCast(activeItem.presRot, NumCast(bestTarget.rotation)) || + bestTarget.width !== NumCast(activeItem.presWidth, NumCast(bestTarget.width)) || + bestTarget.height !== NumCast(activeItem.presHeight, NumCast(bestTarget.height)) + ) { + bestTarget._dataTransition = `all ${transTime}ms`; + bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x)); + bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y)); + bestTarget.rotation = NumCast(activeItem.presRot, NumCast(bestTarget.rotation)); + bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); + bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); + changed = true; + } + } + if (pinDataTypes.clippable) { + if (bestTarget._clipWidth !== activeItem.presPinClipWidth) { + bestTarget._clipWidth = activeItem.presPinClipWidth; + changed = true; + } + } + if (pinDataTypes.temporal) { + if (bestTarget._currentTimecode !== activeItem.presStartTime) { + bestTarget._currentTimecode = activeItem.presStartTime; + changed = true; + } } - if (pinDataTypes.clippable) bestTarget._clipWidth = activeItem.presPinClipWidth; - if (pinDataTypes.temporal) bestTarget._currentTimecode = activeItem.presStartTime; if (pinDataTypes.scrollable) { - bestTarget._scrollTop = activeItem.presPinViewScroll; - const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); - if (contentBounds) { - const dv = DocumentManager.Instance.getDocumentView(bestTarget)?.ComponentView; - dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }); + if (bestTarget._scrollTop !== activeItem.presPinViewScroll) { + bestTarget._scrollTop = activeItem.presPinViewScroll; + changed = true; + const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); + if (contentBounds) { + const dv = DocumentManager.Instance.getDocumentView(bestTarget)?.ComponentView; + dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }); + } } } if (pinDataTypes.dataannos) { @@ -397,6 +418,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinDataTypes.textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; if (pinDataTypes.poslayoutview) { + changed = true; StrListCast(activeItem.presPinLayoutData) .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) .forEach(data => { @@ -428,12 +450,18 @@ export class PresBox extends ViewBoxBaseComponent() { dv.ComponentView?.brushView?.(viewport); } } else { - bestTarget._panX = activeItem.presPinViewX; - bestTarget._panY = activeItem.presPinViewY; - bestTarget._viewScale = activeItem.presPinViewScale; + if (bestTarget._panX !== activeItem.presPinViewX || bestTarget._panY !== activeItem.presPinViewY || bestTarget._viewScale !== activeItem.presPinViewScale) { + bestTarget._panX = activeItem.presPinViewX; + bestTarget._panY = activeItem.presPinViewY; + bestTarget._viewScale = activeItem.presPinViewScale; + changed = true; + } } } - return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10); + if (changed) { + bestTarget._viewTransition = presTransitionTime; + return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10); + } } /// copies values from the targetDoc (which is the prototype of the pinDoc) to @@ -495,7 +523,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } - static _navTimer: NodeJS.Timeout; + static _navTimer: NodeJS.Timeout | undefined; /** * This method makes sure that cursor navigates to the element that * has the option open and last in the group. @@ -563,7 +591,7 @@ export class PresBox extends ViewBoxBaseComponent() { // adjust the pan and scale to that of the pinView when it was added. const pinDocLayout = (BoolCast(activeItem.presPinLayout) || BoolCast(activeItem.presPinView)) && DocCast(targetDoc.context)?._currentFrame === undefined; if (activeItem.presPinData || activeItem.presPinView || pinDocLayout) { - clearTimeout(PresBox._navTimer); + PresBox._navTimer && clearTimeout(PresBox._navTimer); // targetDoc may or may not be displayed. this gets the first available document (or alias) view that matches targetDoc const bestTargetView = DocumentManager.Instance.getFirstDocumentView(targetDoc); if (bestTargetView?.props.Document) PresBox._navTimer = PresBox.restoreTargetDocView(bestTargetView?.props.Document, { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500)); -- cgit v1.2.3-70-g09d2 From cdd1dd95c67fcb95914913bb5346c5117c0abc27 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 18 Nov 2022 17:26:17 -0500 Subject: migration of link properties to propertiesView --- src/client/util/LinkFollower.ts | 14 +- src/client/util/LinkManager.ts | 3 +- src/client/util/SelectionManager.ts | 4 + src/client/views/DocumentButtonBar.tsx | 4 +- src/client/views/PropertiesView.scss | 8 +- src/client/views/PropertiesView.tsx | 307 +++++++++++++++------ .../CollectionFreeFormLinkView.tsx | 27 +- src/client/views/linking/LinkEditor.tsx | 16 +- src/client/views/linking/LinkMenu.scss | 8 +- src/client/views/linking/LinkMenuItem.scss | 24 +- src/client/views/linking/LinkMenuItem.tsx | 42 ++- src/client/views/nodes/LinkDocPreview.tsx | 2 + src/client/views/nodes/trails/PresBox.tsx | 30 +- src/client/views/nodes/trails/PresEnums.ts | 3 + src/fields/Doc.ts | 2 +- src/fields/documentSchemas.ts | 2 +- 16 files changed, 327 insertions(+), 169 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index a3eb7ed7a..52885e428 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -111,7 +111,19 @@ export class LinkFollower { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; } const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; - DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished); + DocumentManager.Instance.jumpToDocument( + target, + zoom, + (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), + targetContexts, + linkDoc, + undefined, + sourceDoc, + allFinished, + undefined, + undefined, + Cast(target.presZoom, 'number', null) + ); } } else { allFinished(); diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 7a12a8580..49cc3218d 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -19,7 +19,8 @@ import { Cast, StrCast } from '../../fields/Types'; export class LinkManager { @observable static _instance: LinkManager; @observable static userLinkDBs: Doc[] = []; - public static currentLink: Opt; + @observable public static currentLink: Opt; + @observable public static currentLinkAnchor: Opt; public static get Instance() { return LinkManager._instance; } diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index a3d6f5227..1a2dda953 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -4,6 +4,7 @@ import { Doc, Opt } from '../../fields/Doc'; import { DocCast } from '../../fields/Types'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocumentView } from '../views/nodes/DocumentView'; +import { LinkManager } from './LinkManager'; import { ScriptingGlobals } from './ScriptingGlobals'; export namespace SelectionManager { @@ -15,6 +16,7 @@ export namespace SelectionManager { @action SelectSchemaViewDoc(doc: Opt) { manager.SelectedSchemaDocument = doc; + if (doc?.type === DocumentType.LINK) LinkManager.currentLink = doc; } @action SelectView(docView: DocumentView, ctrlPressed: boolean): void { @@ -32,6 +34,7 @@ export namespace SelectionManager { manager.SelectedViews.clear(); manager.SelectedViews.set(docView, docView.rootDoc); } + if (docView.rootDoc.type === DocumentType.LINK) LinkManager.currentLink = docView.rootDoc; } @action DeselectView(docView: DocumentView): void { @@ -42,6 +45,7 @@ export namespace SelectionManager { } @action DeselectAll(): void { + LinkManager.currentLink = undefined; manager.SelectedSchemaDocument = undefined; Array.from(manager.SelectedViews.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false)); manager.SelectedViews.clear(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index ecf330792..5969d55e9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -21,7 +21,7 @@ import './DocumentButtonBar.scss'; import { Colors } from './global/globalEnums'; import { MetadataEntryMenu } from './MetadataEntryMenu'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhereMod } from './nodes/DocumentView'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { TemplateMenu } from './TemplateMenu'; @@ -180,7 +180,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } - CollectionDockingView.AddSplit(googleDoc, 'right'); + CollectionDockingView.AddSplit(googleDoc, OpenWhereMod.right); } else if (e.altKey) { e.preventDefault(); window.open(googleDocUrl); diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index 437df4739..30806f718 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -1,9 +1,9 @@ -@import "./global/globalCssVariables.scss"; +@import './global/globalCssVariables.scss'; .propertiesView { height: 100%; width: 250; - font-family: "Roboto"; + font-family: 'Roboto'; cursor: auto; overflow-x: hidden; @@ -843,7 +843,7 @@ } .propertiesView-section { - padding: 10px 0; + padding-left: 20px; } .propertiesView-input { @@ -877,4 +877,4 @@ color: white; padding-left: 8px; background-color: rgb(51, 51, 51); -} \ No newline at end of file +} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 93a3fd253..076dc8261 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -4,7 +4,7 @@ import { faAnchor, faArrowRight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@material-ui/core'; import { intersection } from 'lodash'; -import { action, autorun, computed, Lambda, observable } from 'mobx'; +import { action, autorun, computed, Lambda, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSelfEdit, AclSym, AclUnset, DataSym, Doc, DocListCast, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc'; @@ -27,12 +27,13 @@ import { InkStrokeProperties } from './InkStrokeProperties'; import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; import { FilterBox } from './nodes/FilterBox'; import { KeyValueBox } from './nodes/KeyValueBox'; -import { PresBox } from './nodes/trails'; +import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; import { PropertiesButtons } from './PropertiesButtons'; import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector'; import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import './PropertiesView.scss'; import { DefaultStyleProvider } from './StyleProvider'; +import { Colors } from './global/globalEnums'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -54,7 +55,7 @@ export class PropertiesView extends React.Component { } @computed get selectedDoc() { - return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc || Doc.ActiveDashboard; + return LinkManager.currentLink || SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc || Doc.ActiveDashboard; } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -405,7 +406,7 @@ export class PropertiesView extends React.Component { */ @computed get expansionIcon() { return ( - {'Show more permissions'}
}> + Show more permissions
}>
{ @@ -1406,6 +1407,37 @@ export class PropertiesView extends React.Component { } }); + @undoBatch + changeAnimationBehavior = action((behavior: string) => { + const lanch = this.destinationAnchor; + if (lanch) { + lanch.presEffect = behavior; + } + }); + @undoBatch + @action + updateEffectDirection = (effect: PresEffectDirection) => { + const lanch = this.destinationAnchor; + if (lanch) { + lanch.presEffectDirection = effect; + } + }; + + @undoBatch + animationDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const lanch = this.destinationAnchor; + const color = lanch?.presEffectDirection === direction || (direction === PresEffectDirection.Center && !lanch?.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + return ( + {direction}
}> +
this.updateEffectDirection(direction)}> + {icon ? : null} +
+ + ); + }; + @undoBatch changeFollowBehavior = action((follow: string) => { if (LinkManager.currentLink && this.selectedDoc) { @@ -1438,19 +1470,23 @@ export class PropertiesView extends React.Component { } }; - toggleAnchor = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)))); + toggleProp = (e: React.PointerEvent, prop: string) => { + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc[prop] = !this.selectedDoc[prop])))); }; - toggleArrow = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow)))); - }; + @computed get destinationAnchor() { + const ldoc = LinkManager.currentLink; + const lanch = LinkManager.currentLinkAnchor; + if (ldoc && lanch) return LinkManager.getOppositeAnchor(ldoc, lanch) ?? lanch; + return ldoc ? DocCast(ldoc.anchor2) : ldoc; + } - toggleZoomToTarget1 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor1).followLinkZoom = !DocCast(this.selectedDoc.anchor1).followLinkZoom)))); - }; - toggleZoomToTarget2 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor2).followLinkZoom = !DocCast(this.selectedDoc.anchor2).followLinkZoom)))); + @computed get sourceAnchor() { + return LinkManager.currentLinkAnchor ?? (LinkManager.currentLink && this.destinationAnchor ? LinkManager.getOppositeAnchor(LinkManager.currentLink, this.destinationAnchor) : LinkManager.currentLink); + } + + toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc) => { + anchor && setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (anchor[prop] = !anchor[prop])))); }; @computed @@ -1485,6 +1521,23 @@ export class PropertiesView extends React.Component { ); } + // Converts seconds to ms and updates presTransition + setZoom = (number: String, change?: number) => { + let scale = Number(number) / 100; + if (change) scale += change; + if (scale < 0.01) scale = 0.01; + if (scale > 1) scale = 1; + this.destinationAnchor && (this.destinationAnchor.presZoom = scale); + }; + // Converts seconds to ms and updates presTransition + setZoomSrc = (number: String, change?: number) => { + let scale = Number(number) / 100; + if (change) scale += change; + if (scale < 0.01) scale = 0.01; + if (scale > 1) scale = 1; + this.sourceAnchor && (this.sourceAnchor.presZoom = scale); + }; + /** * Handles adding and removing members from the sharing panel */ @@ -1498,6 +1551,10 @@ export class PropertiesView extends React.Component { render() { const isNovice = Doc.noviceMode; + const zoom = Number((NumCast(this.destinationAnchor?.presZoom) * 100).toPrecision(3)); + const zoomSrc = Number((NumCast(this.sourceAnchor?.presZoom) * 100).toPrecision(3)); + const targZoom = this.destinationAnchor?.followLinkZoom; + const srcZooom = this.sourceAnchor?.followLinkZoom; if (!this.selectedDoc && !this.isPres) { return (
@@ -1507,81 +1564,6 @@ export class PropertiesView extends React.Component {
); } else { - if (this.selectedDoc && this.isLink) { - return ( -
-
Linking
-
-

Information

-
-

Link Relationship

- {this.editRelationship} -
-
-

Description

- {this.editDescription} -
-
-
-

Behavior

-
-

Follow

- -
-
-

Auto-move anchor

- -
-
-

Display arrow

- -
-
-

Zoom to target

- -
-
-

Zoom to source

- -
-
-
- ); - } if (this.selectedDoc && !this.isPres) { return (
{ {this.contextsSubMenu} {this.linksSubMenu} + {!this.selectedDoc || !LinkManager.currentLink ? null : ( + <> +
+
+

Link Relationship

+ {this.editRelationship} +
+
+

Description

+ {this.editDescription} +
+
+
+
+

Follow Behavior

+ +
+
+

Target Effect

+ +
+ {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} +
+
+ {PresBox.inputter('0.1', '0.1', '10', NumCast(this.destinationAnchor?.presTransition) / 1000, true, (val: string) => + PresBox.SetTransitionTime(val, (timeInMS: number) => this.destinationAnchor && (this.destinationAnchor.presTransition = timeInMS)) + )}{' '} +
+
Fast
+
Medium
+
Slow
+
{' '} +
+

Play Target Audio

+ +
+
+

Auto-move anchor

+ +
+
+

Show link

+ +
+
+

Display arrow

+ +
+
+

Zoom to target (% screen filled)

+
+ +
+
this.setZoom(String(zoom), 0.1))}> + +
+
this.setZoom(String(zoom), -0.1))}> + +
+
+
+ +
+ {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom)} +
+

Zoom to source (% screen filled)

+
+ +
+
this.setZoomSrc(String(zoomSrc), 0.1))}> + +
+
this.setZoomSrc(String(zoomSrc), -0.1))}> + +
+
+
+ +
+ {!srcZooom ? null : PresBox.inputter('0', '1', '100', zoomSrc, true, this.setZoomSrc)} +
+ + )} {this.inkSubMenu} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index bf9de6760..a4131d7c0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -44,7 +44,7 @@ export class CollectionFreeFormLinkView extends React.Component { - if (SettingsManager.propertiesWidth > 0) { - SettingsManager.propertiesWidth = 0; - } else { + if ((SettingsManager.propertiesWidth ?? 0) < 100) { SettingsManager.propertiesWidth = 250; } }; @@ -217,14 +215,25 @@ export class CollectionFreeFormLinkView extends React.Component (LinkManager.currentLink = this.props.LinkDocs[0]))); if (!this.renderData) return null; const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; - LinkManager.currentLink = this.props.LinkDocs[0]; const linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field); //get string representing relationship const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List; const linkColorList = Doc.UserDoc().linkColorList as List; @@ -241,8 +250,8 @@ export class CollectionFreeFormLinkView extends React.Component {textX === undefined ? null : ( diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 8c4d756d2..07c20dae4 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -327,21 +327,7 @@ export class LinkEditor extends React.Component {
- {[ - PresEffect.None, - PresEffect.Zoom, - PresEffect.Lightspeed, - PresEffect.Fade, - PresEffect.Flip, - PresEffect.Rotate, - PresEffect.Bounce, - PresEffect.Roll, - PresEffect.Left, - PresEffect.Right, - PresEffect.Center, - PresEffect.Top, - PresEffect.Bottom, - ].map(effect => ( + {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
this.changeEffect(effect.toString())}> {effect.toString()}
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss index 77c16a28f..80cf93ed8 100644 --- a/src/client/views/linking/LinkMenu.scss +++ b/src/client/views/linking/LinkMenu.scss @@ -1,4 +1,4 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; .linkMenu { width: auto; @@ -13,7 +13,6 @@ border: 1px solid #e4e4e4; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); background: white; - min-width: 170px; max-height: 230px; overflow-y: scroll; z-index: 10; @@ -22,7 +21,7 @@ .linkMenu-list { white-space: nowrap; overflow-x: hidden; - width: 240px; + width: 100%; scrollbar-color: white; &:last-child { @@ -39,7 +38,6 @@ border-bottom: 0.5px solid lightgray; //@extend: 5px 0; - &:last-child { border-bottom: none; } @@ -76,4 +74,4 @@ display: none; } } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index 8333aa374..2ca97a27d 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -1,7 +1,7 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; .linkMenu-item { - // border-top: 0.5px solid $medium-gray; + // border-top: 0.5px solid $medium-gray; position: relative; display: flex; border-top: 0.5px solid #cdcdcd; @@ -14,7 +14,6 @@ background-color: white; - .linkMenu-name { position: relative; width: auto; @@ -22,9 +21,7 @@ display: flex; .linkMenu-text { - - // padding: 4px 2px; - //display: inline; + width: 100%; .linkMenu-source-title { text-decoration: none; @@ -35,9 +32,7 @@ margin-left: 20px; } - .linkMenu-title-wrapper { - display: flex; align-items: center; min-height: 20px; @@ -59,7 +54,7 @@ .linkMenu-destination-title { text-decoration: none; - color: #4476F7; + color: #4476f7; font-size: 13px; line-height: 0.9; padding-bottom: 2px; @@ -96,9 +91,7 @@ //overflow-wrap: break-word; user-select: none; } - } - } .linkMenu-item-content { @@ -114,7 +107,6 @@ } &:hover { - background-color: rgb(201, 239, 252); .linkMenu-item-buttons { @@ -122,7 +114,6 @@ } .linkMenu-item-content { - .linkMenu-destination-title { text-decoration: underline; color: rgb(60, 90, 156); @@ -135,10 +126,7 @@ .linkMenu-item-buttons { //@extend: right; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); + position: relative; display: none; .button { @@ -172,4 +160,4 @@ cursor: pointer; } } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 387e0e3d5..c3b5fa997 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,12 +1,12 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, observable } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Cast, StrCast } from '../../../fields/Types'; +import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; -import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; @@ -16,6 +16,9 @@ import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; import React = require('react'); +import { SettingsManager } from '../../util/SettingsManager'; +import { SelectionManager } from '../../util/SelectionManager'; +import { undoBatch } from '../../util/UndoManager'; interface LinkMenuItemProps { groupType: string; @@ -76,8 +79,19 @@ export class LinkMenuItem extends React.Component { this._showMore = !this._showMore; } - onEdit = (e: React.PointerEvent): void => { - LinkManager.currentLink = this.props.linkDoc; + @computed get sourceAnchor() { + const ldoc = this.props.linkDoc; + if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) { + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + } + return this.props.sourceDoc; + } + @action + onEdit = (e: React.PointerEvent) => { + const sel = SelectionManager.Views(); + LinkManager.currentLink = this.props.linkDoc === LinkManager.currentLink ? undefined : this.props.linkDoc; + LinkManager.currentLinkAnchor = this.sourceAnchor; setupMoveUpEvents( this, e, @@ -88,7 +102,12 @@ export class LinkMenuItem extends React.Component { return true; }, emptyFunction, - () => this.props.showEditor(this.props.linkDoc) + action(() => { + if ((SettingsManager.propertiesWidth ?? 0) < 100) { + SettingsManager.propertiesWidth = 250; + } + //this.props.showEditor(this.props.linkDoc); + }) ); }; @@ -123,6 +142,8 @@ export class LinkMenuItem extends React.Component { ); }; + deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this.props.linkDoc)))); + render() { const destinationIcon = Doc.toIcon(this.props.destinationDoc) as any as IconProp; @@ -141,7 +162,7 @@ export class LinkMenuItem extends React.Component { : undefined; return ( -
+
{
Edit Link
}>
e.stopPropagation()}> - + +
+ + Delete Link
}> +
e.stopPropagation()}> +
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 135fbca31..b326865b3 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -124,6 +124,8 @@ export class LinkDocPreview extends React.Component { return undefined; } @observable _showEditor = false; + + @action editLink = (e: React.PointerEvent): void => { LinkManager.currentLink = this.props.linkDoc; setupMoveUpEvents( diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index adfd2fda1..1cb6bc3a2 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -33,7 +33,7 @@ import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentVie import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; -import { PresEffect, PresMovement, PresStatus } from './PresEnums'; +import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import { map } from 'bluebird'; import { OpenWhere, OpenWhereMod } from '../DocumentView'; const { Howl } = require('howler'); @@ -71,10 +71,10 @@ export class PresBox extends ViewBoxBaseComponent() { */ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc, root: Doc) { const effectProps = { - left: presEffectDoc?.presEffectDirection === PresEffect.Left, - right: presEffectDoc?.presEffectDirection === PresEffect.Right, - top: presEffectDoc?.presEffectDirection === PresEffect.Top, - bottom: presEffectDoc?.presEffectDirection === PresEffect.Bottom, + left: presEffectDoc?.presEffectDirection === PresEffectDirection.Left, + right: presEffectDoc?.presEffectDirection === PresEffectDirection.Right, + top: presEffectDoc?.presEffectDirection === PresEffectDirection.Top, + bottom: presEffectDoc?.presEffectDirection === PresEffectDirection.Bottom, opposite: true, delay: 0, duration: Cast(presEffectDoc?.presTransition, 'number', null), @@ -1191,7 +1191,7 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action - updateEffectDirection = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); + updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); @undoBatch @action @@ -1236,12 +1236,12 @@ export class PresBox extends ViewBoxBaseComponent() { {movement}
); - const presDirection = (direction: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const color = this.activeItem.presEffectDirection === direction || (direction === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const color = this.activeItem.presEffectDirection === direction || (direction === PresEffectDirection.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( {direction}
}>
this.updateEffectDirection(direction)}> {icon ? : null}
@@ -1405,11 +1405,11 @@ export class PresBox extends ViewBoxBaseComponent() {
{StrCast(this.activeItem.presEffectDirection)}
- {presDirection(PresEffect.Left, 'angle-right', 1, 2, {})} - {presDirection(PresEffect.Right, 'angle-left', 3, 2, {})} - {presDirection(PresEffect.Top, 'angle-down', 2, 1, {})} - {presDirection(PresEffect.Bottom, 'angle-up', 2, 3, {})} - {presDirection(PresEffect.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} + {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
)} @@ -1428,7 +1428,7 @@ export class PresBox extends ViewBoxBaseComponent() { applyTo = (array: Doc[]) => { this.updateMovement(this.activeItem.presMovement as PresMovement, true); this.updateEffect(this.activeItem.presEffect as PresEffect, true); - this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffect, true); + this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true); const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; array.forEach(curDoc => { curDoc.presTransition = presTransition; diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts index c6a222c3a..034f7588b 100644 --- a/src/client/views/nodes/trails/PresEnums.ts +++ b/src/client/views/nodes/trails/PresEnums.ts @@ -14,6 +14,9 @@ export enum PresEffect { Bounce = 'Bounce', Roll = 'Roll', None = 'None', +} + +export enum PresEffectDirection { Left = 'Enter from left', Right = 'Enter from right', Center = 'Enter from center', diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 75801b68c..c10751698 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1268,7 +1268,7 @@ export namespace Doc { let _lastDate = 0; export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) { - linkFollowUnhighlight(); + //linkFollowUnhighlight(); // runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = undefined)); // setTimeout(() => runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect))); runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect)); diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 24b5a359d..10324449f 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -93,7 +93,7 @@ export const documentSchema = createSchema({ layers: listSpec('string'), // which layers the document is part of _lockedPosition: 'boolean', // whether the document can be moved (dragged) _lockedTransform: 'boolean', // whether a freeformview can pan/zoom - displayArrow: 'boolean', // toggles directed arrows + linkDisplayArrow: 'boolean', // toggles directed arrows // drag drop properties _stayInCollection: 'boolean', // whether document can be dropped into a different collection -- cgit v1.2.3-70-g09d2 From 403d1c4fece9efa663e0fd7161afff9f27cf670c Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 16 Dec 2022 15:07:50 -0500 Subject: fixed problem with undo. regularized all linkfollowing anchor fields to start with followLink. added ease vs linear flag for scroll transitions in link and preselmeent navigations. added link follow to move target to specified offset from source. shifted from setting dropAction on items to setting childDropAction on collections --- src/Utils.ts | 29 +++-- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 35 +++--- src/client/util/LinkFollower.ts | 78 ++++++++---- src/client/views/DocumentButtonBar.scss | 17 +++ src/client/views/DocumentButtonBar.tsx | 68 +++++++--- src/client/views/GestureOverlay.tsx | 1 - src/client/views/PropertiesView.tsx | 88 +++++++++---- .../views/collections/CollectionNoteTakingView.tsx | 4 +- .../views/collections/CollectionPileView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 4 +- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 5 + .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +- .../collectionLinear/CollectionLinearView.tsx | 3 +- src/client/views/linking/LinkPopup.scss | 5 +- src/client/views/linking/LinkPopup.tsx | 13 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 11 +- src/client/views/nodes/LabelBox.tsx | 140 ++++++++++++--------- src/client/views/nodes/WebBox.tsx | 8 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 5 +- src/client/views/nodes/trails/PresBox.tsx | 37 ++++-- src/client/views/nodes/trails/PresEnums.ts | 1 + src/client/views/pdf/AnchorMenu.tsx | 3 +- src/client/views/pdf/PDFViewer.tsx | 21 ++-- src/client/views/search/SearchBox.tsx | 29 ++++- src/fields/util.ts | 10 +- 29 files changed, 416 insertions(+), 217 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 5e0514bc6..9d3b9eb2b 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -558,9 +558,13 @@ export namespace JSONUtils { } } -const easeInOutQuad = (currentTime: number, start: number, change: number, duration: number) => { - let newCurrentTime = currentTime / (duration / 2); +const easeFunc = (transition: 'ease' | 'linear' | undefined, currentTime: number, start: number, change: number, duration: number) => { + if (transition === 'linear') { + let newCurrentTime = currentTime / duration; // currentTime / (duration / 2); + return start + newCurrentTime * change; + } + let newCurrentTime = currentTime / (duration / 2); if (newCurrentTime < 1) { return (change / 2) * newCurrentTime * newCurrentTime + start; } @@ -569,23 +573,28 @@ const easeInOutQuad = (currentTime: number, start: number, change: number, durat return (-change / 2) * (newCurrentTime * (newCurrentTime - 2) - 1) + start; }; -export function smoothScroll(duration: number, element: HTMLElement | HTMLElement[], to: number) { +export function smoothScroll(duration: number, element: HTMLElement | HTMLElement[], to: number, transition: 'ease' | 'linear' | undefined, stopper?: () => void) { + stopper?.(); const elements = element instanceof HTMLElement ? [element] : element; const starts = elements.map(element => element.scrollTop); const startDate = new Date().getTime(); - + let _stop = false; + const stop = () => (_stop = true); const animateScroll = () => { const currentDate = new Date().getTime(); const currentTime = currentDate - startDate; - elements.map((element, i) => (element.scrollTop = easeInOutQuad(currentTime, starts[i], to - starts[i], duration))); + elements.map((element, i) => (element.scrollTop = easeFunc(transition, currentTime, starts[i], to - starts[i], duration))); - if (currentTime < duration) { - requestAnimationFrame(animateScroll); - } else { - elements.forEach(element => (element.scrollTop = to)); + if (!_stop) { + if (currentTime < duration) { + requestAnimationFrame(animateScroll); + } else { + elements.forEach(element => (element.scrollTop = to)); + } } }; animateScroll(); + return stop; } export function smoothScrollHorizontal(duration: number, element: HTMLElement | HTMLElement[], to: number) { @@ -596,7 +605,7 @@ export function smoothScrollHorizontal(duration: number, element: HTMLElement | const animateScroll = () => { const currentDate = new Date().getTime(); const currentTime = currentDate - startDate; - elements.map((element, i) => (element.scrollLeft = easeInOutQuad(currentTime, starts[i], to - starts[i], duration))); + elements.map((element, i) => (element.scrollLeft = easeFunc('ease', currentTime, starts[i], to - starts[i], duration))); if (currentTime < duration) { requestAnimationFrame(animateScroll); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d13d96dd3..634b14822 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -37,7 +37,7 @@ import { FontIconBox } from '../views/nodes/button/FontIconBox'; import { ColorBox } from '../views/nodes/ColorBox'; import { ComparisonBox } from '../views/nodes/ComparisonBox'; import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox'; -import { DocFocusOptions, OpenWhereMod } from '../views/nodes/DocumentView'; +import { DocFocusOptions, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; import { EquationBox } from '../views/nodes/EquationBox'; import { FieldViewProps } from '../views/nodes/FieldView'; import { FilterBox } from '../views/nodes/FilterBox'; @@ -1322,7 +1322,7 @@ export namespace DocUtils { return DocUtils.ActiveRecordings.map(audio => { const sourceDoc = getSourceDoc(); const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor() || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline'); - link && (link.followLinkLocation = 'add:right'); + link && (link.followLinkLocation = OpenWhere.addRight); return link; }); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 635980e03..5549769aa 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -22,7 +22,7 @@ import { Colors } from "../views/global/globalEnums"; import { MainView } from "../views/MainView"; import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; import { OverlayView } from "../views/OverlayView"; -import { DragManager } from "./DragManager"; +import { DragManager, dropActionType } from "./DragManager"; import { MakeTemplate } from "./DropConverter"; import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; @@ -306,7 +306,7 @@ export class CurrentUserUtils { const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => { const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined; const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, - _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, _dropAction: "alias", + _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true, _removeDropProperties: new List(["_stayInCollection"]), }; @@ -316,7 +316,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true, _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, - childDocumentsActive: true + childDocumentsActive: true, childDropAction: 'alias' }; const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; return DocUtils.AssignScripts(DocUtils.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts); @@ -352,15 +352,15 @@ export class CurrentUserUtils { const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined; const reqdBtnOpts:DocumentOptions = { title, icon, target, btnType: ButtonType.MenuButton, system: true, dontUndo: true, dontRegisterView: true, - _width: 60, _height: 60, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, _dropAction: "alias", - _removeDropProperties: new List(["dropAction", "_stayInCollection"]), + _width: 60, _height: 60, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, + _removeDropProperties: new List(["_stayInCollection"]), }; return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs); }); const reqdStackOpts:DocumentOptions ={ - title: "menuItemPanel", childDropAction: "alias", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, - _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true + title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, + _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" }); } @@ -397,14 +397,14 @@ export class CurrentUserUtils { // sets up the main document for the mobile button static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, { ...opts, - _removeDropProperties: new List(["dropAction"]), _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15, + _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15, borderRounding: "5px", boxShadow: "0 0", system: true }) as any as Doc // sets up the text container for the information contained within the mobile button static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, { ...opts, - _removeDropProperties: new List(["dropAction"]), _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25, + _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25, backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, system: true }) as any as Doc @@ -573,8 +573,8 @@ export class CurrentUserUtils { }) static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({ - btnType: ButtonType.ToolButton, _forceActive: true, _dropAction: "alias", _hideContextMenu: true, - _removeDropProperties: new List(["_dropAction", "_hideContextMenu", "stayInCollection"]), + btnType: ButtonType.ToolButton, _forceActive: true, _hideContextMenu: true, + _removeDropProperties: new List([ "_hideContextMenu", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true, ...opts, }) @@ -595,12 +595,15 @@ export class CurrentUserUtils { // { scripts: { onClick: 'nextKeyFrame(_readOnly_)'}, opts:{title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, width: 20,} }, ]; const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts)); - const dockBtnsReqdOpts = { - title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", + const dockBtnsReqdOpts:DocumentOptions = { + title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'alias', childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true }; reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); - reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + reaction(() => UndoManager.undoStack.slice(), () => { + console.log(UndoManager.undoStack) + Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4; + }, { fireImmediately: true }); return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns); } @@ -687,7 +690,7 @@ export class CurrentUserUtils { _nativeWidth: params.width ?? 30, _width: params.width ?? 30, _height: 30, _nativeHeight: 30, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, - _dropAction: "alias", _removeDropProperties: new List(["dropAction", "_stayInCollection"]), + _removeDropProperties: new List([ "_stayInCollection"]), }; const reqdFuncs:{[key:string]:any} = { ...params.funcs, @@ -698,7 +701,7 @@ export class CurrentUserUtils { /// Initializes all the default buttons for the top bar context menu static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") { - const reqdCtxtOpts = { title: "context menu buttons", flexGap: 0, childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }; + const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", flexGap: 0, childDropAction: 'alias', childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }; const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined); const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => { const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title); diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 0285803e8..94badbb44 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,5 +1,6 @@ import { action, runInAction } from 'mobx'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { Doc, DocListCast, Opt, WidthSym } from '../../fields/Doc'; +import { listSpec } from '../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentDecorations } from '../views/DocumentDecorations'; @@ -98,32 +99,59 @@ export class LinkFollower { : linkDoc.anchor1 ) as Doc; if (target) { - const options: DocFocusOptions = { - playAudio: BoolCast(sourceDoc.followLinkAudio), - toggleTarget: BoolCast(sourceDoc.followLinkToggle), - willPan: true, - willPanZoom: BoolCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkZoom, false), - zoomTime: NumCast(LinkManager.getOppositeAnchor(linkDoc, target)?.linkTransitionTime, 500), - zoomScale: Cast(sourceDoc.linkZoomScale, 'number', null), - effect: sourceDoc, - originatingDoc: sourceDoc, + const doFollow = (canToggle?: boolean) => { + const options: DocFocusOptions = { + playAudio: BoolCast(sourceDoc.followLinkAudio), + toggleTarget: canToggle && BoolCast(sourceDoc.followLinkToggle), + willPan: true, + willPanZoom: BoolCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkZoom, false), + zoomTime: NumCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkTransitionTime, 500), + zoomScale: Cast(sourceDoc.followLinkZoomScale, 'number', null), + easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, + effect: sourceDoc, + originatingDoc: sourceDoc, + }; + if (target.TourMap) { + const fieldKey = Doc.LayoutFieldKey(target); + const tour = DocListCast(target[fieldKey]).reverse(); + LightboxView.SetLightboxDoc(currentContext, undefined, tour); + setTimeout(LightboxView.Next); + allFinished(); + } else { + const containerAnnoDoc = Cast(target.annotationOn, Doc, null); + const containerDoc = containerAnnoDoc || target; + var containerDocContext = containerDoc?.context ? [Cast(containerDoc?.context, Doc, null)] : ([] as Doc[]); + while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) { + containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; + } + const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; + DocumentManager.Instance.jumpToDocument(target, options, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, OpenWhere.inPlace), finished), targetContexts, allFinished); + } }; - if (target.TourMap) { - const fieldKey = Doc.LayoutFieldKey(target); - const tour = DocListCast(target[fieldKey]).reverse(); - LightboxView.SetLightboxDoc(currentContext, undefined, tour); - setTimeout(LightboxView.Next); - allFinished(); - } else { - const containerAnnoDoc = Cast(target.annotationOn, Doc, null); - const containerDoc = containerAnnoDoc || target; - var containerDocContext = containerDoc?.context ? [Cast(containerDoc?.context, Doc, null)] : ([] as Doc[]); - while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) { - containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; + let movedTarget = false; + if (sourceDoc.followLinkLocation === OpenWhere.inParent) { + const sourceDocParent = DocCast(sourceDoc.context); + if (target.context instanceof Doc && target.context !== sourceDocParent) { + Doc.RemoveDocFromList(target.context, Doc.LayoutFieldKey(target.context), target); + movedTarget = true; + } + if (!DocListCast(sourceDocParent[Doc.LayoutFieldKey(sourceDocParent)]).includes(target)) { + Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target); + movedTarget = true; + } + target.context = sourceDocParent; + const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)]; + if (sourceDoc.followLinkXoffset !== undefined && moveTo[0] !== target.x) { + target.x = moveTo[0]; + movedTarget = true; + } + if (sourceDoc.followLinkYoffset !== undefined && moveTo[1] !== target.y) { + target.y = moveTo[1]; + movedTarget = true; } - const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; - DocumentManager.Instance.jumpToDocument(target, options, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), targetContexts, allFinished); - } + if (movedTarget) setTimeout(doFollow); + else doFollow(true); + } else doFollow(true); } else { allFinished(); } diff --git a/src/client/views/DocumentButtonBar.scss b/src/client/views/DocumentButtonBar.scss index f9c988fdd..835d6c8bb 100644 --- a/src/client/views/DocumentButtonBar.scss +++ b/src/client/views/DocumentButtonBar.scss @@ -28,6 +28,15 @@ $linkGap: 3px; height: 20px; align-items: center; } +.documentButtonBar-linkTypes { + position: absolute; + display: none; + width: 60px; + top: -14px; + background: black; + height: 20px; + align-items: center; +} .documentButtonBar-followTypes { width: 20px; display: none; @@ -55,6 +64,14 @@ $linkGap: 3px; } } } +.documentButtonBar-link { + color: white; + &:hover { + .documentButtonBar-linkTypes { + display: flex; + } + } +} .documentButtonBar-pinIcon { &:hover { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 5969d55e9..90c6c040c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -1,24 +1,24 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, observable, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; -import { BoolCast, Cast, NumCast } from '../../fields/Types'; +import { Cast, NumCast } from '../../fields/Types'; import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { Docs } from '../documents/Documents'; import { DragManager } from '../util/DragManager'; import { SelectionManager } from '../util/SelectionManager'; -import { SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { TabDocView } from './collections/TabDocView'; import './DocumentButtonBar.scss'; import { Colors } from './global/globalEnums'; +import { LinkPopup } from './linking/LinkPopup'; import { MetadataEntryMenu } from './MetadataEntryMenu'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView, DocumentViewInternal, OpenWhereMod } from './nodes/DocumentView'; @@ -26,6 +26,7 @@ import { DashFieldView } from './nodes/formattedText/DashFieldView'; import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { TemplateMenu } from './TemplateMenu'; import React = require('react'); +import { DocumentType } from '../documents/DocumentTypes'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -255,6 +256,28 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } + @observable subLink = ''; + @computed get linkButton() { + const targetDoc = this.view0?.props.Document; + return !targetDoc || !this.view0 ? null : ( +
+
+ search for target
}> +
+ +
+ +
+
+ +
+
+ ); + } + @observable subPin = ''; @computed get pinButton() { @@ -284,7 +307,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null), currentFrame: Cast(docs.lastElement()?.currentFrame, 'number', null) }); e.stopPropagation(); }} /> @@ -319,12 +342,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get shareButton() { const targetDoc = this.view0?.props.Document; return !targetDoc ? null : ( - -
{'Open Sharing Manager'}
- - }> + {'Open Sharing Manager'}
}>
SharingManager.Instance.open(this.view0, targetDoc)}>
@@ -347,12 +365,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get metadataButton() { const view0 = this.view0; return !view0 ? null : ( - -
Show metadata panel
- - }> + Show metadata panel
}>
(DocumentV simulateMouseClick(child, e.clientX, e.clientY - 30, e.screenX, e.screenY - 30); }; + @observable _showLinkPopup = false; + @action + toggleLinkSearch = (e: React.PointerEvent) => { + this._showLinkPopup = !this._showLinkPopup; + e.stopPropagation(); + }; render() { if (!this.view0) return null; @@ -476,9 +495,20 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
-
- -
+ {this._showLinkPopup ? ( +
+ (link.linkDisplay = !this.props.views().lastElement()?.rootDoc.isLinkButton)} + linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.()} + linkFrom={() => this.props.views().lastElement()?.rootDoc} + /> +
+ ) : ( +
{this.linkButton}
+ )} + {(DocumentLinksButton.StartLink || Doc.UserDoc()['documentLinksButton-fullMenu']) && DocumentLinksButton.StartLink !== doc ? (
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index a29073f14..e3328fb4c 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -122,7 +122,6 @@ export class GestureOverlay extends Touchable { onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined, backgroundColor: data.backgroundColor, - _removeDropProperties: new List(['dropAction']), dragFactory: data.dragFactory, system: true, }) diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index e43b160b8..92c5708aa 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1414,7 +1414,7 @@ export class PropertiesView extends React.Component { changeFollowBehavior = action((follow: string) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = follow)); @undoBatch - changeAnimationBehavior = action((behavior: string) => this.sourceAnchor && (this.sourceAnchor.linkAnimEffect = behavior)); + changeAnimationBehavior = action((behavior: string) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimEffect = behavior)); @undoBatch changeEffectDirection = action((effect: PresEffectDirection) => this.sourceAnchor && (this.sourceAnchor.linkAnimDirection = effect)); @@ -1474,8 +1474,20 @@ export class PropertiesView extends React.Component { return selAnchor ?? (LinkManager.currentLink && this.destinationAnchor ? LinkManager.getOppositeAnchor(LinkManager.currentLink, this.destinationAnchor) : LinkManager.currentLink); } - toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc) => { - anchor && setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (anchor[prop] = !anchor[prop])))); + toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc, value: any = true, ovalue: any = false, cb: (val: any) => any = val => val) => { + anchor && + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoBatch( + action(() => { + anchor[prop] = anchor[prop] === value ? ovalue : value; + this.selectedDoc && cb(anchor[prop]); + }) + ) + ); }; @computed @@ -1516,7 +1528,7 @@ export class PropertiesView extends React.Component { if (change) scale += change; if (scale < 0.01) scale = 0.01; if (scale > 1) scale = 1; - this.sourceAnchor && (this.sourceAnchor.linkZoomScale = scale); + this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale); }; /** @@ -1532,7 +1544,7 @@ export class PropertiesView extends React.Component { render() { const isNovice = Doc.noviceMode; - const zoom = Number((NumCast(this.sourceAnchor?.linkZoomScale, 1) * 100).toPrecision(3)); + const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3)); const targZoom = this.sourceAnchor?.followLinkZoom; const indent = 30; const hasSelectedAnchor = SelectionManager.Views().some(dv => DocListCast(this.sourceAnchor?.links).includes(LinkManager.currentLink!)); @@ -1610,21 +1622,22 @@ export class PropertiesView extends React.Component {

Follow by

Animation

- this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}> {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => ( @@ -1642,9 +1655,9 @@ export class PropertiesView extends React.Component { '0.1', '0.1', '10', - NumCast(this.sourceAnchor?.linkTransitionTime) / 1000, + NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000, true, - (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.linkTransitionTime = timeInMS)), + (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)), indent )}{' '}
{
+
+

Ease Transitions

+ +
+
+

Capture Offset to Target

+ +
+
+

Center Target (no zoom)

+ +

Zoom %

-
+
this.setZoom(String(zoom), 0.1))}> @@ -1695,18 +1741,18 @@ export class PropertiesView extends React.Component {
- {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)} + {!targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
{ - smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight); + smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight, 'ease'); }; // let's dive in and get the actual document we want to drag/move around @@ -193,7 +193,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const top = found.getBoundingClientRect().top; const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0) { - smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop); + smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); } } const endFocus = async (moved: boolean) => (options?.afterFocus ? options?.afterFocus(moved) : ViewAdjustment.doNothing); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index e95622630..ba90ed8cd 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -120,7 +120,7 @@ export class CollectionPileView extends CollectionSubView() { const doc = this.childDocs[0]; doc.x = e.clientX; doc.y = e.clientY; - this.props.addDocTab(doc, OpenWhere.inParent) && (this.props.removeDocument?.(doc) || false); + this.props.addDocTab(doc, OpenWhere.inParentFromScreen) && (this.props.removeDocument?.(doc) || false); dist = 0; } } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 08aebc62d..acf59b5da 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -242,7 +242,7 @@ export class CollectionStackingView extends CollectionSubView { - smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight); + smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight, 'ease'); }; // let's dive in and get the actual document we want to drag/move around @@ -255,7 +255,7 @@ export class CollectionStackingView extends CollectionSubView options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index ac896a8fd..a1466bcd0 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -57,7 +57,7 @@ export class CollectionTimeView extends CollectionSubView() { async componentDidMount() { this.props.setContentView?.(this); //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), ""); - ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; useRightSplit(alias, shiftKey); "; runInAction(() => { this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index a61ae680b..e45e2a1cb 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -281,6 +281,11 @@ export class TabDocView extends React.Component { pinDoc.title = doc.title + ' (move)'; pinDoc.presMovement = PresMovement.Pan; } + if (pinProps?.currentFrame !== undefined) { + pinDoc.presCurrentFrame = pinProps?.currentFrame; + pinDoc.title = doc.title + ' (move)'; + pinDoc.presMovement = PresMovement.Pan; + } if (pinDoc.isInkMask) { pinDoc.presHideAfter = true; pinDoc.presHideBefore = true; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4818094de..6b9eb7916 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1186,7 +1186,7 @@ export class CollectionFreeFormView extends CollectionSubView { switch (where) { case OpenWhere.inParent: + return this.props.addDocument?.(doc) || false; + case OpenWhere.inParentFromScreen: return ( this.props.addDocument?.( (doc instanceof Doc ? [doc] : doc).map(doc => { @@ -1741,7 +1743,7 @@ export class CollectionFreeFormView extends CollectionSubView Doc | undefined; + linkCreateAnchor?: () => Doc | undefined; + linkCreated?: (link: Doc) => void; // groupType: string; // linkDoc: Doc; // docView: DocumentView; @@ -32,14 +35,10 @@ export class LinkPopup extends React.Component { // TODO: should check for valid URL @undoBatch - makeLinkToURL = (target: string, lcoation: string) => { - ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, 'onRadd:rightight', target, target); - }; + makeLinkToURL = (target: string, lcoation: string) => ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, OpenWhere.addRight, target, target); @action - onLinkChange = (e: React.ChangeEvent) => { - this.linkURL = e.target.value; - }; + onLinkChange = (e: React.ChangeEvent) => (this.linkURL = e.target.value); getPWidth = () => 500; getPHeight = () => 500; @@ -67,7 +66,9 @@ export class LinkPopup extends React.Component { Document={Doc.MySearcher} DataDoc={Doc.MySearcher} linkFrom={linkDoc} + linkCreateAnchor={this.props.linkCreateAnchor} linkSearch={true} + linkCreated={this.props.linkCreated} fieldKey="data" dropAction="move" isSelected={returnTrue} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index bf1f13a06..f8ef87fb1 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -184,7 +184,7 @@ export class CollectionFreeFormDocumentView extends DocComponent - {!DocumentLinksButton.LinkEditorDocView ? this.linkButtonInner : {title}
}>{this.linkButtonInner}} + {title}
}>{this.linkButtonInner}
); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c9fbe7a98..76cc6800a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -75,6 +75,7 @@ export enum OpenWhere { inPlace = 'inPlace', lightbox = 'lightbox', add = 'add', + addLeft = 'add:left', addRight = 'add:right', addBottom = 'add:bottom', dashboard = 'dashboard', @@ -82,7 +83,10 @@ export enum OpenWhere { fullScreen = 'fullScreen', toggle = 'toggle', replace = 'replace', + replaceRight = 'replace:right', + replaceLeft = 'replace:left', inParent = 'inParent', + inParentFromScreen = 'inParentFromScreen', } export enum OpenWhereMod { none = '', @@ -108,6 +112,7 @@ export interface DocFocusOptions { playAudio?: boolean; // whether to play audio annotation on focus toggleTarget?: boolean; // whether to toggle target on and off originatingDoc?: Doc; // document that triggered the focus + easeFunc?: 'linear' | 'ease'; // transition method for scrolling } export type DocAfterFocusFunc = (notFocused: boolean) => Promise; export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => void; @@ -737,7 +742,7 @@ export class DocumentViewInternal extends DocComponent{renderDoc}; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index b58a9affb..10897b48f 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -15,16 +15,17 @@ import { FieldView, FieldViewProps } from './FieldView'; import BigText from './LabelBigText'; import './LabelBox.scss'; - export interface LabelBoxProps { label?: string; } @observer -export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps)>() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); } +export class LabelBox extends ViewBoxBaseComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(LabelBox, fieldKey); + } public static LayoutStringWithTitle(fieldStr: string, label?: string) { - return !label ? LabelBox.LayoutString(fieldStr) : ``; //e.g., "" + return !label ? LabelBox.LayoutString(fieldStr) : ``; //e.g., "" } private dropDisposer?: DragManager.DragDropDisposer; private _timeout: any; @@ -35,11 +36,12 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro this._timeout && clearTimeout(this._timeout); } + getAnchor = () => { + return this.rootDoc; + }; + getTitle() { - return this.rootDoc["title-custom"] ? StrCast(this.rootDoc.title) : - this.props.label ? this.props.label : - typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) : - StrCast(this.rootDoc.title); + return this.rootDoc['title-custom'] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : typeof this.rootDoc[this.fieldKey] === 'string' ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title); } protected createDropTarget = (ele: HTMLDivElement) => { @@ -47,36 +49,42 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro if (ele) { this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document); } - } + }; - get paramsDoc() { return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc; } + get paramsDoc() { + return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc; + } specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - !Doc.noviceMode && funcs.push({ - description: "Clear Script Params", event: () => { - const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); - params?.map(p => this.paramsDoc[p] = undefined); - }, icon: "trash" - }); + !Doc.noviceMode && + funcs.push({ + description: 'Clear Script Params', + event: () => { + const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []); + params?.map(p => (this.paramsDoc[p] = undefined)); + }, + icon: 'trash', + }); - funcs.length && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "mouse-pointer" }); - } + funcs.length && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: funcs, icon: 'mouse-pointer' }); + }; @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { const docDragData = de.complete.docDragData; - const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); + const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []); const missingParams = params?.filter(p => !this.paramsDoc[p]); if (docDragData && missingParams?.includes((e.target as any).textContent)) { - this.paramsDoc[(e.target as any).textContent] = new List(docDragData.droppedDocuments.map((d, i) => - d.onDragStart ? docDragData.draggedDocuments[i] : d)); + this.paramsDoc[(e.target as any).textContent] = new List(docDragData.droppedDocuments.map((d, i) => (d.onDragStart ? docDragData.draggedDocuments[i] : d))); e.stopPropagation(); } - } + }; @observable _mouseOver = false; - @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; } + @computed get hoverColor() { + return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : 'unset'; + } fitTextToBox = (r: any): any => { const singleLine = BoolCast(this.rootDoc._singleLine, true); @@ -85,63 +93,73 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro fontSizeFactor: 1, minimumFontSize: NumCast(this.rootDoc._minFontSize, 8), maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000), - limitingDimension: "both", - horizontalAlign: "center", - verticalAlign: "center", - textAlign: "center", + limitingDimension: 'both', + horizontalAlign: 'center', + verticalAlign: 'center', + textAlign: 'center', singleLine, - whiteSpace: singleLine ? "nowrap" : "pre-wrap" + whiteSpace: singleLine ? 'nowrap' : 'pre-wrap', }; this._timeout = undefined; if (!r) return params; - if (!r.offsetHeight || !r.offsetWidth) return this._timeout = setTimeout(() => this.fitTextToBox(r)); + if (!r.offsetHeight || !r.offsetWidth) return (this._timeout = setTimeout(() => this.fitTextToBox(r))); const parent = r.parentNode; const parentStyle = parent.style; - parentStyle.display = ""; - parentStyle.alignItems = ""; - r.setAttribute("style", ""); - r.style.width = singleLine ? "" : "100%"; + parentStyle.display = ''; + parentStyle.alignItems = ''; + r.setAttribute('style', ''); + r.style.width = singleLine ? '' : '100%'; - r.style.textOverflow = "ellipsis"; - r.style.overflow = "hidden"; + r.style.textOverflow = 'ellipsis'; + r.style.overflow = 'hidden'; BigText(r, params); return params; - } + }; // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")") render() { - const boxParams = this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes - const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); + const boxParams = this.fitTextToBox(null); // this causes mobx to trigger re-render when data changes + const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []); const missingParams = params?.filter(p => !this.paramsDoc[p]); params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ... const label = this.getTitle(); return ( -
this._mouseOver = false)} - onMouseOver={action(() => this._mouseOver = true)} - ref={this.createDropTarget} onContextMenu={this.specificContextMenu} +
(this._mouseOver = false))} + onMouseOver={action(() => (this._mouseOver = true))} + ref={this.createDropTarget} + onContextMenu={this.specificContextMenu} style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}> -
- this.fitTextToBox(r))}> - {label.startsWith("#") ? (null) : label.replace(/([^a-zA-Z])/g, "$1\u200b")} +
+ this.fitTextToBox(r))}> + {label.startsWith('#') ? null : label.replace(/([^a-zA-Z])/g, '$1\u200b')}
-
- {!missingParams?.length ? (null) : missingParams.map(m =>
{m}
)} +
+ {!missingParams?.length + ? null + : missingParams.map(m => ( +
+ {m} +
+ ))}
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 64b186489..a3e83f047 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -241,7 +241,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + goTo = (scrollTop: number, duration: number, easeFunc: 'linear' | 'ease' | undefined) => { if (this._outerRef.current) { const iframeHeight = Math.max(scrollTop, this._scrollHeight - this.panelHeight()); if (duration) { - smoothScroll(duration, [this._outerRef.current], scrollTop); + smoothScroll(duration, [this._outerRef.current], scrollTop, easeFunc); this.setDashScrollTop(scrollTop, duration); } else { this.setDashScrollTop(scrollTop); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 9e91f6c46..b895043de 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1120,7 +1120,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent void); setupEditor(config: any, fieldKey: string) { const curText = Cast(this.dataDoc[this.fieldKey], RichTextField, null) || StrCast(this.dataDoc[this.fieldKey]); const rtfField = Cast((!curText && this.layoutDoc[this.fieldKey]) || this.dataDoc[fieldKey], RichTextField); @@ -1302,7 +1303,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { this.rootDoc._itemIndex = index; const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - if (activeItem.presActiveFrame !== undefined) { + const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame; + if (activeFrame !== undefined) { const transTime = NumCast(activeItem.presTransition, 500); - const context = DocCast(DocCast(activeItem.presentationTargetDoc).context); + const context = activeItem.presActiveFrame ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc); if (context) { const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.ComponentView as CollectionFreeFormView; if (ffview) { this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, ffview.childDocs.slice(), transTime); - context._currentFrame = NumCast(activeItem.presActiveFrame); + context._currentFrame = NumCast(activeFrame); } } } @@ -547,11 +549,12 @@ export class PresBox extends ViewBoxBaseComponent() { LightboxView.SetLightboxDoc(undefined); const options: DocFocusOptions = { willPan: activeItem.presMovement !== PresMovement.None, - willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump, - zoomScale: NumCast(activeItem.presZoom, 1), + willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, + zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500), noSelect: true, originatingDoc: activeItem, + easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, }; var containerDocContext = srcContext ? [srcContext] : []; @@ -747,8 +750,8 @@ export class PresBox extends ViewBoxBaseComponent() { }); movementName = action((activeItem: Doc) => { - if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) { - activeItem.presMovement = PresMovement.Zoom; + if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) { + return PresMovement.Zoom; } return StrCast(activeItem.presMovement); }); @@ -890,7 +893,7 @@ export class PresBox extends ViewBoxBaseComponent() { else this.regularSelect(doc, ref, drag, focus); }; - static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance.keyEvents(e); + static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance?.keyEvents(e); // Key for when the presentaiton is active @action @@ -1097,7 +1100,7 @@ export class PresBox extends ViewBoxBaseComponent() { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; - if (timeInMS > 10000) timeInMS = 10000; + if (timeInMS > 100000) timeInMS = 100000; setter(timeInMS); }; setTransitionTime = (number: String, change?: number) => { @@ -1155,6 +1158,12 @@ export class PresBox extends ViewBoxBaseComponent() { activeItem.openDocument = !activeItem.openDocument; this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument)); }; + @undoBatch + @action + updateEaseFunc = (activeItem: Doc) => { + activeItem.presEaseFunc = activeItem.presEaseFunc === 'linear' ? 'ease' : 'linear'; + this.selectedArray.forEach(doc => (doc.presEaseFunc = activeItem.presEaseFunc)); + }; @undoBatch @action @@ -1223,7 +1232,7 @@ export class PresBox extends ViewBoxBaseComponent() { let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2; if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); const effect = activeItem.presEffect ? activeItem.presEffect : PresMovement.None; - activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : PresMovement.Zoom; + // activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : PresMovement.Zoom; return (
() {
{isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.None)} + {presMovement(PresMovement.Center)} {presMovement(PresMovement.Zoom)} {presMovement(PresMovement.Pan)} {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.Jump)} @@ -1281,7 +1291,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)} + {PresBox.inputter('0.1', '0.1', '100', transitionSpeed, true, this.setTransitionTime)}
Fast
Medium
@@ -1317,6 +1327,11 @@ export class PresBox extends ViewBoxBaseComponent() { Lightbox
+ {'Transition movement style'}
}> +
this.updateEaseFunc(activeItem)}> + {`${StrCast(activeItem.presEaseFunc, 'ease')}`} +
+
{type === DocumentType.AUDIO || type === DocumentType.VID ? null : ( <> diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts index 034f7588b..8c8b83fbf 100644 --- a/src/client/views/nodes/trails/PresEnums.ts +++ b/src/client/views/nodes/trails/PresEnums.ts @@ -1,6 +1,7 @@ export enum PresMovement { Zoom = 'zoom', Pan = 'pan', + Center = 'center', Jump = 'jump', None = 'none', } diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index ee2ae10a7..265328036 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -210,14 +210,13 @@ export class AnchorMenu extends AntimodeMenu { ), - //NOTE: link popup is currently in progress {'Find document to link to selected text'}
}> , - , + , AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? ( <> ) : ( diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 0703ca9b4..906dff377 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -76,7 +76,7 @@ export class PDFViewer extends React.Component { private _lastSearch = false; private _viewerIsSetup = false; private _ignoreScroll = false; - private _initialScroll: Opt; + private _initialScroll: { loc: Opt; easeFunc: 'linear' | 'ease' | undefined } | undefined; private _forcedScroll = true; selectionText = () => this._selectionText; @@ -164,6 +164,8 @@ export class PDFViewer extends React.Component { } }; + _scrollStopper: undefined | (() => void); + // scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location, // otherwise it will scroll smoothly. scrollFocus = (doc: Doc, scrollTop: number, options: DocFocusOptions) => { @@ -173,12 +175,12 @@ export class PDFViewer extends React.Component { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); const scrollTo = doc.unrendered ? scrollTop : Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight)); if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) { - if (!this._pdfViewer) this._initialScroll = scrollTo; - else if (!options.instant) smoothScroll((focusSpeed = options.zoomTime??500), mainCont, scrollTo); + if (!this._pdfViewer) this._initialScroll = { loc: scrollTo, easeFunc: options.easeFunc }; + else if (!options.instant) this._scrollStopper = smoothScroll((focusSpeed = options.zoomTime ?? 500), mainCont, scrollTo, options.easeFunc, this._scrollStopper); else this._mainCont.current?.scrollTo({ top: Math.abs(scrollTo || 0) }); } } else { - this._initialScroll = NumCast(this.props.layoutDoc._scrollTop); + this._initialScroll = { loc: NumCast(this.props.layoutDoc._scrollTop), easeFunc: options.easeFunc }; } return focusSpeed; }; @@ -202,7 +204,7 @@ export class PDFViewer extends React.Component { this.gotoPage(NumCast(this.props.Document._curPage, 1)); } document.removeEventListener('pagesinit', this.pagesinit); - var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : ''; + var quickScroll: { loc?: string; easeFunc?: 'ease' | 'linear' } | undefined = { loc: this._initialScroll ? this._initialScroll.loc?.toString() : '', easeFunc: this._initialScroll ? this._initialScroll.easeFunc : undefined }; this._disposers.scale = reaction( () => NumCast(this.props.layoutDoc._viewScale, 1), scale => (this._pdfViewer.currentScaleValue = scale), @@ -213,7 +215,7 @@ export class PDFViewer extends React.Component { pos => { if (!this._ignoreScroll) { this._showWaiting && this.setupPdfJsViewer(); - const viewTrans = quickScroll ?? StrCast(this.props.Document._viewTransition); + const viewTrans = quickScroll?.loc ?? StrCast(this.props.Document._viewTransition); const durationMiliStr = viewTrans.match(/([0-9]*)ms/); const durationSecStr = viewTrans.match(/([0-9.]*)s/); const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0; @@ -221,7 +223,7 @@ export class PDFViewer extends React.Component { if (duration) { setTimeout( () => { - this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos); + this._mainCont.current && (this._scrollStopper = smoothScroll(duration, this._mainCont.current, pos, this._initialScroll?.easeFunc ?? 'ease', this._scrollStopper)); setTimeout(() => (this._forcedScroll = false), duration); }, this._mainCont.current ? 0 : 250 @@ -236,7 +238,7 @@ export class PDFViewer extends React.Component { ); quickScroll = undefined; if (this._initialScroll !== undefined && this._mainCont.current) { - this._mainCont.current?.scrollTo({ top: Math.abs(this._initialScroll || 0) }); + this._mainCont.current?.scrollTo({ top: Math.abs(this._initialScroll?.loc || 0) }); this._initialScroll = undefined; } }; @@ -295,7 +297,7 @@ export class PDFViewer extends React.Component { @action scrollToAnnotation = (scrollToAnnotation: Doc) => { if (scrollToAnnotation) { - this.scrollFocus(scrollToAnnotation, NumCast(scrollToAnnotation.y), {zoomTime: 500}); + this.scrollFocus(scrollToAnnotation, NumCast(scrollToAnnotation.y), { zoomTime: 500 }); Doc.linkFollowHighlight(scrollToAnnotation); } }; @@ -452,6 +454,7 @@ export class PDFViewer extends React.Component { }; onClick = (e: React.MouseEvent) => { + this._scrollStopper?.(); if (this._setPreviewCursor && e.button === 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { this._setPreviewCursor(e.clientX, e.clientY, false, false); } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index b78c8654f..aac488559 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -4,10 +4,12 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { StrCast } from '../../../fields/Types'; +import { DocCast, StrCast } from '../../../fields/Types'; +import { StopEvent } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; +import { LinkManager } from '../../util/LinkManager'; import { CollectionDockingView } from '../collections/CollectionDockingView'; import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; @@ -20,6 +22,8 @@ const ERROR = 0.03; export interface SearchBoxProps extends FieldViewProps { linkSearch: boolean; linkFrom?: (() => Doc | undefined) | undefined; + linkCreateAnchor?: () => Doc | undefined; + linkCreated?: (link: Doc) => void; } /** @@ -111,10 +115,11 @@ export class SearchBox extends ViewBoxBaseComponent() { // TODO: nda -- Change this method to change what happens when you click on the item. makeLink = action((linkTo: Doc) => { - if (this.props.linkFrom) { - const linkFrom = this.props.linkFrom(); + if (this.props.linkCreateAnchor) { + const linkFrom = this.props.linkCreateAnchor(); if (linkFrom) { - DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); + const link = DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); + link && this.props.linkCreated?.(link); } } }); @@ -380,7 +385,7 @@ export class SearchBox extends ViewBoxBaseComponent() { const query = StrCast(this._searchString); Doc.SetSearchQuery(query); - Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); + if (!this.props.linkSearch) Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); this._results.clear(); if (query) { @@ -437,6 +442,8 @@ export class SearchBox extends ViewBoxBaseComponent() { const resultsJSX = Array(); + const fromDoc = this.props.linkFrom?.(); + sortedResults.forEach(result => { var className = 'searchBox-results-scroll-view-result'; @@ -460,6 +467,13 @@ export class SearchBox extends ViewBoxBaseComponent() { e.stopPropagation(); } } + style={{ + fontWeight: DocListCast(fromDoc?.links).find( + link => Doc.AreProtosEqual(LinkManager.getOppositeAnchor(link, fromDoc!), result[0] as Doc) || Doc.AreProtosEqual(DocCast(LinkManager.getOppositeAnchor(link, fromDoc!)?.annotationOn), result[0] as Doc) + ) + ? 'bold' + : '', + }} className={className}>
{title as string}
{formattedType}
@@ -482,7 +496,10 @@ export class SearchBox extends ViewBoxBaseComponent() { defaultValue={''} autoComplete="off" onChange={this.onInputChange} - onKeyPress={e => (e.key === 'Enter' ? this.submitSearch() : null)} + onKeyPress={e => { + e.key === 'Enter' ? this.submitSearch() : null; + e.stopPropagation(); + }} type="text" placeholder="Search..." id="search-input" diff --git a/src/fields/util.ts b/src/fields/util.ts index f222e4555..7f4892bd6 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -449,7 +449,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any diff?.op === '$addToSet' ? { redo: () => { - receiver[prop].push(...diff.items.map((item: any) => (item.value ? item.value() : item))); + receiver[prop].push(...diff.items.map((item: any) => item.value ?? item)); lastValue = ObjectField.MakeCopy(receiver[prop]); }, undo: action(() => { @@ -459,7 +459,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any const ind = receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading); ind !== -1 && receiver[prop].splice(ind, 1); } else { - const ind = receiver[prop].indexOf(item.value ? item.value() : item); + const ind = receiver[prop].indexOf(item.value ?? item); ind !== -1 && receiver[prop].splice(ind, 1); } }); @@ -471,7 +471,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any ? { redo: action(() => { diff.items.forEach((item: any) => { - const ind = item instanceof SchemaHeaderField ? receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) : receiver[prop].indexOf(item.value ? item.value() : item); + const ind = item instanceof SchemaHeaderField ? receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) : receiver[prop].indexOf(item.value ?? item); ind !== -1 && receiver[prop].splice(ind, 1); }); lastValue = ObjectField.MakeCopy(receiver[prop]); @@ -483,8 +483,8 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any const ind = (prevValue as List).findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading); ind !== -1 && receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) === -1 && receiver[prop].splice(ind, 0, item); } else { - const ind = (prevValue as List).indexOf(item.value ? item.value() : item); - ind !== -1 && receiver[prop].indexOf(item.value ? item.value() : item) === -1 && receiver[prop].splice(ind, 0, item); + const ind = (prevValue as List).indexOf(item.value ?? item); + ind !== -1 && receiver[prop].indexOf(item.value ?? item) === -1 && receiver[prop].splice(ind, 0, item); } }); lastValue = ObjectField.MakeCopy(receiver[prop]); -- cgit v1.2.3-70-g09d2 From 84f728cffb94319b86be8d6cc478ce424ec45c2f Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 20 Jan 2023 11:17:38 -0500 Subject: removed tour map from lightbox. added option to create anchors without adding thm as annotations. made zoom of text an option for pres and links --- src/client/documents/Documents.ts | 4 +- src/client/util/DragManager.ts | 4 +- src/client/util/LinkFollower.ts | 10 +--- src/client/views/DocComponent.tsx | 7 +++ src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/InkingStroke.tsx | 4 +- src/client/views/LightboxView.tsx | 56 +++++----------------- src/client/views/MarqueeAnnotator.tsx | 8 ++-- src/client/views/PropertiesView.tsx | 10 ++++ .../collections/CollectionStackedTimeline.tsx | 18 +++---- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 14 +++--- src/client/views/collections/TabDocView.tsx | 2 +- .../CollectionFreeFormLinkView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 +++-- src/client/views/nodes/AudioBox.tsx | 7 ++- src/client/views/nodes/DocumentLinksButton.tsx | 6 +-- src/client/views/nodes/DocumentView.tsx | 14 +++--- src/client/views/nodes/FunctionPlotBox.tsx | 7 +-- src/client/views/nodes/ImageBox.tsx | 8 ++-- src/client/views/nodes/LabelBox.tsx | 4 +- src/client/views/nodes/LinkDocPreview.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 5 +- src/client/views/nodes/PDFBox.tsx | 8 ++-- src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 11 +++-- src/client/views/nodes/WebBox.tsx | 6 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 39 +++++++-------- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 13 +++-- src/client/views/pdf/AnchorMenu.tsx | 13 ++--- src/client/views/pdf/Annotation.tsx | 8 ++-- src/client/views/pdf/PDFViewer.tsx | 4 +- 33 files changed, 157 insertions(+), 159 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b51fcb454..80b040cc0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1310,13 +1310,13 @@ export namespace DocUtils { options?.afterFocus?.(false); } - export let ActiveRecordings: { props: FieldViewProps; getAnchor: () => Doc }[] = []; + export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = []; export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) { broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1)); return DocUtils.ActiveRecordings.map(audio => { const sourceDoc = getSourceDoc(); - const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor() || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline'); + const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor(true) || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline'); link && (link.followLinkLocation = OpenWhere.addRight); return link; }); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d0690fa10..a56f87075 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -251,8 +251,8 @@ export namespace DragManager { } // drags a linker button and creates a link on drop - export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | (() => Doc), downX: number, downY: number, options?: DragOptions) { - StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.() ?? sourceView.rootDoc), downX, downY, options); + export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | ((addAsAnnotation: boolean) => Doc), downX: number, downY: number, options?: DragOptions) { + StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.(true) ?? sourceView.rootDoc), downX, downY, options); } // drags a column from a schema view diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 0f216e349..5bdfca54a 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -111,15 +111,9 @@ export class LinkFollower { easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, effect: sourceDoc, originatingDoc: sourceDoc, - zoomTextSelections: false, + zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText), }; - if (target.TourMap) { - const fieldKey = Doc.LayoutFieldKey(target); - const tour = DocListCast(target[fieldKey]).reverse(); - LightboxView.SetLightboxDoc(currentContext, undefined, tour); - setTimeout(LightboxView.Next); - allFinished(); - } else if (target.type === DocumentType.PRES) { + if (target.type === DocumentType.PRES) { const containerAnnoDoc = Cast(sourceDoc, Doc, null); const containerDoc = containerAnnoDoc || sourceDoc; var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index c9c09b63b..78ab2b3d4 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -130,6 +130,13 @@ export function ViewBoxAnnotatableComponent

() isAnyChildContentActive = () => this._isAnyChildContentActive; + isContentActive = (outsideReaction?: boolean) => + this.props.isContentActive?.() === false + ? false + : Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.isAnyChildContentActive() + ? true + : undefined; + lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 90c6c040c..f06dc93e3 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -501,7 +501,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV key="popup" showPopup={this._showLinkPopup} linkCreated={link => (link.linkDisplay = !this.props.views().lastElement()?.rootDoc.isLinkButton)} - linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.()} + linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)} linkFrom={() => this.props.views().lastElement()?.rootDoc} />

diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index a6fa2f04b..319a9419e 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -78,8 +78,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1); - getAnchor = () => { - return this._subContentView?.getAnchor?.() || this.rootDoc; + getAnchor = (addAsAnnotation: boolean) => { + return this._subContentView?.getAnchor?.(addAsAnnotation) || this.rootDoc; }; scrollFocus = (textAnchor: Doc, options: DocFocusOptions) => { diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index d79b696a3..3627aa783 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -37,7 +37,6 @@ export class LightboxView extends React.Component { @observable private static _doc: Opt; @observable private static _docTarget: Opt; @observable private static _docFilters: string[] = []; // filters - @observable private static _tourMap: Opt = []; // list of all tours available from the current target private static _savedState: Opt<{ panX: Opt; panY: Opt; scale: Opt; scrollTop: Opt }>; private static _history: Opt<{ doc: Doc; target?: Doc }[]> = []; @observable private static _future: Opt = []; @@ -90,13 +89,6 @@ export class LightboxView extends React.Component { this._doc = doc; this._layoutTemplate = layoutTemplate; this._docTarget = target || doc; - this._tourMap = DocListCast(doc?.links) - .map(link => { - const opp = LinkManager.getOppositeAnchor(link, doc!); - return opp?.TourMap ? opp : undefined; - }) - .filter(m => m) - .map(m => m!); return true; } @@ -164,7 +156,7 @@ export class LightboxView extends React.Component { const target = (LightboxView._docTarget = this._future?.pop()); const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target); if (targetDocView && target) { - const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.() || target).lastElement(); + const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement(); l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen'); targetDocView.focus(target, { originalTarget: target, willPanZoom: true, zoomScale: 0.9 }); if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target }); @@ -189,13 +181,6 @@ export class LightboxView extends React.Component { LightboxView.SetLightboxDoc(target); } } - LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links) - .map(link => { - const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); - return opp?.TourMap ? opp : undefined; - }) - .filter(m => m) - .map(m => m!); } @action public static Previous() { @@ -214,13 +199,6 @@ export class LightboxView extends React.Component { LightboxView.SetLightboxDoc(doc, target); } if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc); - LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links) - .map(link => { - const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); - return opp?.TourMap ? opp : undefined; - }) - .filter(m => m) - .map(m => m!); } @action stepInto = () => { @@ -231,27 +209,20 @@ export class LightboxView extends React.Component { history: LightboxView._history, saved: LightboxView._savedState, }); - const tours = LightboxView._tourMap; - if (tours && tours.length) { - const fieldKey = Doc.LayoutFieldKey(tours[0]); - LightboxView._future?.push(...DocListCast(tours[0][fieldKey]).reverse()); - } else { - const coll = LightboxView._docTarget; - if (coll) { - const fieldKey = Doc.LayoutFieldKey(coll); - const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])]; - const links = DocListCast(coll.links) - .map(link => LinkManager.getOppositeAnchor(link, coll)) - .filter(doc => doc) - .map(doc => doc!); - LightboxView.SetLightboxDoc(coll, undefined, contents.length ? contents : links); - TabDocView.PinDoc(coll, { hidePresBox: true }); - } + const coll = LightboxView._docTarget; + if (coll) { + const fieldKey = Doc.LayoutFieldKey(coll); + const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])]; + const links = DocListCast(coll.links) + .map(link => LinkManager.getOppositeAnchor(link, coll)) + .filter(doc => doc) + .map(doc => doc!); + LightboxView.SetLightboxDoc(coll, undefined, contents.length ? contents : links); + TabDocView.PinDoc(coll, { hidePresBox: true }); } }; future = () => LightboxView._future; - tourMap = () => LightboxView._tourMap; render() { let downx = 0, downy = 0; @@ -345,7 +316,7 @@ export class LightboxView extends React.Component { }, this.future()?.length.toString() )} - +
{ } interface LightboxTourBtnProps { navBtn: (left: Opt, bottom: Opt, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element; - tourMap: () => Opt; future: () => Opt; stepInto: () => void; } @@ -410,7 +380,7 @@ export class LightboxTourBtn extends React.Component { e.stopPropagation(); this.props.stepInto(); }, - StrCast(this.props.tourMap()?.lastElement()?.TourMap) + '' ); } } diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index bf1242346..b1965c5c8 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -52,8 +52,8 @@ export class MarqueeAnnotator extends React.Component { AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true)); AnchorMenu.Instance.OnAudio = unimplementedFunction; AnchorMenu.Instance.Highlight = this.highlight; - AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations); - AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor; + AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations, addAsAnnotation); + AnchorMenu.Instance.onMakeAnchor = () => AnchorMenu.Instance.GetAnchor(undefined, true); } @action @@ -194,11 +194,11 @@ export class MarqueeAnnotator extends React.Component { return textRegionAnno; }; @action - highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap) => { + highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => { // creates annotation documents for current highlights const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DataSym]); const annotationDoc = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations); - !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc); + addAsAnnotation && !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc); return (annotationDoc as Doc) ?? undefined; }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 8d495d286..af50478b0 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1679,6 +1679,16 @@ export class PropertiesView extends React.Component {
+
+

Zoom Text Selections

+ +

Toggle Target (Show/Hide)

, - {'toggle pushpin behavior'}
}> -
}> +
, diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 7069ff399..d8e44ae9d 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -55,9 +55,9 @@ class RegionAnnotation extends React.Component { pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); @undoBatch - makePushpin = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); + makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); - isPushpin = () => BoolCast(this.annoTextRegion.followLinkToggle); + isTargetToggler = () => BoolCast(this.annoTextRegion.followLinkToggle); @action onPointerDown = (e: React.PointerEvent) => { @@ -67,8 +67,8 @@ class RegionAnnotation extends React.Component { AnchorMenu.Instance.Pinned = false; AnchorMenu.Instance.AddTag = this.addTag.bind(this); AnchorMenu.Instance.PinToPres = this.pinToPres; - AnchorMenu.Instance.MakePushpin = this.makePushpin; - AnchorMenu.Instance.IsPushpin = this.isPushpin; + AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; + AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); e.stopPropagation(); } else if (e.button === 0) { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f95d5ac2e..b0b7816b8 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -135,7 +135,7 @@ export class PDFViewer extends React.Component { copy = (e: ClipboardEvent) => { if (this.props.isContentActive() && e.clipboardData) { e.clipboardData.setData('text/plain', this._selectionText); - const anchor = this._getAnchor(); + const anchor = this._getAnchor(undefined, false); if (anchor) { anchor.textCopied = true; e.clipboardData.setData('dash/pdfAnchor', anchor[Id]); @@ -317,7 +317,7 @@ export class PDFViewer extends React.Component { this._ignoreScroll = false; if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio this._scrollTimer = setTimeout(() => { - DocUtils.MakeLinkToActiveAudio(() => this.props.DocumentView?.().ComponentView?.getAnchor!()!, false); + DocUtils.MakeLinkToActiveAudio(() => this.props.DocumentView?.().ComponentView?.getAnchor!(true)!, false); this._scrollTimer = undefined; }, 200); } -- cgit v1.2.3-70-g09d2 From 555d67a31adbe7e6d42f7f7805ba1348e6d505f6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 24 Jan 2023 17:05:25 -0500 Subject: stopped storing presCollection in PresBox in favor of computing it. added anchor menu option for viewing linked trail. fixed showing slected slides in presbox when link with up is used. --- package-lock.json | 1621 ++++++++------------ package.json | 2 +- src/client/util/DocumentManager.ts | 26 +- src/client/views/AntimodeMenu.tsx | 143 +- src/client/views/DocumentButtonBar.tsx | 30 +- src/client/views/MainView.tsx | 1 + .../collectionFreeForm/MarqueeOptionsMenu.tsx | 60 +- src/client/views/nodes/DocumentView.tsx | 4 + src/client/views/nodes/button/FontIconBox.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 12 +- src/client/views/nodes/formattedText/marks_rts.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 307 ++-- src/client/views/nodes/trails/PresElementBox.tsx | 10 +- src/client/views/pdf/AnchorMenu.tsx | 145 +- src/client/views/pdf/Annotation.tsx | 7 - src/client/views/search/SearchBox.tsx | 13 +- 17 files changed, 1058 insertions(+), 1333 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/package-lock.json b/package-lock.json index 26e7a41d7..547a6e1d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2288,7 +2288,7 @@ "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", "dev": true }, "@types/strip-json-comments": { @@ -2639,7 +2639,7 @@ "textarea-caret": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.0.2.tgz", - "integrity": "sha1-82DEhpmqGr9xhoCkOjGoUGZcLK8=" + "integrity": "sha512-gRzeti2YS4did7UJnPQ47wrjD+vp+CJIe9zbsu0bJ987d8QVLvLNG9757rqiQTIy4hGIeFauTTJt5Xkn51UkXg==" } } }, @@ -2738,7 +2738,7 @@ "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==" }, "agent-base": { "version": "6.0.2", @@ -3530,7 +3530,7 @@ "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" }, "bail": { "version": "2.0.2", @@ -3600,7 +3600,7 @@ "base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" }, "base64-js": { "version": "1.5.1", @@ -4577,7 +4577,7 @@ "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==" }, "component-emitter": { "version": "1.3.0", @@ -4587,7 +4587,7 @@ "component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==" }, "compress-brotli": { "version": "1.3.8", @@ -5295,7 +5295,7 @@ "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=" + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==" }, "cyclist": { "version": "1.0.1", @@ -6211,7 +6211,7 @@ "dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", "dev": true, "requires": { "xtend": "^4.0.0" @@ -6341,7 +6341,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "ws": { "version": "7.4.6", @@ -8711,7 +8711,7 @@ "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q==", + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", @@ -9349,14 +9349,14 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" } } }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" }, "has-flag": { "version": "3.0.0", @@ -9949,7 +9949,7 @@ "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==" }, "inflight": { "version": "1.0.6", @@ -11002,7 +11002,7 @@ "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "requires": { "graceful-fs": "^4.1.6" } @@ -11426,7 +11426,7 @@ "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" }, "lodash.isplainobject": { "version": "4.0.6", @@ -11687,7 +11687,7 @@ "mathquill": { "version": "0.10.1-a", "resolved": "https://registry.npmjs.org/mathquill/-/mathquill-0.10.1-a.tgz", - "integrity": "sha1-vyylaQEAY6w0vNXVKa3Ag3zVPD8=", + "integrity": "sha512-snSAEwAtwdwBFSor+nVBnWWQtTw67kgAgKMyAIxuz4ZPboy0qkWZmd7BL3lfOXp/INihhRlU1PcfaAtDaRhmzA==", "requires": { "jquery": "^1.12.3" }, @@ -11695,7 +11695,7 @@ "jquery": { "version": "1.12.4", "resolved": "https://registry.npmjs.org/jquery/-/jquery-1.12.4.tgz", - "integrity": "sha1-AeHfuikP5z3rp3zurLD5ui/sngw=" + "integrity": "sha512-UEVp7PPK9xXYSk8xqXCJrkXnKZtlgWkd2GsAQbMRFK6S/ePU2JN5G2Zum8hIVjzR3CpdfSqdqAzId/xd4TJHeg==" } } }, @@ -13234,9 +13234,9 @@ "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" }, "npm": { - "version": "6.14.17", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.17.tgz", - "integrity": "sha512-CxEDn1ydVRPDl4tHrlnq+WevYAhv4GF2AEHzJKQ4prZDZ96IS3Uo6t0Sy6O9kB6XzqkI+J00WfYCqqk0p6IJ1Q==", + "version": "6.14.18", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.18.tgz", + "integrity": "sha512-p3SjqSchSuNQUqbJBgwdv0L3O6bKkaSfQrQzJsskNpNKLg0g37c5xTXFV0SqTlX9GWvoGxBELVJMRWq0J8oaLA==", "requires": { "JSONStream": "^1.3.5", "abbrev": "~1.1.1", @@ -13245,9 +13245,9 @@ "aproba": "^2.0.0", "archy": "~1.0.0", "bin-links": "^1.1.8", - "bluebird": "^3.5.5", + "bluebird": "^3.7.2", "byte-size": "^5.0.1", - "cacache": "^12.0.3", + "cacache": "^12.0.4", "call-limit": "^1.1.1", "chownr": "^1.1.4", "ci-info": "^2.0.0", @@ -13255,19 +13255,19 @@ "cli-table3": "^0.5.1", "cmd-shim": "^3.0.3", "columnify": "~1.5.4", - "config-chain": "^1.1.12", + "config-chain": "^1.1.13", "debuglog": "*", "detect-indent": "~5.0.0", "detect-newline": "^2.1.0", - "dezalgo": "~1.0.3", + "dezalgo": "^1.0.4", "editor": "~1.0.0", - "figgy-pudding": "^3.5.1", + "figgy-pudding": "^3.5.2", "find-npm-prefix": "^1.0.2", "fs-vacuum": "~1.2.10", "fs-write-stream-atomic": "~1.0.10", "gentle-fs": "^2.3.1", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", + "glob": "^7.2.3", + "graceful-fs": "^4.2.10", "has-unicode": "~2.0.1", "hosted-git-info": "^2.8.9", "iferr": "^1.0.2", @@ -13277,7 +13277,7 @@ "inherits": "^2.0.4", "ini": "^1.3.8", "init-package-json": "^1.10.3", - "is-cidr": "^3.0.0", + "is-cidr": "^3.1.1", "json-parse-better-errors": "^1.0.2", "lazy-property": "~1.0.0", "libcipm": "^4.0.8", @@ -13288,7 +13288,7 @@ "libnpmsearch": "^2.0.2", "libnpmteam": "^1.0.2", "libnpx": "^10.2.4", - "lock-verify": "^2.1.0", + "lock-verify": "^2.2.2", "lockfile": "^1.0.4", "lodash._baseindexof": "*", "lodash._baseuniq": "~4.6.0", @@ -13302,11 +13302,11 @@ "lodash.uniq": "~4.5.0", "lodash.without": "~4.4.0", "lru-cache": "^5.1.1", - "meant": "^1.0.2", + "meant": "^1.0.3", "mississippi": "^3.0.0", - "mkdirp": "^0.5.5", + "mkdirp": "^0.5.6", "move-concurrently": "^1.0.1", - "node-gyp": "^5.1.0", + "node-gyp": "^5.1.1", "nopt": "^4.0.3", "normalize-package-data": "^2.5.0", "npm-audit-report": "^1.3.3", @@ -13327,19 +13327,19 @@ "path-is-inside": "~1.0.2", "promise-inflight": "~1.0.1", "qrcode-terminal": "^0.12.0", - "query-string": "^6.8.2", - "qw": "~1.0.1", + "query-string": "^6.14.1", + "qw": "^1.0.2", "read": "~1.0.7", "read-cmd-shim": "^1.0.5", "read-installed": "~4.0.3", - "read-package-json": "^2.1.1", + "read-package-json": "^2.1.2", "read-package-tree": "^5.3.1", "readable-stream": "^3.6.0", "readdir-scoped-modules": "^1.1.0", - "request": "^2.88.0", + "request": "^2.88.2", "retry": "^0.12.0", "rimraf": "^2.7.1", - "safe-buffer": "^5.1.2", + "safe-buffer": "^5.2.1", "semver": "^5.7.1", "sha": "^3.0.0", "slide": "~1.1.6", @@ -13355,7 +13355,7 @@ "unique-filename": "^1.1.1", "unpipe": "~1.0.0", "update-notifier": "^2.5.0", - "uuid": "^3.3.3", + "uuid": "^3.4.0", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "~3.0.0", "which": "^1.3.1", @@ -13363,6 +13363,14 @@ "write-file-atomic": "^2.4.3" }, "dependencies": { + "@iarna/cli": { + "version": "2.1.0", + "bundled": true, + "requires": { + "glob": "^7.1.2", + "signal-exit": "^3.0.2" + } + }, "JSONStream": { "version": "1.3.5", "bundled": true, @@ -13373,70 +13381,59 @@ }, "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "bundled": true }, "agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "bundled": true, "requires": { "es6-promisify": "^5.0.0" } }, "agentkeepalive": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "bundled": true, "requires": { "humanize-ms": "^1.2.1" } }, "ansi-align": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "bundled": true, "requires": { "string-width": "^2.0.0" } }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "bundled": true }, "ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "bundled": true, "requires": { "color-convert": "^1.9.0" } }, "ansicolors": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" + "bundled": true }, "ansistyles": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", - "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=" + "bundled": true }, "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "bundled": true }, "archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + "bundled": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "bundled": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -13444,8 +13441,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13454,69 +13450,70 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "asap": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "bundled": true }, "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "version": "0.2.6", + "bundled": true, "requires": { "safer-buffer": "~2.1.0" } }, "assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "bundled": true }, "asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "bundled": true }, "aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "bundled": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + "version": "1.11.0", + "bundled": true }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "bundled": true }, "bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "optional": true, + "bundled": true, "requires": { "tweetnacl": "^0.14.3" } }, "bin-links": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.8.tgz", - "integrity": "sha512-KgmVfx+QqggqP9dA3iIc5pA4T1qEEEL+hOhOhNPaUm77OTrJoOXE/C05SJLNJe6m/2wUK7F1tDSou7n5TfCDzQ==", + "bundled": true, "requires": { "bluebird": "^3.5.3", "cmd-shim": "^3.0.0", @@ -13527,14 +13524,12 @@ } }, "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" + "version": "3.7.2", + "bundled": true }, "boxen": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "bundled": true, "requires": { "ansi-align": "^2.0.0", "camelcase": "^4.0.0", @@ -13547,8 +13542,7 @@ }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13556,28 +13550,23 @@ }, "buffer-from": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" + "bundled": true }, "builtins": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" + "bundled": true }, "byline": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", - "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=" + "bundled": true }, "byte-size": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", - "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==" + "bundled": true }, "cacache": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", - "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "version": "12.0.4", + "bundled": true, "requires": { "bluebird": "^3.5.5", "chownr": "^1.1.1", @@ -13598,28 +13587,23 @@ }, "call-limit": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz", - "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==" + "bundled": true }, "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + "bundled": true }, "capture-stack-trace": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + "bundled": true }, "caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "bundled": true }, "chalk": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "bundled": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -13628,31 +13612,26 @@ }, "chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "bundled": true }, "ci-info": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + "bundled": true }, "cidr-regex": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz", - "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==", + "bundled": true, "requires": { "ip-regex": "^2.1.0" } }, "cli-boxes": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" + "bundled": true }, "cli-columns": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz", - "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=", + "bundled": true, "requires": { "string-width": "^2.0.0", "strip-ansi": "^3.0.1" @@ -13660,8 +13639,7 @@ }, "cli-table3": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "bundled": true, "requires": { "colors": "^1.1.2", "object-assign": "^4.1.0", @@ -13670,8 +13648,7 @@ }, "cliui": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "bundled": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -13680,18 +13657,15 @@ "dependencies": { "ansi-regex": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + "bundled": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "bundled": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -13700,8 +13674,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "bundled": true, "requires": { "ansi-regex": "^4.1.0" } @@ -13710,13 +13683,11 @@ }, "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "bundled": true }, "cmd-shim": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz", - "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==", + "bundled": true, "requires": { "graceful-fs": "^4.1.2", "mkdirp": "~0.5.0" @@ -13724,54 +13695,46 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "bundled": true }, "color-convert": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "bundled": true, "requires": { "color-name": "^1.1.1" } }, "color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "bundled": true }, "colors": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "bundled": true, "optional": true }, "columnify": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", - "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "bundled": true, "requires": { "strip-ansi": "^3.0.0", "wcwidth": "^1.0.0" } }, "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.8", + "bundled": true, "requires": { "delayed-stream": "~1.0.0" } }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "bundled": true }, "concat-stream": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "bundled": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -13781,8 +13744,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13791,22 +13753,32 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "version": "1.1.13", + "bundled": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -13814,8 +13786,7 @@ }, "configstore": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz", - "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==", + "bundled": true, "requires": { "dot-prop": "^4.2.1", "graceful-fs": "^4.1.2", @@ -13827,13 +13798,11 @@ }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "bundled": true }, "copy-concurrently": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "bundled": true, "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -13845,33 +13814,28 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "bundled": true } } }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "bundled": true }, "create-error-class": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "bundled": true, "requires": { "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "bundled": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", @@ -13880,8 +13844,7 @@ "dependencies": { "lru-cache": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "bundled": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -13889,104 +13852,87 @@ }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "bundled": true } } }, "crypto-random-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + "bundled": true }, "cyclist": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" + "bundled": true }, "dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "bundled": true, "requires": { "assert-plus": "^1.0.0" } }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "bundled": true, "requires": { "ms": "2.0.0" }, "dependencies": { "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "bundled": true } } }, "debuglog": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" + "bundled": true }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "bundled": true }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + "version": "0.2.2", + "bundled": true }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "bundled": true }, "defaults": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "bundled": true, "requires": { "clone": "^1.0.2" } }, "define-properties": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "bundled": true, "requires": { "object-keys": "^1.0.12" } }, "delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "bundled": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "bundled": true }, "detect-indent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" + "bundled": true }, "detect-newline": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + "bundled": true }, "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "version": "1.0.4", + "bundled": true, "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -13994,26 +13940,22 @@ }, "dot-prop": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", - "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==", + "bundled": true, "requires": { "is-obj": "^1.0.0" } }, "dotenv": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" + "bundled": true }, "duplexer3": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + "bundled": true }, "duplexify": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "bundled": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -14023,8 +13965,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14033,23 +13974,32 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "optional": true, + "bundled": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -14057,52 +14007,44 @@ }, "editor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", - "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" + "bundled": true }, "emoji-regex": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "bundled": true }, "encoding": { "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "bundled": true, "requires": { "iconv-lite": "~0.4.13" } }, "end-of-stream": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "bundled": true, "requires": { "once": "^1.4.0" } }, "env-paths": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" + "version": "2.2.1", + "bundled": true }, "err-code": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + "bundled": true }, "errno": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "bundled": true, "requires": { "prr": "~1.0.1" } }, "es-abstract": { "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "bundled": true, "requires": { "es-to-primitive": "^1.1.1", "function-bind": "^1.1.1", @@ -14113,8 +14055,7 @@ }, "es-to-primitive": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "bundled": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -14123,26 +14064,22 @@ }, "es6-promise": { "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + "bundled": true }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "bundled": true, "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "bundled": true }, "execa": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "bundled": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", @@ -14155,40 +14092,37 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "bundled": true } } }, "extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "bundled": true }, "extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "bundled": true }, "fast-json-stable-stringify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "bundled": true }, "figgy-pudding": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" + "version": "3.5.2", + "bundled": true + }, + "filter-obj": { + "version": "1.1.0", + "bundled": true }, "find-npm-prefix": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", - "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==" + "bundled": true }, "flush-write-stream": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "bundled": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.4" @@ -14196,8 +14130,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14206,37 +14139,45 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "bundled": true }, "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "version": "2.3.3", + "bundled": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, "from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "bundled": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -14244,8 +14185,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14254,30 +14194,39 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "fs-minipass": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "bundled": true, "requires": { "minipass": "^2.6.0" }, "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -14287,8 +14236,7 @@ }, "fs-vacuum": { "version": "1.2.10", - "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", - "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", + "bundled": true, "requires": { "graceful-fs": "^4.1.2", "path-is-inside": "^1.0.1", @@ -14297,8 +14245,7 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "bundled": true, "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -14308,13 +14255,11 @@ "dependencies": { "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "bundled": true }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14323,32 +14268,40 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "bundled": true }, "function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "bundled": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -14362,13 +14315,11 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -14379,13 +14330,11 @@ }, "genfun": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", - "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==" + "bundled": true }, "gentle-fs": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.1.tgz", - "integrity": "sha512-OlwBBwqCFPcjm33rF2BjW+Pr6/ll2741l+xooiwTCeaX2CA1ZuclavyMBe0/KlR21/XGsgY6hzEQZ15BdNa13Q==", + "bundled": true, "requires": { "aproba": "^1.1.2", "chownr": "^1.1.2", @@ -14402,62 +14351,63 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "bundled": true } } }, "get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "bundled": true }, "get-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "bundled": true, "requires": { "pump": "^3.0.0" } }, "getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "bundled": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "bundled": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "global-dirs": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "bundled": true, "requires": { "ini": "^1.3.4" } }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "bundled": true, "requires": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", @@ -14474,25 +14424,21 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "bundled": true } } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + "version": "4.2.10", + "bundled": true }, "har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "bundled": true }, "har-validator": { "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "bundled": true, "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -14500,8 +14446,7 @@ "dependencies": { "ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "bundled": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14511,53 +14456,44 @@ }, "fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "bundled": true }, "json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "bundled": true } } }, "has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "bundled": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "bundled": true }, "has-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + "bundled": true }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "bundled": true }, "hosted-git-info": { "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "bundled": true }, "http-cache-semantics": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + "bundled": true }, "http-proxy-agent": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "bundled": true, "requires": { "agent-base": "4", "debug": "3.1.0" @@ -14565,8 +14501,7 @@ }, "http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "bundled": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -14575,8 +14510,7 @@ }, "https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "bundled": true, "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -14584,52 +14518,44 @@ }, "humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "bundled": true, "requires": { "ms": "^2.0.0" } }, "iconv-lite": { "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "bundled": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "iferr": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", - "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==" + "bundled": true }, "ignore-walk": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "bundled": true, "requires": { "minimatch": "^3.0.4" } }, "import-lazy": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + "bundled": true }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "bundled": true }, "infer-owner": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + "bundled": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -14637,18 +14563,15 @@ }, "inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "bundled": true }, "ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "bundled": true }, "init-package-json": { "version": "1.10.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", - "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", + "bundled": true, "requires": { "glob": "^7.1.1", "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", @@ -14662,59 +14585,50 @@ }, "ip": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "bundled": true }, "ip-regex": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + "bundled": true }, "is-callable": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + "bundled": true }, "is-ci": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "bundled": true, "requires": { "ci-info": "^1.5.0" }, "dependencies": { "ci-info": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" + "bundled": true } } }, "is-cidr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz", - "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==", + "version": "3.1.1", + "bundled": true, "requires": { "cidr-regex": "^2.0.10" } }, "is-date-object": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + "bundled": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "requires": { "number-is-nan": "^1.0.0" } }, "is-installed-globally": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "bundled": true, "requires": { "global-dirs": "^0.1.0", "is-path-inside": "^1.0.0" @@ -14722,103 +14636,88 @@ }, "is-npm": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" + "bundled": true }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + "bundled": true }, "is-path-inside": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "bundled": true, "requires": { "path-is-inside": "^1.0.1" } }, "is-redirect": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + "bundled": true }, "is-regex": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "bundled": true, "requires": { "has": "^1.0.1" } }, "is-retry-allowed": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + "bundled": true }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "bundled": true }, "is-symbol": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "bundled": true, "requires": { "has-symbols": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "bundled": true }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "bundled": true }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "bundled": true }, "isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "bundled": true }, "jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "bundled": true }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "bundled": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "bundled": true }, "json-schema": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + "bundled": true }, "json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "bundled": true }, "jsonparse": { "version": "1.3.1", - "resolved": false, - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + "bundled": true }, "jsprim": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "bundled": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -14828,21 +14727,18 @@ }, "latest-version": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "bundled": true, "requires": { "package-json": "^4.0.0" } }, "lazy-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", - "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=" + "bundled": true }, "libcipm": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.8.tgz", - "integrity": "sha512-IN3hh2yDJQtZZ5paSV4fbvJg4aHxCCg5tcZID/dSVlTuUiWktsgaldVljJv6Z5OUlYspx6xQkbR0efNodnIrOA==", + "bundled": true, "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.1", @@ -14863,8 +14759,7 @@ }, "libnpm": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz", - "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==", + "bundled": true, "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.3", @@ -14890,8 +14785,7 @@ }, "libnpmaccess": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz", - "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==", + "bundled": true, "requires": { "aproba": "^2.0.0", "get-stream": "^4.0.0", @@ -14901,8 +14795,7 @@ }, "libnpmconfig": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", - "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1", "find-up": "^3.0.0", @@ -14911,16 +14804,14 @@ "dependencies": { "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "bundled": true, "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "bundled": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -14928,31 +14819,27 @@ }, "p-limit": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "bundled": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "bundled": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "bundled": true } } }, "libnpmhook": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz", - "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -14962,8 +14849,7 @@ }, "libnpmorg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz", - "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -14973,8 +14859,7 @@ }, "libnpmpublish": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz", - "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.5.1", @@ -14989,8 +14874,7 @@ }, "libnpmsearch": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz", - "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1", "get-stream": "^4.0.0", @@ -14999,8 +14883,7 @@ }, "libnpmteam": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz", - "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -15010,8 +14893,7 @@ }, "libnpx": { "version": "10.2.4", - "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.4.tgz", - "integrity": "sha512-BPc0D1cOjBeS8VIBKUu5F80s6njm0wbVt7CsGMrIcJ+SI7pi7V0uVPGpEMH9H5L8csOcclTxAXFE2VAsJXUhfA==", + "bundled": true, "requires": { "dotenv": "^5.0.1", "npm-package-arg": "^6.0.0", @@ -15024,31 +14906,28 @@ } }, "lock-verify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", - "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", + "version": "2.2.2", + "bundled": true, "requires": { + "@iarna/cli": "^2.1.0", "npm-package-arg": "^6.1.0", "semver": "^5.4.1" } }, "lockfile": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", - "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "bundled": true, "requires": { "signal-exit": "^3.0.2" } }, "lodash._baseindexof": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", - "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=" + "bundled": true }, "lodash._baseuniq": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", - "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", + "bundled": true, "requires": { "lodash._createset": "~4.0.0", "lodash._root": "~3.0.0" @@ -15056,87 +14935,72 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" + "bundled": true }, "lodash._cacheindexof": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", - "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=" + "bundled": true }, "lodash._createcache": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", - "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", + "bundled": true, "requires": { "lodash._getnative": "^3.0.0" } }, "lodash._createset": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", - "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" + "bundled": true }, "lodash._getnative": { "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + "bundled": true }, "lodash._root": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + "bundled": true }, "lodash.clonedeep": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + "bundled": true }, "lodash.restparam": { "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + "bundled": true }, "lodash.union": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + "bundled": true }, "lodash.uniq": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + "bundled": true }, "lodash.without": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", - "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=" + "bundled": true }, "lowercase-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + "bundled": true }, "lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "bundled": true, "requires": { "yallist": "^3.0.2" } }, "make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "bundled": true, "requires": { "pify": "^3.0.0" } }, "make-fetch-happen": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", - "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", + "bundled": true, "requires": { "agentkeepalive": "^3.4.1", "cacache": "^12.0.0", @@ -15152,48 +15016,41 @@ } }, "meant": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.2.tgz", - "integrity": "sha512-KN+1uowN/NK+sT/Lzx7WSGIj2u+3xe5n2LbwObfjOhPZiA+cCfCm6idVl0RkEfjThkw5XJ96CyRcanq6GmKtUg==" + "version": "1.0.3", + "bundled": true }, "mime-db": { "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + "bundled": true }, "mime-types": { "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "bundled": true, "requires": { "mime-db": "~1.35.0" } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "bundled": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "bundled": true }, "minizlib": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "bundled": true, "requires": { "minipass": "^2.9.0" }, "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -15203,8 +15060,7 @@ }, "mississippi": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "bundled": true, "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -15219,24 +15075,15 @@ } }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "bundled": true, "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - } + "minimist": "^1.2.6" } }, "move-concurrently": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "bundled": true, "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -15248,25 +15095,21 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true } } }, "ms": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "bundled": true }, "mute-stream": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + "bundled": true }, "node-fetch-npm": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", - "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "bundled": true, "requires": { "encoding": "^0.1.11", "json-parse-better-errors": "^1.0.0", @@ -15274,9 +15117,8 @@ } }, "node-gyp": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", - "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", + "version": "5.1.1", + "bundled": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -15293,8 +15135,7 @@ }, "nopt": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "bundled": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -15302,8 +15143,7 @@ }, "normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "bundled": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -15313,8 +15153,7 @@ "dependencies": { "resolve": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "bundled": true, "requires": { "path-parse": "^1.0.6" } @@ -15323,8 +15162,7 @@ }, "npm-audit-report": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.3.tgz", - "integrity": "sha512-8nH/JjsFfAWMvn474HB9mpmMjrnKb1Hx/oTAdjv4PT9iZBvBxiZ+wtDUapHCJwLqYGQVPaAfs+vL5+5k9QndXw==", + "bundled": true, "requires": { "cli-table3": "^0.5.0", "console-control-strings": "^1.1.0" @@ -15332,29 +15170,25 @@ }, "npm-bundled": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "bundled": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } }, "npm-cache-filename": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", - "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" + "bundled": true }, "npm-install-checks": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz", - "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==", + "bundled": true, "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" } }, "npm-lifecycle": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", - "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "bundled": true, "requires": { "byline": "^5.0.0", "graceful-fs": "^4.1.15", @@ -15368,18 +15202,15 @@ }, "npm-logical-tree": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz", - "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==" + "bundled": true }, "npm-normalize-package-bin": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + "bundled": true }, "npm-package-arg": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "bundled": true, "requires": { "hosted-git-info": "^2.7.1", "osenv": "^0.1.5", @@ -15389,8 +15220,7 @@ }, "npm-packlist": { "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "bundled": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -15399,8 +15229,7 @@ }, "npm-pick-manifest": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", - "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1", "npm-package-arg": "^6.0.0", @@ -15409,8 +15238,7 @@ }, "npm-profile": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", - "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", + "bundled": true, "requires": { "aproba": "^1.1.2 || 2", "figgy-pudding": "^3.4.1", @@ -15419,8 +15247,7 @@ }, "npm-registry-fetch": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz", - "integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==", + "bundled": true, "requires": { "JSONStream": "^1.3.4", "bluebird": "^3.5.1", @@ -15433,28 +15260,24 @@ "dependencies": { "safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "bundled": true } } }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "bundled": true, "requires": { "path-key": "^2.0.0" } }, "npm-user-validate": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.1.tgz", - "integrity": "sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw==" + "bundled": true }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -15464,28 +15287,23 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "bundled": true }, "oauth-sign": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "bundled": true }, "object-keys": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + "bundled": true }, "object.getownpropertydescriptors": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "bundled": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -15493,31 +15311,26 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + "bundled": true }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "bundled": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "bundled": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -15525,13 +15338,11 @@ }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "bundled": true }, "package-json": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "bundled": true, "requires": { "got": "^6.7.1", "registry-auth-token": "^3.0.1", @@ -15541,8 +15352,7 @@ }, "pacote": { "version": "9.5.12", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", - "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", + "bundled": true, "requires": { "bluebird": "^3.5.3", "cacache": "^12.0.2", @@ -15578,8 +15388,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -15589,8 +15398,7 @@ }, "parallel-transform": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "bundled": true, "requires": { "cyclist": "~0.2.2", "inherits": "^2.0.3", @@ -15599,8 +15407,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15609,72 +15416,72 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "bundled": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "bundled": true }, "path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + "bundled": true }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "bundled": true }, "path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "bundled": true }, "performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "bundled": true }, "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "bundled": true }, "prepend-http": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "bundled": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "bundled": true }, "promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + "bundled": true }, "promise-retry": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", - "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "bundled": true, "requires": { "err-code": "^1.0.0", "retry": "^0.10.0" @@ -15682,51 +15489,43 @@ "dependencies": { "retry": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + "bundled": true } } }, "promzard": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", - "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "bundled": true, "requires": { "read": "1" } }, "proto-list": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + "bundled": true }, "protoduck": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", - "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "bundled": true, "requires": { "genfun": "^5.0.0" } }, "prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "bundled": true }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "bundled": true }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + "version": "1.9.0", + "bundled": true }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "bundled": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -15734,8 +15533,7 @@ }, "pumpify": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "bundled": true, "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -15744,8 +15542,7 @@ "dependencies": { "pump": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "bundled": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -15753,40 +15550,31 @@ } } }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, "qrcode-terminal": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==" + "bundled": true }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.5.3", + "bundled": true }, "query-string": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz", - "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==", + "version": "6.14.1", + "bundled": true, "requires": { "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, "qw": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz", - "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=" + "version": "1.0.2", + "bundled": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "bundled": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -15796,24 +15584,21 @@ }, "read": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "bundled": true, "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", - "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", + "bundled": true, "requires": { "graceful-fs": "^4.1.2" } }, "read-installed": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", + "bundled": true, "requires": { "debuglog": "^1.0.1", "graceful-fs": "^4.1.2", @@ -15825,21 +15610,18 @@ } }, "read-package-json": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", - "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", + "version": "2.1.2", + "bundled": true, "requires": { "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "normalize-package-data": "^2.0.0", "npm-normalize-package-bin": "^1.0.0" } }, "read-package-tree": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "bundled": true, "requires": { "read-package-json": "^2.0.0", "readdir-scoped-modules": "^1.0.0", @@ -15848,8 +15630,7 @@ }, "readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "bundled": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -15858,8 +15639,7 @@ }, "readdir-scoped-modules": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "bundled": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -15869,8 +15649,7 @@ }, "registry-auth-token": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "bundled": true, "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -15878,16 +15657,14 @@ }, "registry-url": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "bundled": true, "requires": { "rc": "^1.0.1" } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "bundled": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -15896,7 +15673,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -15906,122 +15683,103 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "bundled": true }, "require-main-filename": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "bundled": true }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "bundled": true }, "retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + "bundled": true }, "rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "bundled": true, "requires": { "glob": "^7.1.3" } }, "run-queue": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "bundled": true, "requires": { "aproba": "^1.1.1" }, "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true } } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "bundled": true }, "semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "bundled": true }, "semver-diff": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "bundled": true, "requires": { "semver": "^5.0.3" } }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "bundled": true }, "sha": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz", - "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==", + "bundled": true, "requires": { "graceful-fs": "^4.1.2" } }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "bundled": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "bundled": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "bundled": true }, "slide": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + "bundled": true }, "smart-buffer": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" + "bundled": true }, "socks": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", - "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "bundled": true, "requires": { "ip": "1.1.5", "smart-buffer": "^4.1.0" @@ -16029,8 +15787,7 @@ }, "socks-proxy-agent": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", - "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "bundled": true, "requires": { "agent-base": "~4.2.1", "socks": "~2.3.2" @@ -16038,8 +15795,7 @@ "dependencies": { "agent-base": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "bundled": true, "requires": { "es6-promisify": "^5.0.0" } @@ -16048,13 +15804,11 @@ }, "sorted-object": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", - "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=" + "bundled": true }, "sorted-union-stream": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", - "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", + "bundled": true, "requires": { "from2": "^1.3.0", "stream-iterate": "^1.1.0" @@ -16062,8 +15816,7 @@ "dependencies": { "from2": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", - "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", + "bundled": true, "requires": { "inherits": "~2.0.1", "readable-stream": "~1.1.10" @@ -16071,13 +15824,11 @@ }, "isarray": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "bundled": true }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -16087,15 +15838,13 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "bundled": true } } }, "spdx-correct": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "bundled": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -16103,13 +15852,11 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + "bundled": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "bundled": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -16117,18 +15864,15 @@ }, "spdx-license-ids": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" + "bundled": true }, "split-on-first": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" + "bundled": true }, "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "version": "1.17.0", + "bundled": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -16143,16 +15887,14 @@ }, "ssri": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1" } }, "stream-each": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", + "bundled": true, "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -16160,8 +15902,7 @@ }, "stream-iterate": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", - "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", + "bundled": true, "requires": { "readable-stream": "^2.1.5", "stream-shift": "^1.0.0" @@ -16169,8 +15910,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16179,32 +15919,40 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "stream-shift": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + "bundled": true }, "strict-uri-encode": { "version": "2.0.0", - "resolved": false, - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + "bundled": true }, "string-width": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "bundled": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -16212,18 +15960,15 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "bundled": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "bundled": true, "requires": { "ansi-regex": "^3.0.0" } @@ -16245,39 +15990,33 @@ }, "stringify-package": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", - "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==" + "bundled": true }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + "bundled": true }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "bundled": true }, "supports-color": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "bundled": true, "requires": { "has-flag": "^3.0.0" } }, "tar": { "version": "4.4.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "bundled": true, "requires": { "chownr": "^1.1.4", "fs-minipass": "^1.2.7", @@ -16290,8 +16029,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -16299,38 +16037,32 @@ }, "safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "bundled": true }, "yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "bundled": true } } }, "term-size": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "bundled": true, "requires": { "execa": "^0.7.0" } }, "text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "bundled": true }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "bundled": true }, "through2": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "bundled": true, "requires": { "readable-stream": "^2.1.5", "xtend": "~4.0.1" @@ -16338,8 +16070,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16348,104 +16079,106 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } } } } }, "timed-out": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "bundled": true }, "tiny-relative-date": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz", - "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==" + "bundled": true }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "bundled": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "bundled": true + } } }, "tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "bundled": true, "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "bundled": true }, "typedarray": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "bundled": true }, "uid-number": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" + "bundled": true }, "umask": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", - "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" + "bundled": true }, "unique-filename": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "bundled": true, "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "bundled": true, "requires": { "imurmurhash": "^0.1.4" } }, "unique-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "bundled": true, "requires": { "crypto-random-string": "^1.0.0" } }, "unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "bundled": true }, "unzip-response": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" + "bundled": true }, "update-notifier": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "bundled": true, "requires": { "boxen": "^1.2.1", "chalk": "^2.0.1", @@ -16460,55 +16193,47 @@ } }, "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "version": "4.4.1", + "bundled": true, "requires": { "punycode": "^2.1.0" }, "dependencies": { "punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "bundled": true } } }, "url-parse-lax": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "bundled": true, "requires": { "prepend-http": "^1.0.1" } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "bundled": true }, "util-extend": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" + "bundled": true }, "util-promisify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", - "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "bundled": true, "requires": { "object.getownpropertydescriptors": "^2.0.3" } }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + "version": "3.4.0", + "bundled": true }, "validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "bundled": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -16516,16 +16241,14 @@ }, "validate-npm-package-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "bundled": true, "requires": { "builtins": "^1.0.3" } }, "verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "bundled": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -16534,37 +16257,32 @@ }, "wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "bundled": true, "requires": { "defaults": "^1.0.3" } }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "bundled": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "bundled": true }, "wide-align": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "bundled": true, "requires": { "string-width": "^1.0.2" }, "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -16575,24 +16293,21 @@ }, "widest-line": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "bundled": true, "requires": { "string-width": "^2.1.1" } }, "worker-farm": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "bundled": true, "requires": { "errno": "~0.1.7" } }, "wrap-ansi": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "bundled": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -16601,18 +16316,15 @@ "dependencies": { "ansi-regex": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + "bundled": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "bundled": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -16621,8 +16333,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "bundled": true, "requires": { "ansi-regex": "^4.1.0" } @@ -16631,13 +16342,11 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "bundled": true }, "write-file-atomic": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "bundled": true, "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", @@ -16646,28 +16355,23 @@ }, "xdg-basedir": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" + "bundled": true }, "xtend": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + "bundled": true }, "y18n": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + "bundled": true }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + "bundled": true }, "yargs": { "version": "14.2.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", - "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "bundled": true, "requires": { "cliui": "^5.0.0", "decamelize": "^1.2.0", @@ -16684,26 +16388,22 @@ "dependencies": { "ansi-regex": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "bundled": true }, "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "bundled": true, "requires": { "locate-path": "^3.0.0" } }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "bundled": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -16711,29 +16411,25 @@ }, "p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "bundled": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "bundled": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "bundled": true }, "string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "bundled": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -16742,8 +16438,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "bundled": true, "requires": { "ansi-regex": "^4.1.0" } @@ -16752,8 +16447,7 @@ }, "yargs-parser": { "version": "15.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", - "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "bundled": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -16761,8 +16455,7 @@ "dependencies": { "camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "bundled": true } } } @@ -20314,7 +20007,7 @@ "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==" + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, "debug": { "version": "4.1.1", @@ -20327,7 +20020,7 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==" + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" } } }, @@ -21192,7 +20885,7 @@ "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==" }, "to-fast-properties": { "version": "2.0.0", @@ -21563,7 +21256,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } } @@ -22770,7 +22463,7 @@ "resolve-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { "resolve-from": "^3.0.0" @@ -22779,7 +22472,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", "dev": true }, "semver": { @@ -23320,7 +23013,7 @@ "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" }, "yn": { "version": "3.1.1", diff --git a/package.json b/package.json index 9bfcf0cc8..712354355 100644 --- a/package.json +++ b/package.json @@ -237,7 +237,7 @@ "nodemailer": "^5.1.1", "nodemon": "^1.19.4", "normalize.css": "^8.0.1", - "npm": "^6.14.16", + "npm": "^6.14.18", "p-limit": "^2.2.0", "passport": "^0.4.0", "passport-google-oauth20": "^2.0.0", diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 70fe7f2c0..aa09fb005 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -5,7 +5,7 @@ import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../fields/Types'; import { AudioField } from '../../fields/URLField'; import { returnFalse } from '../../Utils'; -import { DocumentType } from '../documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionFreeFormView } from '../views/collections/collectionFreeForm'; import { CollectionView } from '../views/collections/CollectionView'; @@ -32,11 +32,15 @@ export class DocumentManager { private constructor() {} private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = []; - public AddViewRenderedCb = (doc: Doc, func: (dv: DocumentView) => any) => { - const dv = this.getDocumentViewById(doc[Id]); - this._viewRenderedCbs.push({ doc, func }); - if (dv) { - this.callAddViewFuncs(dv); + public AddViewRenderedCb = (doc: Opt, func: (dv: DocumentView) => any) => { + if (doc) { + const dv = this.getDocumentViewById(doc[Id]); + this._viewRenderedCbs.push({ doc, func }); + if (dv) { + this.callAddViewFuncs(dv); + } + } else { + func(undefined as any); } }; callAddViewFuncs = (view: DocumentView) => { @@ -190,6 +194,16 @@ export class DocumentManager { return toReturn; } + static GetContextPath(doc: Opt) { + if (!doc) return []; + const srcContext = Cast(doc.context, Doc, null) ?? Cast(Cast(doc.annotationOn, Doc, null)?.context, Doc, null); + var containerDocContext = srcContext ? [srcContext] : []; + while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking && !DocumentManager.Instance.getDocumentView(containerDocContext[0])) { + containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; + } + return containerDocContext; + } + static playAudioAnno(doc: Doc) { const anno = Cast(doc[Doc.LayoutFieldKey(doc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement(); if (anno) { diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index 0f1fc6b69..de1207ce4 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -1,8 +1,7 @@ -import React = require("react"); -import { observable, action, runInAction } from "mobx"; -import "./AntimodeMenu.scss"; -export interface AntimodeMenuProps { -} +import React = require('react'); +import { observable, action, runInAction } from 'mobx'; +import './AntimodeMenu.scss'; +export interface AntimodeMenuProps {} /** * This is an abstract class that serves as the base for a PDF-style or Marquee-style @@ -17,15 +16,19 @@ export abstract class AntimodeMenu extends React.Co @observable protected _top: number = -300; @observable protected _left: number = -300; @observable protected _opacity: number = 0; - @observable protected _transitionProperty: string = "opacity"; - @observable protected _transitionDuration: string = "0.5s"; - @observable protected _transitionDelay: string = ""; + @observable protected _transitionProperty: string = 'opacity'; + @observable protected _transitionDuration: string = '0.5s'; + @observable protected _transitionDelay: string = ''; @observable protected _canFade: boolean = false; @observable public Pinned: boolean = false; - get width() { return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().width : 0; } - get height() { return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().height : 0; } + get width() { + return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().width : 0; + } + get height() { + return this._mainCont.current ? this._mainCont.current.getBoundingClientRect().height : 0; + } @action /** @@ -36,12 +39,12 @@ export abstract class AntimodeMenu extends React.Co */ public jumpTo = (x: number, y: number, forceJump: boolean = false) => { if (!this.Pinned || forceJump) { - this._transitionProperty = this._transitionDuration = this._transitionDelay = ""; + this._transitionProperty = this._transitionDuration = this._transitionDelay = ''; this._opacity = 1; this._left = x; this._top = y; } - } + }; @action /** @@ -51,56 +54,56 @@ export abstract class AntimodeMenu extends React.Co public fadeOut = (forceOut: boolean) => { if (!this.Pinned) { if (this._opacity === 0.2) { - this._transitionProperty = "opacity"; - this._transitionDuration = "0.1s"; + this._transitionProperty = 'opacity'; + this._transitionDuration = '0.1s'; } if (forceOut) { - this._transitionProperty = ""; - this._transitionDuration = ""; + this._transitionProperty = ''; + this._transitionDuration = ''; } - this._transitionDelay = ""; + this._transitionDelay = ''; this._opacity = 0; this._left = this._top = -300; } - } + }; @action protected pointerLeave = (e: React.PointerEvent) => { if (!this.Pinned && this._canFade) { - this._transitionProperty = "opacity"; - this._transitionDuration = "0.5s"; - this._transitionDelay = "1s"; + this._transitionProperty = 'opacity'; + this._transitionDuration = '0.5s'; + this._transitionDelay = '1s'; this._opacity = 0.2; setTimeout(() => this.fadeOut(false), 3000); } - } + }; @action protected pointerEntered = (e: React.PointerEvent) => { - this._transitionProperty = "opacity"; - this._transitionDuration = "0.1s"; - this._transitionDelay = ""; + this._transitionProperty = 'opacity'; + this._transitionDuration = '0.1s'; + this._transitionDelay = ''; this._opacity = 1; - } + }; @action protected togglePin = (e: React.MouseEvent) => { - runInAction(() => this.Pinned = !this.Pinned); - } + runInAction(() => (this.Pinned = !this.Pinned)); + }; protected dragStart = (e: React.PointerEvent) => { - document.removeEventListener("pointermove", this.dragging); - document.addEventListener("pointermove", this.dragging); - document.removeEventListener("pointerup", this.dragEnd); - document.addEventListener("pointerup", this.dragEnd); + document.removeEventListener('pointermove', this.dragging); + document.addEventListener('pointermove', this.dragging); + document.removeEventListener('pointerup', this.dragEnd); + document.addEventListener('pointerup', this.dragEnd); this._offsetX = e.pageX - this._mainCont.current!.getBoundingClientRect().left; this._offsetY = e.pageY - this._mainCont.current!.getBoundingClientRect().top; e.stopPropagation(); e.preventDefault(); - } + }; @action protected dragging = (e: PointerEvent) => { @@ -115,32 +118,41 @@ export abstract class AntimodeMenu extends React.Co e.stopPropagation(); e.preventDefault(); - } + }; protected dragEnd = (e: PointerEvent) => { - document.removeEventListener("pointermove", this.dragging); - document.removeEventListener("pointerup", this.dragEnd); + document.removeEventListener('pointermove', this.dragging); + document.removeEventListener('pointerup', this.dragEnd); e.stopPropagation(); e.preventDefault(); - } + }; protected handleContextMenu = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); - } + }; protected getDragger = () => { - return
; - } + return
; + }; - protected getElement(buttons: JSX.Element[]) { + protected getElement(buttons: JSX.Element) { return ( -
- {/* {this.getDragger} */} {buttons}
); @@ -148,34 +160,51 @@ export abstract class AntimodeMenu extends React.Co protected getElementVert(buttons: JSX.Element[]) { return ( -
{buttons}
); } - - protected getElementWithRows(rows: JSX.Element[], numRows: number, hasDragger: boolean = true) { return ( -
- {hasDragger ?
: (null)} + {hasDragger ?
: null} {rows}
); } -} \ No newline at end of file +} diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index f06dc93e3..f61d147cf 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -5,11 +5,11 @@ import { action, computed, observable, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; -import { Cast, NumCast } from '../../fields/Types'; +import { Cast, DocCast, NumCast } from '../../fields/Types'; import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; -import { Docs } from '../documents/Documents'; +import { Docs, DocUtils } from '../documents/Documents'; import { DragManager } from '../util/DragManager'; import { SelectionManager } from '../util/SelectionManager'; import { SharingManager } from '../util/SharingManager'; @@ -21,12 +21,13 @@ import { Colors } from './global/globalEnums'; import { LinkPopup } from './linking/LinkPopup'; import { MetadataEntryMenu } from './MetadataEntryMenu'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewInternal, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { TemplateMenu } from './TemplateMenu'; import React = require('react'); import { DocumentType } from '../documents/DocumentTypes'; +import { FontIconBox } from './nodes/button/FontIconBox'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -270,6 +271,13 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
+ open linked trail
}> +
+ +
+
@@ -483,6 +491,22 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV this._showLinkPopup = !this._showLinkPopup; e.stopPropagation(); }; + @action + toggleTrail = (e: React.PointerEvent) => { + const rootView = this.props.views()[0]; + const rootDoc = rootView?.rootDoc; + if (rootDoc) { + const anchor = rootView.ComponentView?.getAnchor?.(true) ?? rootDoc; + const trail = DocCast(anchor.presTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true); + if (trail !== anchor.presTrail) { + DocUtils.MakeLink({ doc: anchor }, { doc: trail }, 'link trail'); + anchor.presTrail = trail; + } + Doc.ActivePresentation = trail; + this.props.views().lastElement()?.props.addDocTab(trail, OpenWhere.replaceRight); + } + e.stopPropagation(); + }; render() { if (!this.view0) return null; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 4494166f2..839db5795 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -249,6 +249,7 @@ export class MainView extends React.Component { fa.faTrash, fa.faTrashAlt, fa.faShare, + fa.faTaxi, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 488f51d77..9581563ce 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -26,33 +26,39 @@ export class MarqueeOptionsMenu extends AntimodeMenu { render() { const presPinWithViewIcon = ; - const buttons = [ - Create a Collection
} placement="bottom"> - - , - Create a Grouping
} placement="bottom"> - - , - Summarize Documents} placement="bottom"> - - , - Delete Documents} placement="bottom"> - - , - Pin selected region to trail} placement="bottom"> - - , - ]; + const buttons = ( + <> + Create a Collection} placement="bottom"> + + + , + Create a Grouping} placement="bottom"> + + + , + Summarize Documents} placement="bottom"> + + + , + Delete Documents} placement="bottom"> + + + , + Pin selected region to trail} placement="bottom"> + + + + ); return this.getElement(buttons); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 054d01d8e..b94db2c6b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -696,6 +696,7 @@ export class DocumentViewInternal extends DocComponent { if (this.rootDoc.type === DocumentType.INK && Doc.ActiveTool === InkTool.Eraser) return; // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document) @@ -736,6 +737,9 @@ export class DocumentViewInternal extends DocComponent() { ); return ( -
(this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen))}> +
e.stopPropagation()} onClick={action(() => (this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen))}> {checkResult} {label} {this.rootDoc.dropDownOpen ? dropdown : null} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 63347015b..39005a18b 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -287,12 +287,12 @@ export class DashFieldViewMenu extends AntimodeMenu { document.addEventListener('pointerdown', hideMenu, true); }; render() { - return this.getElement([ + return this.getElement( {`Show Pivot Viewer for '${this._fieldKey}'`}
}> - , - ]); + + ); } } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index deb1d68a7..8407eee96 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -693,6 +693,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (anchor.followLinkToggle = !anchor.followLinkToggle); + @undoBatch + showTargetTrail = (anchor: Doc) => { + const trail = DocCast(anchor.presTrail); + if (trail) { + Doc.ActivePresentation = trail; + this.props.addDocTab(trail, OpenWhere.replaceRight); + } + }; + isTargetToggler = (anchor: Doc) => BoolCast(anchor.followLinkToggle); specificContextMenu = (e: React.MouseEvent): void => { @@ -717,6 +726,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.pinToPres(anchor as Doc); AnchorMenu.Instance.MakeTargetToggle = () => this.makeTargetToggle(anchor as Doc); + AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(anchor as Doc); AnchorMenu.Instance.IsTargetToggler = () => this.isTargetToggler(anchor as Doc); AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); }) @@ -1471,7 +1481,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { } isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentationTargetDoc === layoutDoc; clearSelectedArray = () => this.selectedArray.clear(); - addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc); - removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc); + addToSelectedArray = action((doc: Doc) => this.selectedArray.add(doc)); + removeFromSelectedArray = action((doc: Doc) => this.selectedArray.delete(doc)); _unmounting = false; @action @@ -211,12 +211,6 @@ export class PresBox extends ViewBoxBaseComponent() { nextSlide = (slideNum?: number) => { const nextSlideInd = slideNum ?? this.itemIndex + 1; let curSlideInd = nextSlideInd; - const resetSelection = action(() => { - this.clearSelectedArray(); - for (let i = nextSlideInd; i <= curSlideInd; i++) { - this.addToSelectedArray(this.childDocs[i]); - } - }); CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); this.clearSelectedArray(); const doGroupWithUp = @@ -224,6 +218,7 @@ export class PresBox extends ViewBoxBaseComponent() { () => { if (nextSelected < this.childDocs.length) { if (force || this.childDocs[nextSelected].groupWithUp) { + this.addToSelectedArray(this.childDocs[nextSelected]); const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].groupWithUp) > 1; if (serial) { this.gotoDocument(nextSelected, this.activeItem, true, async () => { @@ -232,7 +227,7 @@ export class PresBox extends ViewBoxBaseComponent() { doGroupWithUp(nextSelected + 1)(); }); } else { - this.gotoDocument(nextSelected, this.activeItem, undefined, resetSelection); + this.gotoDocument(nextSelected, this.activeItem, true); curSlideInd = this.itemIndex; doGroupWithUp(nextSelected + 1)(); } @@ -513,24 +508,11 @@ export class PresBox extends ViewBoxBaseComponent() { console.log('Finish Slide Nav: ' + targetDoc.title); targetDoc[AnimationSym] = undefined; }; - const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null); - const presCollection = Cast(this.layoutDoc.presCollection, Doc, null); - const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined; - const includesDoc = () => (DocumentManager.Instance.getDocumentView(targetDoc) ? true : false); // DocListCast(presCollection?.data).includes(targetDoc); - const tabMap = CollectionDockingView.Instance?.tabMap; - const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc === srcContext || tab.DashDoc === targetDoc); - // Handles the setting of presCollection - if (includesDoc()) { - //Case 1: Pres collection should not change as it is already the same - } else if (tab !== undefined) { - // Case 2: Pres collection should update - this.layoutDoc.presCollection = srcContext; - } const selViewCache = Array.from(this.selectedArray); const dragViewCache = Array.from(this._dragArray); const eleViewCache = Array.from(this._eleArray); const resetSelection = action(() => { - if (!includesDoc()) { + if (!this.props.isSelected()) { const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc); if (presDocView) SelectionManager.SelectView(presDocView, false); this.clearSelectedArray(); @@ -542,17 +524,28 @@ export class PresBox extends ViewBoxBaseComponent() { }); const createDocView = (doc: Doc, finished?: () => void) => { DocumentManager.Instance.AddViewRenderedCb(doc, () => finished?.()); - (collectionDocView ?? this).props.addDocTab(doc, OpenWhere.lightbox); - this.layoutDoc.presCollection = targetDoc; + LightboxView.AddDocTab(doc, OpenWhere.lightbox); }; - PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, srcContext, includesDoc() || tab ? finished : resetSelection); + PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, resetSelection); }; - static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, srcContext: Doc, finished?: () => void) { + static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, finished?: () => void) { if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); return; } + const options: DocFocusOptions = { + willPan: activeItem.presMovement !== PresMovement.None, + willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, + zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), + zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500), + effect: activeItem, + noSelect: true, + originatingDoc: activeItem, + easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, + zoomTextSelections: BoolCast(activeItem.presZoomText), + playAudio: BoolCast(activeItem.presPlayAudio), + }; const restoreLayout = () => { // After navigating to the document, if it is added as a presPinView then it will // adjust the pan and scale to that of the pinView when it was added. @@ -562,47 +555,29 @@ export class PresBox extends ViewBoxBaseComponent() { PresBox.restoreTargetDocView(DocumentManager.Instance.getFirstDocumentView(targetDoc), { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500)); } }; - // If openDocument is selected then it should open the document for the user - if (activeItem.openDocument) { - LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc); - setTimeout(restoreLayout); - } else { - if (targetDoc) { - const options: DocFocusOptions = { - willPan: activeItem.presMovement !== PresMovement.None, - willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, - zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), - zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500), - effect: activeItem, - noSelect: true, - originatingDoc: activeItem, - easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, - zoomTextSelections: BoolCast(activeItem.presZoomText), - playAudio: BoolCast(activeItem.presPlayAudio), - }; - if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined; - var containerDocContext = srcContext ? [srcContext] : []; - while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) { - containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; - } - const testTarget = containerDocContext.length ? containerDocContext[0] : targetDoc; - if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(testTarget)) { - DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => { - if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(LightboxView.LightboxDoc)) { - DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished); - restoreLayout(); - } else { - LightboxView.SetLightboxDoc(undefined); - DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished); - restoreLayout(); - } - }); - return; - } - DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished); - restoreLayout(); - } else restoreLayout(); + const finishAndRestoreLayout = () => { + finished?.(); + restoreLayout(); + }; + const containerDocContext = DocumentManager.GetContextPath(targetDoc); + + let context = containerDocContext.length ? containerDocContext[0] : targetDoc; + if (activeItem.presOpenInLightbox) { + if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(DocCast(targetDoc.annotationOn) ?? targetDoc))) { + context = DocCast(targetDoc.annotationOn) ?? targetDoc; + LightboxView.SetLightboxDoc(context); // openInTab(targetDoc); + } } + if (targetDoc) { + if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined; + + DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => { + if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(context.annotationOn) ?? context)) { + LightboxView.SetLightboxDoc(undefined); + } + DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finishAndRestoreLayout); + }); + } else finishAndRestoreLayout(); } /** @@ -615,38 +590,34 @@ export class PresBox extends ViewBoxBaseComponent() { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); - if (tagDoc === this.layoutDoc.presCollection) { - tagDoc.opacity = 1; - } else { - if (curDoc.presHide) { - if (index !== this.itemIndex) { - tagDoc.opacity = 1; - } + if (curDoc.presHide) { + if (index !== this.itemIndex) { + tagDoc.opacity = 1; } - const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex); - if (curDoc.presHideBefore && index === hidingIndBef) { - if (index > this.itemIndex) { - tagDoc.opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideAfter) { - tagDoc.opacity = 1; - } + } + const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex); + if (curDoc.presHideBefore && index === hidingIndBef) { + if (index > this.itemIndex) { + tagDoc.opacity = 0; + } else if (index === this.itemIndex || !curDoc.presHideAfter) { + tagDoc.opacity = 1; } - const hidingIndAft = itemIndexes - .slice() - .reverse() - .find(item => item < this.itemIndex); - if (curDoc.presHideAfter && index === hidingIndAft) { - if (index < this.itemIndex) { - tagDoc.opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideBefore) { - tagDoc.opacity = 1; - } + } + const hidingIndAft = itemIndexes + .slice() + .reverse() + .find(item => item < this.itemIndex); + if (curDoc.presHideAfter && index === hidingIndAft) { + if (index < this.itemIndex) { + tagDoc.opacity = 0; + } else if (index === this.itemIndex || !curDoc.presHideBefore) { + tagDoc.opacity = 1; } - const hidingInd = itemIndexes.find(item => item === this.itemIndex); - if (curDoc.presHide && index === hidingInd) { - if (index === this.itemIndex) { - tagDoc.opacity = 0; - } + } + const hidingInd = itemIndexes.find(item => item === this.itemIndex); + if (curDoc.presHide && index === hidingInd) { + if (index === this.itemIndex) { + tagDoc.opacity = 0; } } }); @@ -894,8 +865,9 @@ export class PresBox extends ViewBoxBaseComponent() { selectElement = async (doc: Doc) => { CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem); - if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0); - else this.updateCurrentPresentation(DocCast(doc.context)); + // if (doc.presPinView) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0); + // else + this.updateCurrentPresentation(DocCast(doc.context)); }; //Command click @@ -1043,7 +1015,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get order() { const order: JSX.Element[] = []; const docs: Doc[] = []; - const presCollection = Cast(this.rootDoc.presCollection, Doc, null); + const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement(); const dv = DocumentManager.Instance.getDocumentView(presCollection); this.childDocs .filter(doc => Cast(doc.presentationTargetDoc, Doc, null)) @@ -1209,8 +1181,8 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action updateOpenDoc = (activeItem: Doc) => { - activeItem.openDocument = !activeItem.openDocument; - this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument)); + activeItem.presOpenInLightbox = !activeItem.presOpenInLightbox; + this.selectedArray.forEach(doc => (doc.presOpenInLightbox = activeItem.presOpenInLightbox)); }; @undoBatch @action @@ -1255,8 +1227,6 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get transitionDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection; - const isPinWithView: boolean = BoolCast(activeItem.presPinView); const presEffect = (effect: PresEffect) => (
this.updateEffect(effect)}> {effect} @@ -1309,11 +1279,11 @@ export class PresBox extends ViewBoxBaseComponent() { {this.movementName(activeItem)}
- {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.None)} + {presMovement(PresMovement.None)} {presMovement(PresMovement.Center)} {presMovement(PresMovement.Zoom)} {presMovement(PresMovement.Pan)} - {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.Jump)} + {presMovement(PresMovement.Jump)}
@@ -1355,29 +1325,25 @@ export class PresBox extends ViewBoxBaseComponent() {
Visibility {'&'} Duration
- {isPresCollection ? null : ( - {'Hide before presented'}
}> -
this.updateHideBefore(activeItem)}> - Hide before -
- - )} - {isPresCollection ? null : ( - {'Hide while presented'}
}> -
this.updateHide(activeItem)}> - Hide -
- - )} - {isPresCollection ? null : ( - {'Hide after presented'}
}> -
this.updateHideAfter(activeItem)}> - Hide after -
- - )} + {'Hide before presented'}
}> +
this.updateHideBefore(activeItem)}> + Hide before +
+ + {'Hide while presented'}}> +
this.updateHide(activeItem)}> + Hide +
+
+ + {'Hide after presented'}}> +
this.updateHideAfter(activeItem)}> + Hide after +
+
+ {'Open in lightbox view'}}> -
this.updateOpenDoc(activeItem)}> +
this.updateOpenDoc(activeItem)}> Lightbox
@@ -1412,48 +1378,46 @@ export class PresBox extends ViewBoxBaseComponent() { )}
- {isPresCollection ? null : ( -
- Effects -
-
Play Audio Annotation
- (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} checked={BoolCast(activeItem.presPlayAudio)} /> -
-
-
Zoom Text Selections
- (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} /> -
-
{ - e.stopPropagation(); - this._openEffectDropdown = !this._openEffectDropdown; - })} - style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> - {effect?.toString()} - -
e.stopPropagation()}> - {presEffect(PresEffect.None)} - {presEffect(PresEffect.Fade)} - {presEffect(PresEffect.Flip)} - {presEffect(PresEffect.Rotate)} - {presEffect(PresEffect.Bounce)} - {presEffect(PresEffect.Roll)} -
-
-
-
Effect direction
-
{StrCast(this.activeItem.presEffectDirection)}
-
-
- {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} - {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} - {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} - {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} - {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} +
+ Effects +
+
Play Audio Annotation
+ (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} checked={BoolCast(activeItem.presPlayAudio)} /> +
+
+
Zoom Text Selections
+ (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} /> +
+
{ + e.stopPropagation(); + this._openEffectDropdown = !this._openEffectDropdown; + })} + style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + {effect?.toString()} + +
e.stopPropagation()}> + {presEffect(PresEffect.None)} + {presEffect(PresEffect.Fade)} + {presEffect(PresEffect.Flip)} + {presEffect(PresEffect.Rotate)} + {presEffect(PresEffect.Bounce)} + {presEffect(PresEffect.Roll)}
- )} +
+
Effect direction
+
{StrCast(this.activeItem.presEffectDirection)}
+
+
+ {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} +
+
this.applyTo(this.childDocs)}> Apply to all @@ -1658,7 +1622,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get newDocumentToolbarDropdown() { return (
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} @@ -1794,7 +1758,9 @@ export class PresBox extends ViewBoxBaseComponent() { if (freeform && layout) doc = this.createTemplate(layout, title); if (!freeform && !layout) doc = Docs.Create.TextDocument('', { _nativeWidth: 400, _width: 225, title: title }); if (doc) { - const presCollection = Cast(this.layoutDoc.presCollection, Doc, null); + const tabMap = CollectionDockingView.Instance?.tabMap; + const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc.type === DocumentType.COL)?.DashDoc; + const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentationTargetDoc ?? tab; const data = Cast(presCollection?.data, listSpec(Doc)); const presData = Cast(this.rootDoc.data, listSpec(Doc)); if (data && presData) { @@ -2300,12 +2266,11 @@ export class PresBox extends ViewBoxBaseComponent() { ); } static NavigateToDoc(bestTarget: Doc, activeItem: Doc) { - const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null); const openInTab = (doc: Doc, finished?: () => void) => { CollectionDockingView.AddSplit(doc, OpenWhereMod.right); finished?.(); }; - PresBox.NavigateToTarget(bestTarget, activeItem, openInTab, srcContext); + PresBox.NavigateToTarget(bestTarget, activeItem, openInTab); } } diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f1c97d26a..788900b46 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -365,8 +365,8 @@ export class PresElementBox extends ViewBoxBaseComponent() { } // a previously recorded video will have timecode defined - static videoIsRecorded = (activeItem: Doc) => { - const casted = Cast(activeItem.recording, Doc, null); + static videoIsRecorded = (activeItem: Opt) => { + const casted = Cast(activeItem?.recording, Doc, null); return casted && 'currentTimecode' in casted; }; @@ -381,10 +381,10 @@ export class PresElementBox extends ViewBoxBaseComponent() { static removeEveryExistingRecordingInOverlay = () => { // Remove every recording that already exists in overlay view DocListCast(Doc.MyOverlayDocs.data).forEach(doc => { - // if it's a recording video, don't remove from overlay (user can lose data) - if (!PresElementBox.videoIsRecorded(DocCast(doc.slides))) return; - if (doc.slides !== null) { + // if it's a recording video, don't remove from overlay (user can lose data) + if (!PresElementBox.videoIsRecorded(DocCast(doc.slides))) return; + Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc); } }); diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 2fb795b06..9af686d83 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -11,13 +11,13 @@ import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu'; import { LinkPopup } from '../linking/LinkPopup'; import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu'; import './AnchorMenu.scss'; -import { truncate } from 'lodash'; @observer export class AnchorMenu extends AntimodeMenu { static Instance: AnchorMenu; private _disposer: IReactionDisposer | undefined; + private _disposer2: IReactionDisposer | undefined; private _commentCont = React.createRef(); private _palette = [ 'rgba(208, 2, 27, 0.8)', @@ -37,9 +37,6 @@ export class AnchorMenu extends AntimodeMenu { 'rgba(0, 0, 0, 0.8)', ]; - @observable private _keyValue: string = ''; - @observable private _valueValue: string = ''; - @observable private _added: boolean = false; @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)'; @observable private _showLinkPopup: boolean = false; @@ -56,9 +53,9 @@ export class AnchorMenu extends AntimodeMenu { public Highlight: (color: string, isTargetToggler: boolean) => Opt = (color: string, isTargetToggler: boolean) => undefined; public GetAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = (savedAnnotations: Opt>, addAsAnnotation: boolean) => undefined; public Delete: () => void = unimplementedFunction; - public AddTag: (key: string, value: string) => boolean = returnFalse; public PinToPres: () => void = unimplementedFunction; public MakeTargetToggle: () => void = unimplementedFunction; + public ShowTargetTrail: () => void = unimplementedFunction; public IsTargetToggler: () => boolean = returnFalse; public get Active() { return this._left > 0; @@ -71,7 +68,17 @@ export class AnchorMenu extends AntimodeMenu { AnchorMenu.Instance._canFade = false; } + componentWillUnmount() { + this._disposer?.(); + this._disposer2?.(); + } + componentDidMount() { + this._disposer2 = reaction( + () => this._opacity, + opacity => !opacity && (this._showLinkPopup = false), + { fireImmediately: true } + ); this._disposer = reaction( () => SelectionManager.Views(), selected => { @@ -175,82 +182,62 @@ export class AnchorMenu extends AntimodeMenu { this.highlightColor = Utils.colorString(col); }; - @action keyChanged = (e: React.ChangeEvent) => { - this._keyValue = e.currentTarget.value; - }; - @action valueChanged = (e: React.ChangeEvent) => { - this._valueValue = e.currentTarget.value; - }; - @action addTag = (e: React.PointerEvent) => { - if (this._keyValue.length > 0 && this._valueValue.length > 0) { - this._added = this.AddTag(this._keyValue, this._valueValue); - setTimeout( - action(() => (this._added = false)), - 1000 - ); - } - }; - render() { const buttons = - this.Status === 'marquee' - ? [ - this.highlighter, - - {'Drag to Place Annotation'}
}> - - , - AnchorMenu.Instance.OnAudio === unimplementedFunction ? ( - <> - ) : ( - {'Click to Record Annotation'}
}> - - - ), - {'Find document to link to selected text'}
}> - - , - , - AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? ( - <> - ) : ( - {'Click/Drag to create cropped image'}
}> - - - ), - ] - : [ - {'Remove Link Anchor'}
}> - -
, - {'Pin to Presentation'}}> - - , - {'make target visibility toggle on click'}}> - - , - //
- // - // - //
, - // , - ]; + this.Status === 'marquee' ? ( + <> + {this.highlighter} + Drag to Place Annotation}> + + + {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( + Click to Record Annotation}> + + + )} + Find document to link to selected text}> + + + , + {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : ( + Click/Drag to create cropped image}> + + + )} + + ) : ( + <> + Remove Link Anchor}> + + + Pin to Presentation}> + + + Show Linked Trail}> + + + make target visibility toggle on click}> + + + + ); return this.getElement(buttons); } diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index d8e44ae9d..0a8c69881 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -65,7 +65,6 @@ class RegionAnnotation extends React.Component { AnchorMenu.Instance.Status = 'annotation'; AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); AnchorMenu.Instance.Pinned = false; - AnchorMenu.Instance.AddTag = this.addTag.bind(this); AnchorMenu.Instance.PinToPres = this.pinToPres; AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; @@ -77,12 +76,6 @@ class RegionAnnotation extends React.Component { } }; - addTag = (key: string, value: string): boolean => { - const valNum = parseInt(value); - this.annoTextRegion[key] = isNaN(valNum) ? value : valNum; - return true; - }; - render() { const brushed = this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion); return ( diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index aac488559..7e2a5a237 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -10,6 +10,7 @@ import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; +import { undoBatch } from '../../util/UndoManager'; import { CollectionDockingView } from '../collections/CollectionDockingView'; import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; @@ -113,14 +114,12 @@ export class SearchBox extends ViewBoxBaseComponent() { this.selectElement(doc, () => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, false)); }); - // TODO: nda -- Change this method to change what happens when you click on the item. + @undoBatch makeLink = action((linkTo: Doc) => { - if (this.props.linkCreateAnchor) { - const linkFrom = this.props.linkCreateAnchor(); - if (linkFrom) { - const link = DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); - link && this.props.linkCreated?.(link); - } + const linkFrom = this.props.linkCreateAnchor?.(); + if (linkFrom) { + const link = DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); + link && this.props.linkCreated?.(link); } }); -- cgit v1.2.3-70-g09d2 From af2a2c83868c87812e9ae54c8e3cced81374619a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 27 Feb 2023 15:08:45 -0500 Subject: restructured getAnchor()/scrollFocus to be more consistent. added setterscript for computedFields. restructed getFieldsImpl to avoid making multiple requests for the same document due to timing issues by 'locking' a document cache with a promise before sending the server request. added rotation and fill color as animatable fields. fixed image cropping for --- src/client/DocServer.ts | 143 +++++++------- src/client/documents/Documents.ts | 23 ++- src/client/util/DocumentManager.ts | 4 +- src/client/util/LinkManager.ts | 2 +- src/client/util/SharingManager.tsx | 30 ++- src/client/views/DocumentButtonBar.tsx | 10 +- src/client/views/InkTangentHandles.tsx | 9 +- src/client/views/InkingStroke.tsx | 32 +++- src/client/views/MainView.tsx | 1 - src/client/views/MarqueeAnnotator.tsx | 35 ++-- src/client/views/StyleProvider.tsx | 3 + .../collections/CollectionStackedTimeline.tsx | 10 +- .../views/collections/CollectionTimeView.tsx | 37 +--- src/client/views/collections/TabDocView.tsx | 8 +- .../CollectionFreeFormLayoutEngines.tsx | 2 + .../collectionFreeForm/CollectionFreeFormView.tsx | 49 ++--- src/client/views/nodes/AudioBox.tsx | 12 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 23 ++- src/client/views/nodes/DocumentLinksButton.tsx | 20 +- src/client/views/nodes/DocumentView.tsx | 15 +- src/client/views/nodes/FunctionPlotBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 34 +--- src/client/views/nodes/LabelBox.tsx | 2 - src/client/views/nodes/PDFBox.tsx | 27 +-- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 5 +- src/client/views/nodes/VideoBox.tsx | 23 +-- src/client/views/nodes/WebBox.tsx | 40 ++-- src/client/views/nodes/button/FontIconBox.tsx | 28 ++- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 211 ++++++++++++++------- src/client/views/pdf/AnchorMenu.tsx | 7 +- src/client/views/pdf/PDFViewer.tsx | 9 +- src/fields/Doc.ts | 28 ++- src/fields/ScriptField.ts | 6 +- src/server/DashUploadUtils.ts | 2 +- src/server/websocket.ts | 2 +- 37 files changed, 517 insertions(+), 387 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index cab90138f..8f79ebb03 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -234,7 +234,7 @@ export namespace DocServer { * the server if the document has not been cached. * @param id the id of the requested document */ - const _GetRefFieldImpl = async (id: string, force: boolean = false): Promise> => { + const _GetRefFieldImpl = (id: string, force: boolean = false): Promise> => { // an initial pass through the cache to determine whether the document needs to be fetched, // is already in the process of being fetched or already exists in the // cache @@ -309,8 +309,7 @@ export namespace DocServer { } export async function getYoutubeChannels() { - const apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.Channels }); - return apiKey; + return await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.Channels }); } export function getYoutubeVideos(videoTitle: string, callBack: (videos: any[]) => void) { @@ -329,10 +328,11 @@ export namespace DocServer { */ const _GetRefFieldsImpl = async (ids: string[]): Promise<{ [id: string]: Opt }> => { const requestedIds: string[] = []; - const waitingIds: string[] = []; - const promises: Promise>[] = []; - const map: { [id: string]: Opt } = {}; + const promises: Promise[] = []; + let defaultRes: any = undefined; + const defaultPromise = new Promise(res => (defaultRes = res)); + let defaultPromises: { p: Promise; id: string }[] = []; // 1) an initial pass through the cache to determine // i) which documents need to be fetched // ii) which are already in the process of being fetched @@ -340,6 +340,13 @@ export namespace DocServer { for (const id of ids) { const cached = _cache[id]; if (cached === undefined) { + defaultPromises.push({ + id, + p: (_cache[id] = new Promise(async res => { + await defaultPromise; + res(_cache[id]); + })), + }); // NOT CACHED => we'll have to send a request to the server requestedIds.push(id); } else if (cached instanceof Promise) { @@ -347,10 +354,10 @@ export namespace DocServer { // and requested one of the documents I'm looking for. Shouldn't fetch again, just // wait until this promise is resolved (see 7) promises.push(cached); - waitingIds.push(id); + // waitingIds.push(id); } else { // CACHED => great, let's just add it to the field map - map[id] = cached; + // map[id] = cached; } } @@ -358,74 +365,65 @@ export namespace DocServer { // 2) synchronously, we emit a single callback to the server requesting the serialized (i.e. represented by a string) // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of // the fields have been returned from the server - console.log('Requesting ' + requestedIds.length + ' fields'); + console.log('Requesting ' + requestedIds.length); FieldLoader.active && runInAction(() => (FieldLoader.ServerLoadStatus.requested = requestedIds.length)); - const getSerializedFields: Promise = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds); + const serializedFields = await Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds); // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects. // Here, once deserialized, we also invoke .proto to 'load' the documents' prototypes, which ensures that all // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. - - let retrieved = 0; - const fields: { [id: string]: RefField } = {}; - await getSerializedFields.then(async fieldvals => { - console.log('deserializing ' + fieldvals.length + ' fields'); - const proms: Promise[] = []; - await runInAction(async () => { - for (const field of fieldvals) { - const cached = _cache[field.id]; - if (!cached) { - retrieved++; - if (FieldLoader.active && retrieved % 150 === 0) { - runInAction(() => (FieldLoader.ServerLoadStatus.retrieved = retrieved)); - await new Promise(res => setTimeout(res)); + let processed = 0; + console.log('deserializing ' + serializedFields.length + ' fields'); + for (const field of serializedFields) { + processed++; + if (FieldLoader.active && processed % 150 === 0) { + runInAction(() => (FieldLoader.ServerLoadStatus.retrieved = processed)); + await new Promise(res => setTimeout(res)); // force loading to yield to splash screen rendering to update progress + } + const cached = _cache[field.id]; + if (!cached || (cached instanceof Promise && defaultPromises.some(dp => dp.p === cached))) { + // deserialize + // adds to a list of promises that will be awaited asynchronously + promises.push( + (_cache[field.id] = SerializationHelper.Deserialize(field).then(deserialized => { + //overwrite or delete any promises (that we inserted as flags + // to indicate that the field was in the process of being fetched). Now everything + // should be an actual value within or entirely absent from the cache. + if (deserialized !== undefined) { + _cache[field.id] = deserialized; + } else { + delete _cache[field.id]; } - // deserialize - const prom = SerializationHelper.Deserialize(field).then(async deserialized => { - fields[field.id] = deserialized; - - //overwrite or delete any promises (that we inserted as flags - // to indicate that the field was in the process of being fetched). Now everything - // should be an actual value within or entirely absent from the cache. - if (deserialized !== undefined) { - _cache[field.id] = deserialized; - } else { - delete _cache[field.id]; - } - return deserialized; - }); - // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) - // we set the value at the field's id to a promise that will resolve to the field. - // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). - // The mapping in the .then call ensures that when other callers await these promises, they'll - // get the resolved field - _cache[field.id] = prom; - - // adds to a list of promises that will be awaited asynchronously - proms.push(prom); - } else if (cached instanceof Promise) { - console.log('.'); - proms.push(cached as any); - cached.then((f: any) => (fields[field.id] = f)); - } else if (field) { - console.log('-'); - proms.push(cached as any); - fields[field.id] = DocServer.GetCachedRefField(field.id) || field; - } - } - }); - return Promise.all(proms); - }); + const promInd = defaultPromises.findIndex(dp => dp.id === field.id); + promInd !== -1 && defaultPromises.splice(promInd, 1); + return deserialized; + })) + ); + // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) + // we set the value at the field's id to a promise that will resolve to the field. + // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). + // The mapping in the .then call ensures that when other callers await these promises, they'll + // get the resolved field + } else if (cached instanceof Promise) { + console.log('.'); + //promises.push(cached); + } else if (field) { + // console.log('-'); + } + } + } - // 5) at this point, all fields have a) been returned from the server and b) been deserialized into actual Field objects whose - // prototype documents, if any, have also been fetched and cached. - console.log('Deserialized ' + Object.keys(fields).length + ' fields'); + await Promise.all(promises); + defaultPromises.forEach(df => delete _cache[df.id]); + defaultRes(); - // 6) with this confidence, we can now go through and update the cache at the ids of the fields that - // we explicitly had to fetch. To finish it off, we add whatever value we've come up with for a given - // id to the soon-to-be-returned field mapping. - requestedIds.forEach(id => (map[id] = fields[id])); - } + // 5) at this point, all fields have a) been returned from the server and b) been deserialized into actual Field objects whose + // prototype documents, if any, have also been fetched and cached. + console.log('Deserialized ' + (requestedIds.length - defaultPromises.length) + ' fields'); + // 6) with this confidence, we can now go through and update the cache at the ids of the fields that + // we explicitly had to fetch. To finish it off, we add whatever value we've come up with for a given + // id to the soon-to-be-returned field mapping. + //ids.forEach(id => (map[id] = _cache[id] as any)); // 7) those promises we encountered in the else if of 1), which represent // other callers having already submitted a request to the server for (a) document(s) @@ -434,16 +432,19 @@ export namespace DocServer { // // fortunately, those other callers will also hit their own version of 6) and clean up // the shared cache when these promises resolve, so all we have to do is... - const otherCallersFetching = await Promise.all(promises); + //const otherCallersFetching = await Promise.all(promises); // ...extract the RefFields returned from the resolution of those promises and add them to our // own map. - waitingIds.forEach((id, index) => (map[id] = otherCallersFetching[index])); + // waitingIds.forEach((id, index) => (map[id] = otherCallersFetching[index])); // now, we return our completed mapping from all of the ids that were passed into the method // to their actual RefField | undefined values. This return value either becomes the input // argument to the caller's promise (i.e. GetRefFields(["_id1_", "_id2_", "_id3_"]).then(map => //do something with map...)) // or it is the direct return result if the promise is awaited (i.e. let fields = await GetRefFields(["_id1_", "_id2_", "_id3_"])). - return map; + return ids.reduce((map, id) => { + map[id] = _cache[id] as any; + return map; + }, {} as { [id: string]: Opt }); }; let _GetRefFields: (ids: string[]) => Promise<{ [id: string]: Opt }> = errorFunc; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index debb11066..d2ab67849 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -263,6 +263,7 @@ export class DocumentOptions { viewTransitionTime?: number; // transition duration for view parameters presTransition?: number; //the time taken for the transition TO a document presDuration?: number; //the duration of the slide in presentation view + presZoomText?: boolean; // whether text anchors should shown in a larger box when following links to make them stand out borderRounding?: string; boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow data?: any; @@ -1043,6 +1044,9 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), url, options, id); } + export function CollectionAnchorDocument(options: DocumentOptions = {}, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); + } export function TextanchorDocument(options: DocumentOptions = {}, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); } @@ -1051,6 +1055,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); } + export function InkAnchorDocument(options: DocumentOptions, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); + } + export function HTMLAnchorDocument(documents: Array, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), options, id); } @@ -1407,12 +1415,15 @@ export namespace DocUtils { } }); funcs && - Object.keys(funcs).map(key => { - const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) { - doc[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }) : undefined; - } - }); + Object.keys(funcs) + .filter(key => key.endsWith('-setter')) + .map(key => { + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) { + const setFunc = Cast(funcs[key + '-setter'], 'string', null); + doc[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; + } + }); return doc; } export function AssignOpts(doc: Doc | undefined, reqdOpts: DocumentOptions, items?: Doc[]) { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e4d48d4de..d9273c2c9 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -199,7 +199,7 @@ export class DocumentManager { static GetContextPath(doc: Opt, includeExistingViews?: boolean) { if (!doc) return []; const srcContext = Cast(doc.context, Doc, null) ?? Cast(Cast(doc.annotationOn, Doc, null)?.context, Doc, null); - var containerDocContext = srcContext ? [srcContext] : []; + var containerDocContext = srcContext ? [srcContext, doc] : [doc]; while ( containerDocContext.length && containerDocContext[0]?.context && @@ -286,7 +286,7 @@ export class DocumentManager { return annoContainerView.iconify(() => DocumentManager.Instance.AddViewRenderedCb(targetDoc, () => this.jumpToDocument(targetDoc, { ...options, originalTarget, toggleTarget: false }, createViewFunc, docContextPath, finished)), 30); } if (!docView && targetDoc.type !== DocumentType.MARKER) { - annoContainerView.focus(targetDoc, {}); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below + annoContainerView.focus(targetDoc, options); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below } } diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 7da16ca78..46d44fea4 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -48,7 +48,7 @@ export class LinkManager { const a2 = DocCast(linkdata[1]); a1 && a2 && - Promise.all([a1.proto, a2.proto]).then( + Promise.all([Doc.GetProto(a1), Doc.GetProto(a2)]).then( action(protos => { (protos[0] as Doc)?.[DirectLinksSym].add(link); (protos[1] as Doc)?.[DirectLinksSym].add(link); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 00ae85d12..36095700c 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -130,29 +130,21 @@ export class SharingManager extends React.Component<{}> { if (!this.populating && Doc.UserDoc()[Id] !== '__guest__') { this.populating = true; const userList = await RequestPromise.get(Utils.prepend('/getUsers')); - const raw = JSON.parse(userList) as User[]; - const sharingDocs: ValidatedUser[] = []; - const evaluating = raw.map(async user => { - const isCandidate = user.email !== Doc.CurrentUserEmail; - if (isCandidate) { - const sharingDoc = await DocServer.GetRefField(user.sharingDocumentId); - const linkDatabase = await DocServer.GetRefField(user.linkDatabaseId); + const raw = (JSON.parse(userList) as User[]).filter(user => user.email !== 'guest' && user.email !== Doc.CurrentUserEmail); + const docs = await DocServer.GetRefFields(raw.reduce((list, user) => [...list, user.sharingDocumentId, user.linkDatabaseId], [] as string[])); + raw.map( + action((newUser: User) => { + const sharingDoc = docs[newUser.sharingDocumentId]; + const linkDatabase = docs[newUser.linkDatabaseId]; if (sharingDoc instanceof Doc && linkDatabase instanceof Doc) { - sharingDocs.push({ user, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.userColor) }); - } - } - }); - return Promise.all(evaluating).then(() => { - runInAction(async () => { - for (const sharer of sharingDocs) { - if (!this.users.find(user => user.user.email === sharer.user.email)) { - this.users.push(sharer); + if (!this.users.find(user => user.user.email === newUser.email)) { + this.users.push({ user: newUser, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.userColor) }); // LinkManager.addLinkDB(sharer.linkDatabase); } } - }); - this.populating = false; - }); + }) + ); + this.populating = false; } }; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index f61d147cf..9298c881c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -315,7 +315,13 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout, pinDocContent, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null), currentFrame: Cast(docs.lastElement()?.currentFrame, 'number', null) }); + TabDocView.PinDoc(docs, { + pinAudioPlay: true, + pinDocLayout, + pinData: { dataview: true }, + activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null), + currentFrame: Cast(docs.lastElement()?.currentFrame, 'number', null), + }); e.stopPropagation(); }} /> @@ -496,7 +502,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const rootView = this.props.views()[0]; const rootDoc = rootView?.rootDoc; if (rootDoc) { - const anchor = rootView.ComponentView?.getAnchor?.(true) ?? rootDoc; + const anchor = rootView.ComponentView?.getAnchor?.(false) ?? rootDoc; const trail = DocCast(anchor.presTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true); if (trail !== anchor.presTrail) { DocUtils.MakeLink({ doc: anchor }, { doc: trail }, 'link trail'); diff --git a/src/client/views/InkTangentHandles.tsx b/src/client/views/InkTangentHandles.tsx index c4a2f603e..71e0ff63c 100644 --- a/src/client/views/InkTangentHandles.tsx +++ b/src/client/views/InkTangentHandles.tsx @@ -38,18 +38,19 @@ export class InkTangentHandles extends React.Component { setupMoveUpEvents( this, e, - (e: PointerEvent, down: number[], delta: number[]) => { + action((e: PointerEvent, down: number[], delta: number[]) => { if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('DocDecs move tangent'); if (e.altKey) this.onBreakTangent(controlIndex); const inkMoveEnd = this.props.inkView.ptFromScreen({ X: delta[0], Y: delta[1] }); const inkMoveStart = this.props.inkView.ptFromScreen({ X: 0, Y: 0 }); InkStrokeProperties.Instance.moveTangentHandle(this.docView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex); return false; - }, - () => { + }), + action(() => { this.props.inkView.controlUndo?.end(); + this.props.inkView.controlUndo = undefined; UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']); - }, + }), emptyFunction ); }; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 76c1aa80a..17cf6a678 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -25,7 +25,7 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, HeightSym, WidthSym } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; -import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; import { DashColor, OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; @@ -41,11 +41,13 @@ import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; -import { DocComponentView, DocFocusOptions } from './nodes/DocumentView'; +import { DocComponentView, DocFocusOptions, DocumentView } from './nodes/DocumentView'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { StyleProp } from './StyleProvider'; import Color = require('color'); +import { Docs } from '../documents/Documents'; +import { PinProps, PresBox } from './nodes/trails'; @observer export class InkingStroke extends ViewBoxBaseComponent() { @@ -78,12 +80,28 @@ export class InkingStroke extends ViewBoxBaseComponent() { // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1); - getAnchor = (addAsAnnotation: boolean) => { - return this._subContentView?.getAnchor?.(addAsAnnotation) || this.rootDoc; + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { + if (this._subContentView) { + return this._subContentView.getAnchor?.(addAsAnnotation) || this.rootDoc; + } + + if (!addAsAnnotation && !pinProps) return this.rootDoc; + + const anchor = Docs.Create.InkAnchorDocument({ title: 'Ink anchor:' + this.rootDoc.title, presDuration: 1100, presTransition: 1000, unrendered: true, annotationOn: this.rootDoc }); + if (anchor) { + anchor.backgroundColor = 'transparent'; + // /* addAsAnnotation &&*/ this.addDocument(anchor); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: true, inkable: true } }, this.rootDoc); + return anchor; + } + return this.rootDoc; }; - scrollFocus = (textAnchor: Doc, options: DocFocusOptions) => { - return this._subContentView?.scrollFocus?.(textAnchor, options); + scrollFocus = (docView: DocumentView, anchor: Doc, options: DocFocusOptions) => { + if (this._subContentView) return this._subContentView?.scrollFocus?.(docView, anchor, options); + + const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; + return PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; }; /** * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); @@ -349,7 +367,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1); const closed = InkingStroke.IsClosed(inkData); const isInkMask = BoolCast(this.layoutDoc.isInkMask); - const fillColor = isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : StrCast(this.layoutDoc.fillColor, 'transparent'); + const fillColor = isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FillColor) ?? 'transparent'; const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); // bcz: Hack!! Not really sure why, but having fractional values for width/height of mask ink strokes causes the dragging clone (see DragManager) to be offset from where it should be. diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 625dc2748..64f116a09 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -145,7 +145,6 @@ export class MainView extends React.Component { if (ele && prog) { // remove from DOM setTimeout(() => { - clearTimeout(); prog.style.transition = '1s'; prog.style.width = '100%'; }, 0); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 3bdf65d01..30867a774 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -8,7 +8,7 @@ import { GetEffectiveAcl } from '../../fields/util'; import { unimplementedFunction, Utils } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import { DragManager } from '../util/DragManager'; -import { undoBatch } from '../util/UndoManager'; +import { undoBatch, UndoManager } from '../util/UndoManager'; import './MarqueeAnnotator.scss'; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @@ -48,7 +48,11 @@ export class MarqueeAnnotator extends React.Component { constructor(props: any) { super(props); - AnchorMenu.Instance.OnCrop = (e: PointerEvent) => this.props.anchorMenuCrop?.(this.highlight('', true), true); + AnchorMenu.Instance.OnCrop = (e: PointerEvent) => { + if (this.props.anchorMenuCrop) { + UndoManager.RunInBatch(() => this.props.anchorMenuCrop?.(this.highlight('', true, undefined, false), true), 'cropping'); + } + }; AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true)); AnchorMenu.Instance.OnAudio = unimplementedFunction; AnchorMenu.Instance.Highlight = this.highlight; @@ -87,11 +91,8 @@ export class MarqueeAnnotator extends React.Component { AnchorMenu.Instance.StartDrag = action((e: PointerEvent, ele: HTMLElement) => { e.preventDefault(); e.stopPropagation(); - const sourceAnchorCreator = () => { - const annoDoc = this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true); // hyperlink color - annoDoc && this.props.addDocument(annoDoc); - return annoDoc; - }; + const sourceAnchorCreator = () => this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true); // hyperlink color + const targetCreator = (annotationOn: Doc | undefined) => { const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); FormattedTextBox.SelectOnLoad = target[Id]; @@ -116,11 +117,7 @@ export class MarqueeAnnotator extends React.Component { e.preventDefault(); e.stopPropagation(); var cropRegion: Doc | undefined; - const sourceAnchorCreator = () => { - cropRegion = this.highlight('', true); // hyperlink color - cropRegion && this.props.addDocument(cropRegion); - return cropRegion; - }; + const sourceAnchorCreator = () => (cropRegion = this.highlight('', true, undefined, true)); // hyperlink color const targetCreator = (annotationOn: Doc | undefined) => this.props.anchorMenuCrop!(cropRegion, false)!; DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { @@ -159,7 +156,15 @@ export class MarqueeAnnotator extends React.Component { return marqueeAnno; } - const textRegionAnno = Docs.Create.HTMLAnchorDocument([], { annotationOn: this.props.rootDoc, text: this.props.selectionText(), backgroundColor: 'transparent', title: 'Selection on ' + this.props.rootDoc.title }); + const textRegionAnno = Docs.Create.HTMLAnchorDocument([], { + annotationOn: this.props.rootDoc, + text: this.props.selectionText(), + backgroundColor: 'transparent', + presDuration: 2100, + presTransition: 500, + presZoomText: true, + title: 'Selection on ' + this.props.rootDoc.title, + }); let minX = Number.MAX_VALUE; let maxX = -Number.MAX_VALUE; let minY = Number.MAX_VALUE; @@ -262,10 +267,6 @@ export class MarqueeAnnotator extends React.Component { AnchorMenu.Instance.jumpTo(cliX, cliY); - if (AnchorMenu.Instance.Highlighting) { - // when highlighter has been toggled when menu is pinned, we auto-highlight immediately on mouse up - this.highlight('rgba(245, 230, 95, 0.75)', false); // yellowish highlight color for highlighted text (should match AnchorMenu's highlight color) - } this.props.finishMarquee(undefined, undefined, e); runInAction(() => (this._width = this._height = 0)); } else { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 5f87f0697..153c30052 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -31,6 +31,7 @@ export enum StyleProp { BorderRounding = 'borderRounding', // border radius of the document view Color = 'color', // foreground color of Document view items BackgroundColor = 'backgroundColor', // background color of a document view + FillColor = 'fillColor', // fill color of an ink stroke or shape WidgetColor = 'widgetColor', // color to display UI widgets on a document view -- used for the sidebar divider dragger on a text note HideLinkButton = 'hideLinkButton', // hides the blue-dot link button. used when a document acts like a button LinkSource = 'linkSource', // source document of a link -- used by LinkAnchorBox @@ -158,6 +159,8 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 28f08b6ce..eecab9d86 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -190,7 +190,7 @@ export class CollectionStackedTimeline extends CollectionSubView 15 && !this.IsTrimming) { - const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd, undefined, true); + const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true); setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false)); } (!isClick || !wasSelecting) && (this._markerEnd = undefined); @@ -273,7 +273,7 @@ export class CollectionStackedTimeline extends CollectionSubView { if (shiftKey) { - CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this.currentTime, undefined, undefined, true); + CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.currentTime, undefined, undefined, true); } else { !wasPlaying && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width)); } @@ -388,8 +388,10 @@ export class CollectionStackedTimeline extends CollectionSubView, anchorEndTime: Opt, docAnchor: Opt, addAsAnnotation: boolean) { + static createAnchor(rootDoc: Doc, dataDoc: Doc, fieldKey: string, anchorStartTime: Opt, anchorEndTime: Opt, docAnchor: Opt, addAsAnnotation: boolean) { if (anchorStartTime === undefined) return rootDoc; + const startTag = '_timecodeToShow'; + const endTag = '_timecodeToHide'; const anchor = docAnchor ?? Docs.Create.LabelDocument({ diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index e6f29ec37..437b22040 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -21,7 +21,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; import React = require('react'); -import { DocFocusOptions } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; import { PresBox } from '../nodes/trails'; @observer @@ -52,8 +52,7 @@ export class CollectionTimeView extends CollectionSubView() { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, annotationOn: this.rootDoc, }); - anchor.presPinPivotField = this.pivotField; // should be captured in pinDocView below - PresBox.pinDocView(anchor, { pinData: { viewType: true, filters: true } }, this.rootDoc); + PresBox.pinDocView(anchor, { pinData: { viewType: true, pivot: true, filters: true } }, this.rootDoc); if (addAsAnnotation) { // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered @@ -67,32 +66,12 @@ export class CollectionTimeView extends CollectionSubView() { }; @action - scrollFocus = (anchor: Doc, options: DocFocusOptions) => { - if (options.preview) { - // if in preview, then override document's fields with view spec - this._focusFilters = StrListCast(anchor.presPinDocFilters); - this._focusRangeFilters = StrListCast(anchor.presPinDocRangeFilters); - this._focusPivotField = StrCast(anchor.presPinPivotField); - return undefined; - } - const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; - - // should be part of restoreTargetDocView - this.layoutDoc._prevFilterIndex = 1; - this.layoutDoc._pivotField = anchor.presPinPivotField; - - return PresBox.restoreTargetDocView( - this.props.DocumentView?.(), // - { pinDocLayout: BoolCast(anchor.presPinLayout) }, - anchor, - focusSpeed, - { - viewType: anchor.presPinViewType ? true : false, - filters: anchor.presPinDocFilters || anchor.presPinDocRangeFilters ? true : false, - } - ) - ? focusSpeed - : undefined; + scrollPreview = (docView: DocumentView, anchor: Doc, options: DocFocusOptions) => { + // if in preview, then override document's fields with view spec + this._focusFilters = StrListCast(anchor.presPinDocFilters); + this._focusRangeFilters = StrListCast(anchor.presPinDocRangeFilters); + this._focusPivotField = StrCast(anchor.presPinPivotField); + return undefined; }; layoutEngine = () => this._layoutEngine; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f93810deb..b75f315ca 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -247,13 +247,13 @@ export class TabDocView extends React.Component { alert('Cannot pin presentation document to itself'); return; } - const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false); - const pinDoc = anchorDoc && anchorDoc !== doc ? Doc.MakeDelegate(anchorDoc) : Doc.MakeDelegate(doc); + const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); + const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); pinDoc.presentationTargetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the alias' layout are the presentation slide children. the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; - pinDoc.presDuration = 2000; + pinDoc.presDuration = pinDoc.presDuration ?? 1000; pinDoc.groupWithUp = false; pinDoc.context = curPres; // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time @@ -274,7 +274,7 @@ export class TabDocView extends React.Component { pinDoc.presStartTime = NumCast(doc.clipStart); pinDoc.presEndTime = NumCast(doc.clipEnd, duration); } - PresBox.pinDocView(pinDoc, pinProps.pinDocContent ? { ...pinProps, pinData: PresBox.pinDataTypes(doc) } : pinProps, doc); + //PresBox.pinDocView(pinDoc, pinProps.pinDocContent ? { ...pinProps, pinData: PresBox.pinDataTypes(doc) } : pinProps, anchorDoc && anchorDoc !== doc && !anchorDoc.unrendered ? anchorDoc : doc); pinDoc.onClick = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)'); Doc.AddDocToList(curPres, 'data', pinDoc, presSelected); //save position diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 7dd9cdb8b..fa0695fb2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -14,6 +14,7 @@ export interface ViewDefBounds { x: number; y: number; z?: number; + rotation?: number; text?: string; zIndex?: number; width?: number; @@ -31,6 +32,7 @@ export interface PoolData { x: number; y: number; z?: number; + rotation?: number; zIndex?: number; width?: number; height?: number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7d176f426..0477c6a16 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -8,7 +8,6 @@ import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from import { Id } from '../../../../fields/FieldSymbols'; import { InkData, InkField, InkTool, PointData, Segment } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; -import { ObjectField } from '../../../../fields/ObjectField'; import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; import { ScriptField } from '../../../../fields/ScriptField'; @@ -41,7 +40,7 @@ import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDo import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; -import { PresBox } from '../../nodes/trails/PresBox'; +import { PinProps, PresBox } from '../../nodes/trails/PresBox'; import { VideoBox } from '../../nodes/VideoBox'; import { CreateImage } from '../../nodes/WebBoxRenderer'; import { StyleProp } from '../../StyleProvider'; @@ -523,6 +522,10 @@ export class CollectionFreeFormView extends CollectionSubView ); @@ -1425,17 +1428,21 @@ export class CollectionFreeFormView extends CollectionSubView { + scrollFocus = (docView: DocumentView, anchor: Doc, options: DocFocusOptions) => { const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; if (options.preview) { this._focusFilters = StrListCast(anchor.presPinDocFilters); this._focusRangeFilters = StrListCast(anchor.presPinDocRangeFilters); return undefined; } - return PresBox.restoreTargetDocView( - this.props.DocumentView?.(), // - { pinDocLayout: BoolCast(anchor.presPinLayout) }, - anchor, - focusSpeed, - { - dataview: anchor.presData ? true : false, - pannable: anchor.presPinData ? true : false, - viewType: anchor.presPinViewType ? true : false, - filters: anchor.presPinDocFilters || anchor.presPinDocRangeFilters ? true : false, - } - ) - ? focusSpeed - : undefined; + return PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document - getAnchor = (addAsAnnotation: boolean) => { - if (this.props.Document.annotationOn) { - return this.rootDoc; - } - + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.TextanchorDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._viewType), presTransition: 500, annotationOn: this.rootDoc }); - PresBox.pinDocView(anchor, { pinData: { pannable: true, viewType: true, filters: true } }, this.rootDoc); + const anchor = Docs.Create.CollectionAnchorDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._viewType), unrendered: true, presTransition: 500, annotationOn: this.rootDoc }); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: true, viewType: true, filters: true } }, this.rootDoc); if (addAsAnnotation) { if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1d59d3356..81dc3aafd 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -18,6 +18,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import './AudioBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; +import { PinProps, PresBox } from './trails'; /** * AudioBox @@ -136,20 +137,19 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - return ( + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { + const anchor = CollectionStackedTimeline.createAnchor( this.rootDoc, this.dataDoc, this.annotationKey, - '_timecodeToShow' /* audioStart */, - '_timecodeToHide' /* audioEnd */, this._ele?.currentTime || Cast(this.props.Document._currentTimecode, 'number', null) || (this.mediaState === media_state.Recording ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined), undefined, undefined, addAsAnnotation - ) || this.rootDoc - ); + ) || this.rootDoc; + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.rootDoc); + return anchor; }; // updates timecode and shows it in timeline, follows links at time diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index ba510e1dc..9a32556f8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,7 +1,6 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; -import { InkField } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; @@ -20,11 +19,10 @@ import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import React = require('react'); export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { - dataProvider?: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string } | undefined; + dataProvider?: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; rotation?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string } | undefined; sizeProvider?: (doc: Doc, replica: string) => { width: number; height: number } | undefined; renderCutoffProvider: (doc: Doc) => boolean; zIndex?: number; - rotation: number; dataTransition?: string; replica: string; CollectionFreeFormView: CollectionFreeFormView; @@ -46,7 +44,7 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames @observable _animPos: number[] | undefined = undefined; @observable _contentView: DocumentView | undefined | null; @@ -56,7 +54,7 @@ export class CollectionFreeFormDocumentView extends DocComponent, property: string) => { - if (doc === this.layoutDoc) + if (doc === this.layoutDoc) { // prettier-ignore switch (property) { case StyleProp.Opacity: return this.Opacity; // only change the opacity for this specific document, not its children case StyleProp.BackgroundColor: return this.BackgroundColor; case StyleProp.Color: return this.Color; } + } return this.props.styleProvider?.(doc, props, property); }; @@ -108,6 +110,15 @@ export class CollectionFreeFormDocumentView extends DocComponent }); } + public static setStringValues(time: number, d: Doc, vals: { [val: string]: Opt }) { + const timecode = Math.round(time); + Object.keys(vals).forEach(val => { + const findexed = Cast(d[`${val}-indexed`], listSpec('string'), []).slice(); + findexed[timecode] = vals[val] as any as string; + d[`${val}-indexed`] = new List(findexed); + }); + } + public static setValues(time: number, d: Doc, vals: { [val: string]: Opt }) { const timecode = Math.round(time); Object.keys(vals).forEach(val => { diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 2432d4c37..5783d0e57 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -16,6 +16,7 @@ import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { TaskCompletionBox } from './TaskCompletedBox'; import React = require('react'); import _ = require('lodash'); +import { PinProps } from './trails'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; @@ -175,7 +176,7 @@ export class DocumentLinksButton extends React.Component { + action((screenX: number, screenY: number, startLink: Doc, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView, pinProps?: PinProps) => { if (startLink === endLink) { DocumentLinksButton.StartLink = undefined; DocumentLinksButton.StartLinkView = undefined; @@ -183,7 +184,7 @@ export class DocumentLinksButton extends React.Component DocumentLinksButton.StartLink && DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View)}> + onClick={e => + DocumentLinksButton.StartLink && + DocumentLinksButton.finishLinkClick( + e.clientX, + e.clientY, + DocumentLinksButton.StartLink, + this.props.View.props.Document, + true, + this.props.View, + (e.shiftKey ? { pinDocLayout: true, pinDocContent: true, pinData: { poslayoutview: true, dataannos: true, dataview: true } } : {}) as PinProps + ) + }> ) : null} @@ -292,7 +304,7 @@ export class DocumentLinksButton extends React.Component void; export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocComponentView { updateIcon?: () => void; // updates the icon representation of the document - getAnchor?: (addAsAnnotation: boolean) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) - scrollFocus?: (doc: Doc, options: DocFocusOptions) => Opt; // returns the duration of the focus + getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) + scrollPreview?: (docView: DocumentView, doc: Doc, options: DocFocusOptions) => Opt; // returns the duration of the focus + scrollFocus?: (docView: DocumentView, doc: Doc, options: DocFocusOptions) => Opt; // returns the duration of the focus brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void; reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views @@ -585,7 +586,13 @@ export class DocumentViewInternal extends DocComponent (focusSpeed => (PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined))(options.instant ? 0 : options.zoomTime ?? 500)); + const focusSpeed = targetMatch && scrollFocus?.(this.props.DocumentView(), presItem?.proto === anchor ? presItem : anchor, options); // FOCUS: navigate through the display hierarchy making sure the target is in view const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing; diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 5c0005dae..8fa01c97a 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -13,7 +13,7 @@ import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; -import { DocFocusOptions } from './DocumentView'; +import { DocFocusOptions, DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; const EquationSchema = createSchema({}); @@ -42,14 +42,14 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent ); } getAnchor = (addAsAnnotation: boolean) => { - const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc }); + const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc, unrendered: true }); anchor.xRange = new List(Array.from(this._plot.options.xAxis.domain)); anchor.yRange = new List(Array.from(this._plot.options.yAxis.domain)); if (addAsAnnotation) this.addDocument(anchor); return anchor; }; @action - scrollFocus = (doc: Doc, smooth: DocFocusOptions) => { + scrollFocus = (docView: DocumentView, doc: Doc, options: DocFocusOptions) => { this.dataDoc.xRange = new List(Array.from(Cast(doc.xRange, listSpec('number'), Cast(this.dataDoc.xRange, listSpec('number'), [-10, 10])))); this.dataDoc.yRange = new List(Array.from(Cast(doc.yRange, listSpec('number'), Cast(this.dataDoc.xRange, listSpec('number'), [-1, 9])))); return 0; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0ba576e55..363cd1d94 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -8,7 +8,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { createSchema } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; import { DashColor, emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; @@ -26,11 +26,11 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComp import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, OpenWhere } from './DocumentView'; +import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView'; import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; -import { PresBox } from './trails'; +import { PinProps, PresBox } from './trails'; import React = require('react'); import Color = require('color'); import { LinkDocPreview } from './LinkDocPreview'; @@ -71,34 +71,14 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; - return PresBox.restoreTargetDocView( - this.props.DocumentView?.(), // - { pinDocLayout: BoolCast(anchor.presPinLayout) }, - anchor, - focusSpeed, - !anchor.presPinData - ? {} - : { - pannable: true, - dataannos: anchor.presAnnotations !== undefined, - dataview: true, - } - ) - ? focusSpeed - : undefined; - }; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document - - getAnchor = (addAsAnnotation: boolean) => { + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const anchor = this._getAnchor?.(this._savedAnnotations, false) ?? // use marquee anchor, otherwise, save zoom/pan as anchor Docs.Create.ImageanchorDocument({ title: 'ImgAnchor:' + this.rootDoc.title, presTransition: 1000, unrendered: true, annotationOn: this.rootDoc }); if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; /* addAsAnnotation &&*/ this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinData: { pannable: true } }, this.rootDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: true } }, this.rootDoc); return anchor; } return this.rootDoc; @@ -177,9 +157,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.rootDoc; - getTitle() { return this.rootDoc['title-custom'] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : typeof this.rootDoc[this.fieldKey] === 'string' ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 88d134bba..8d7ab2f0d 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -5,7 +5,7 @@ import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; +import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, PdfField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; @@ -22,13 +22,13 @@ import { LightboxView } from '../LightboxView'; import { CreateImage } from '../nodes/WebBoxRenderer'; import { PDFViewer } from '../pdf/PDFViewer'; import { SidebarAnnos } from '../SidebarAnnos'; +import { DocFocusOptions, DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { ImageBox } from './ImageBox'; import './PDFBox.scss'; +import { PinProps, PresBox } from './trails'; import { VideoBox } from './VideoBox'; import React = require('react'); -import { PresBox } from './trails'; -import { DocFocusOptions } from './DocumentView'; @observer export class PDFBox extends ViewBoxAnnotatableComponent() { @@ -200,18 +200,18 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.brushView(view); - scrollFocus = (doc: Doc, options: DocFocusOptions) => { + scrollFocus = (docView: DocumentView, anchor: Doc, options: DocFocusOptions) => { let didToggle = false; - if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { + if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(anchor) && !this.SidebarShown) { this.toggleSidebar(options.preview); didToggle = true; } - if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; - this._initialScrollTarget = doc; - PresBox.restoreTargetDocView(this.props.DocumentView?.(), {}, doc, options.zoomTime ?? 500, { pannable: doc.presPinData ? true : false }); - return this._pdfViewer?.scrollFocus(doc, NumCast(doc.presPinViewScroll, NumCast(doc.y)), options) ?? (didToggle ? 1 : undefined); + if (this._sidebarRef?.current?.makeDocUnfiltered(anchor)) return 1; + this._initialScrollTarget = anchor; + PresBox.restoreTargetDocView(docView, anchor, options.zoomTime ?? 500); + return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.presPinViewScroll, NumCast(anchor.y)), options) ?? (didToggle ? 1 : undefined); }; - getAnchor = (addAsAnnotation: boolean) => { + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { let ele: Opt = undefined; if (this._pdfViewer?.selectionContent()) { ele = document.createElement('div'); @@ -223,11 +223,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent { this._pdfViewer = pdfViewer; - if (this._initialScrollTarget) { - this.scrollFocus(this._initialScrollTarget, { instant: true }); + const docView = this.props.DocumentView?.(); + if (this._initialScrollTarget && docView) { + this.scrollFocus(docView, this._initialScrollTarget, { instant: true }); this._initialScrollTarget = undefined; } }; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index f94996c66..61e4894f0 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -130,7 +130,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { const startTime = Cast(this.layoutDoc._currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined); - return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow', '_timecodeToHide', startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.rootDoc; + return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.rootDoc; }; videoLoad = () => { diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 281967a21..fa2021642 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -20,6 +20,7 @@ import { EditableView } from '../EditableView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { OverlayView } from '../OverlayView'; import { DocumentIconContainer } from './DocumentIcon'; +import { DocFocusOptions, DocumentView } from './DocumentView'; import './ScriptingBox.scss'; const _global = (window /* browser */ || global) /* node */ as any; @@ -481,10 +482,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { - return undefined; - }; - getSuggestedParams(pos: number) { const firstScript = this.rawText.slice(0, pos); const indexP = firstScript.lastIndexOf('.'); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 1dfa55c64..c26562e7c 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -7,6 +7,7 @@ import * as rp from 'request-promise'; import { Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; +import { ObjectField } from '../../../fields/ObjectField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; import { emptyFunction, formatTime, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; @@ -27,11 +28,11 @@ import { DocumentDecorations } from '../DocumentDecorations'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; +import { OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; +import { PinProps, PresBox } from './trails'; import './VideoBox.scss'; -import { ObjectField } from '../../../fields/ObjectField'; -import { DocFocusOptions, OpenWhere } from './DocumentView'; const path = require('path'); /** @@ -390,13 +391,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSummary)?.startDragging(downX, downY, 'move', true)); }; - getAnchor = (addAsAnnotation: boolean) => { + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const timecode = Cast(this.layoutDoc._currentTimecode, 'number', null); const marquee = AnchorMenu.Instance.GetAnchor?.(undefined, addAsAnnotation); - return ( - CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow' /* videoStart */, '_timecodeToHide' /* videoEnd */, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || - this.rootDoc - ); + if (!addAsAnnotation && marquee) marquee.backgroundColor = 'transparent'; + const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || this.rootDoc; + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.rootDoc); + return anchor; }; // sets video info on load @@ -953,14 +954,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - if (doc !== this.rootDoc) { - const showTime = Cast(doc._timecodeToShow, 'number', null); - showTime !== undefined && setTimeout(() => this.Seek(showTime), 100); - return 0.1; - } - }; - // renders CollectionStackedTimeline @computed get renderTimeline() { return ( diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 4c9bead9d..caab18e0d 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as WebRequest from 'web-request'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; @@ -11,8 +11,9 @@ import { listSpec } from '../../../fields/Schema'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, WebField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, getWordAtPoint, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils'; +import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; +import { DragManager } from '../../util/DragManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; @@ -21,7 +22,6 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; -import { DocumentDecorations } from '../DocumentDecorations'; import { Colors } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; @@ -29,13 +29,13 @@ import { AnchorMenu } from '../pdf/AnchorMenu'; import { Annotation } from '../pdf/Annotation'; import { SidebarAnnos } from '../SidebarAnnos'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, DocumentView, DocumentViewInternal, DocumentViewProps } from './DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from './LinkDocPreview'; import { VideoBox } from './VideoBox'; import './WebBox.scss'; import React = require('react'); -import { DragManager } from '../../util/DragManager'; +import { PinProps, PresBox } from './trails'; const { CreateImage } = require('./WebBoxRenderer'); const _global = (window /* browser */ || global) /* node */ as any; const htmlToText = require('html-to-text'); @@ -189,6 +189,7 @@ export class WebBox extends ViewBoxAnnotatableComponent void) => (this._setBrushViewer = func); brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); - scrollFocus = (doc: Doc, options: DocFocusOptions) => { - if (this._url && StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), options.preview); - if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { + focus = (doc: Doc, options: DocFocusOptions) => { + !doc.unrendered && this.props.DocumentView?.() && this.scrollFocus(this.props.DocumentView?.(), doc, {}); + this.props.focus(doc, options); + }; + scrollFocus = (docView: DocumentView, anchor: Doc, options: DocFocusOptions) => { + if (this._url && StrCast(anchor.webUrl) !== this._url) this.submitURL(StrCast(anchor.webUrl), options.preview); + if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(anchor) && !this.SidebarShown) { this.toggleSidebar(options.preview); } - if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; - if (doc !== this.rootDoc && this._outerRef.current) { + if (this._sidebarRef?.current?.makeDocUnfiltered(anchor)) return 1; + if (anchor !== this.rootDoc && this._outerRef.current) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(doc.y) + doc[HeightSym](), this._scrollHeight)); + const scrollTo = !anchor[HeightSym]() + ? NumCast(anchor.y) + : Utils.scrollIntoView(NumCast(anchor.y), anchor[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[HeightSym](), this._scrollHeight)); + const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; if (scrollTo !== undefined && this._initialScroll === undefined) { - const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; this.goTo(scrollTo, focusSpeed, options.easeFunc); + PresBox.restoreTargetDocView(docView, anchor, focusSpeed); return focusSpeed; } else if (!this._webPageHasBeenRendered || !this._scrollHeight || this._initialScroll !== undefined) { this._initialScroll = scrollTo; + return PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; } } return undefined; }; - getAnchor = (addAsAnnotation: boolean) => { + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { let ele: Opt = undefined; try { const contents = this._iframe?.contentWindow?.getSelection()?.getRangeAt(0).cloneContents(); @@ -330,9 +339,11 @@ export class WebBox extends ViewBoxAnnotatableComponent { + const layoutFrameNumber = Cast(dv.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values + const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed + if (contentFrameNumber !== undefined) { + CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { backgroundColor: color }); + } else { + dv.rootDoc._backgroundColor = color; + } + }); + } else { + const selected = SelectionManager.Docs().length ? SelectionManager.Docs() : LinkManager.currentLink ? [LinkManager.currentLink] : []; + if (checkResult) { + return selected.lastElement()?._backgroundColor ?? 'transparent'; + } + selected.forEach(doc => (doc._backgroundColor = color)); } - if (selected) selected._backgroundColor = color; }); // toggle: Set overlay status of selected document diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 788de7af9..269438a7c 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -45,7 +45,7 @@ import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { SidebarAnnos } from '../../SidebarAnnos'; import { StyleProp } from '../../StyleProvider'; -import { DocFocusOptions, DocumentViewInternal, OpenWhere } from '../DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { LinkDocPreview } from '../LinkDocPreview'; import { DashDocCommentView } from './DashDocCommentView'; @@ -932,7 +932,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + scrollFocus = (docView: DocumentView, textAnchor: Doc, options: DocFocusOptions) => { let didToggle = false; if (DocListCast(this.Document[this.fieldKey + '-sidebar']).includes(textAnchor) && !this.SidebarShown) { this.toggleSidebar(options.preview); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 13cbd87eb..45d386436 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -4,9 +4,9 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; -import { AnimationSym, Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc'; +import { AnimationSym, Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../../fields/Doc'; import { Copy, Id } from '../../../../fields/FieldSymbols'; -import { InkTool } from '../../../../fields/InkField'; +import { InkField, InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; @@ -34,8 +34,23 @@ import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; +import { SerializationHelper } from '../../../util/SerializationHelper'; const { Howl } = require('howler'); +export interface pinDataTypes { + scrollable?: boolean; + pannable?: boolean; + viewType?: boolean; + inkable?: boolean; + filters?: boolean; + pivot?: boolean; + temporal?: boolean; + clippable?: boolean; + dataview?: boolean; + textview?: boolean; + poslayoutview?: boolean; + dataannos?: boolean; +} export interface PinProps { audioRange?: boolean; activeFrame?: number; @@ -45,18 +60,7 @@ export interface PinProps { pinDocLayout?: boolean; // pin layout info (width/height/x/y) pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text) pinAudioPlay?: boolean; // pin audio annotation - pinData?: { - scrollable?: boolean | undefined; - pannable?: boolean | undefined; - viewType?: boolean | undefined; - filters?: boolean | undefined; - temporal?: boolean | undefined; - clippable?: boolean | undefined; - dataview?: boolean | undefined; - textview?: boolean | undefined; - poslayoutview?: boolean | undefined; - dataannos?: boolean | undefined; - }; + pinData?: pinDataTypes; } @observer @@ -318,19 +322,9 @@ export class PresBox extends ViewBoxBaseComponent() { this.onHideDocument(); //Handles hide after/before } }); - static pinDataTypes(target?: Doc): { - scrollable?: boolean; - pannable?: boolean; - viewType?: boolean; - filters?: boolean; - temporal?: boolean; - clippable?: boolean; - dataview?: boolean; - textview?: boolean; - poslayoutview?: boolean; - dataannos?: boolean; - } { + static pinDataTypes(target?: Doc): pinDataTypes { const targetType = target?.type as any; + const inkable = [DocumentType.INK].includes(targetType); const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetType) || target?._viewType === CollectionViewType.Stacking; const pannable = [DocumentType.IMG, DocumentType.PDF].includes(targetType) || (targetType === DocumentType.COL && target?._viewType === CollectionViewType.Freeform); const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(targetType); @@ -340,18 +334,19 @@ export class PresBox extends ViewBoxBaseComponent() { const textview = [DocumentType.RTF].includes(targetType) && target?.activeFrame === undefined; const viewType = targetType === DocumentType.COL; const filters = true; + const pivot = true; const dataannos = false; - return { scrollable, pannable, viewType, filters, temporal, clippable, dataview, textview, poslayoutview, dataannos }; + return { scrollable, pannable, inkable, viewType, pivot, filters, temporal, clippable, dataview, textview, poslayoutview, dataannos }; } @action playAnnotation = (anno: AudioField) => {}; @action - static restoreTargetDocView(bestTargetView: Opt, pinProps: PinProps | undefined, activeItem: Doc, transTime: number, pinDataTypes = this.pinDataTypes(bestTargetView?.rootDoc)) { - if (!bestTargetView) return; - const bestTarget = bestTargetView.rootDoc; + static restoreTargetDocView(bestTargetView: Opt, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.presPinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) { + const bestTarget = bestTargetView?.rootDoc ?? (targetDoc?.unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc); + if (!bestTarget) return; let changed = false; - if (pinProps?.pinDocLayout) { + if (pinDocLayout) { if ( bestTarget.x !== NumCast(activeItem.presX, NumCast(bestTarget.x)) || bestTarget.y !== NumCast(activeItem.presY, NumCast(bestTarget.y)) || @@ -369,33 +364,51 @@ export class PresBox extends ViewBoxBaseComponent() { changed = true; } } - if (pinDataTypes.clippable) { + if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.presPinClipWidth !== undefined)) { if (bestTarget._clipWidth !== activeItem.presPinClipWidth) { bestTarget._clipWidth = activeItem.presPinClipWidth; changed = true; } } - if (pinDataTypes.temporal) { + if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) { if (bestTarget._currentTimecode !== activeItem.presStartTime) { bestTarget._currentTimecode = activeItem.presStartTime; changed = true; } } - if (pinDataTypes.viewType && activeItem.presPinViewType !== undefined) { + if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.presFillColor !== undefined || activeItem.color !== undefined))) { + if (bestTarget.fillColor !== activeItem.presFillColor) { + Doc.GetProto(bestTarget).fillColor = activeItem.presFillColor; + changed = true; + } + if (bestTarget.color !== activeItem.color) { + Doc.GetProto(bestTarget).color = activeItem.color; + changed = true; + } + } + if ((pinDataTypes?.viewType && activeItem.presPinViewType !== undefined) || (!pinDataTypes && activeItem.presPinViewType !== undefined)) { if (bestTarget._viewType !== activeItem.presPinViewType) { bestTarget._viewType = activeItem.presPinViewType; changed = true; } } - if (pinDataTypes.filters && activeItem.presPinDocFilters !== undefined) { + if ((pinDataTypes?.filters && activeItem.presPinDocFilters !== undefined) || (!pinDataTypes && activeItem.presPinDocFilters !== undefined)) { if (bestTarget.docFilters !== activeItem.presPinDocFilters) { bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presPinDocFilters as ObjectField) || new List([]); changed = true; } } - if (pinDataTypes.scrollable) { + if ((pinDataTypes?.pivot && activeItem.presPinPvitoField !== undefined) || (!pinDataTypes && activeItem.presPinPivotField !== undefined)) { + if (bestTarget.pivotField !== activeItem.presPinPivotField) { + bestTarget.pivotField = activeItem.presPinPivotField; + bestTarget._prevFilterIndex = 1; // need to revisit this...see CollectionTimeView + changed = true; + } + } + + if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.presPinViewScroll !== undefined)) { if (bestTarget._scrollTop !== activeItem.presPinViewScroll) { bestTarget._scrollTop = activeItem.presPinViewScroll; changed = true; @@ -406,39 +419,59 @@ export class PresBox extends ViewBoxBaseComponent() { } } } - if (pinDataTypes.dataannos) { + if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.presAnnotations !== undefined)) { const fkey = Doc.LayoutFieldKey(bestTarget); - Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List([...DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered), ...DocListCast(activeItem.presAnnotations)]); + const oldItems = DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered); + const newItems = DocListCast(activeItem.presAnnotations).map(doc => { + doc.hidden = false; + return doc; + }); + const hiddenItems = DocListCast(bestTarget[fkey + '-annotations']) + .filter(doc => !doc.unrendered && !newItems.includes(doc)) + .map(doc => { + doc.hidden = true; + return doc; + }); + const newList = new List([...oldItems, ...hiddenItems, ...newItems]); + Doc.GetProto(bestTarget)[fkey + '-annotations'] = newList; } - if (pinDataTypes.dataview && activeItem.presData !== undefined) { + if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) { bestTarget._dataTransition = `all ${transTime}ms`; const fkey = Doc.LayoutFieldKey(bestTarget); Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; bestTarget[fkey + '-useAlt'] = activeItem.presUseAlt; setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); } - if (pinDataTypes.textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; - if (pinDataTypes.poslayoutview) { + if ((pinDataTypes?.textview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) { + Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; + } + if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) { changed = true; + const layoutField = Doc.LayoutFieldKey(bestTarget); + const transitioned = new Set(); StrListCast(activeItem.presPinLayoutData) - .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) - .forEach(data => { - const doc = DocServer.GetCachedRefField(data.id) as Doc; - doc._dataTransition = `all ${transTime}ms`; - doc.x = data.x; - doc.y = data.y; - doc._width = data.w; - doc._height = data.h; + .map(str => JSON.parse(str) as { id: string; x: number; y: number; back: string; fill: string; w: number; h: number; data: string; text: string }) + .forEach(async data => { + const doc = DocCast(DocServer.GetCachedRefField(data.id)); + if (doc) { + transitioned.add(doc); + const field = !data.data ? undefined : await SerializationHelper.Deserialize(data.data); + const tfield = !data.text ? undefined : await SerializationHelper.Deserialize(data.text); + doc._dataTransition = `all ${transTime}ms`; + doc.x = data.x; + doc.y = data.y; + data.back && (doc._backgroundColor = data.back); + data.fill && (doc._fillColor = data.fill); + doc._width = data.w; + doc._height = data.h; + data.data && (Doc.GetProto(doc).data = field); + data.text && (Doc.GetProto(doc).text = tfield); + Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc); + } }); - setTimeout( - () => - StrListCast(activeItem.presPinLayoutData) - .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) - .forEach(action(data => ((DocServer.GetCachedRefField(data.id) as Doc)._dataTransition = undefined))), - transTime + 10 - ); + setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10); } - if (pinDataTypes.pannable) { + if (pinDataTypes?.pannable || (!pinDataTypes && (activeItem.presPinViewBounds !== undefined || activeItem.presPinViewX !== undefined || activeItem.presPinViewScale !== undefined))) { const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }; @@ -460,7 +493,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } if (changed) { - return bestTargetView.setViewTransition('all', transTime); + return bestTargetView?.setViewTransition('all', transTime); } } @@ -499,12 +532,31 @@ export class PresBox extends ViewBoxBaseComponent() { pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered)); } if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text; + if (pinProps.pinData.inkable) { + pinDoc.presFillColor = targetDoc.fillColor; + pinDoc.presColor = targetDoc.color; + } if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop; if (pinProps.pinData.clippable) pinDoc.presPinClipWidth = targetDoc._clipWidth; if (pinProps.pinData.poslayoutview) - pinDoc.presPinLayoutData = new List(DocListCast(targetDoc[fkey] as ObjectField).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) }))); + pinDoc.presPinLayoutData = new List( + DocListCast(targetDoc[fkey] as ObjectField).map(d => + JSON.stringify({ + id: d[Id], + x: NumCast(d.x), + y: NumCast(d.y), + w: NumCast(d._width), + h: NumCast(d._height), + fill: StrCast(d._fillColor), + back: StrCast(d._backgroundColor), + data: SerializationHelper.Serialize(d.data instanceof ObjectField ? d.data[Copy]() : ''), + text: SerializationHelper.Serialize(d.text instanceof ObjectField ? d.text[Copy]() : ''), + }) + ) + ); if (pinProps.pinData.viewType) pinDoc.presPinViewType = targetDoc._viewType; if (pinProps.pinData.filters) pinDoc.presPinDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField); + if (pinProps.pinData.pivot) pinDoc.presPinPivotField = targetDoc._pivotField; if (pinProps.pinData.pannable) { pinDoc.presPinViewX = NumCast(targetDoc._panX); pinDoc.presPinViewY = NumCast(targetDoc._panY); @@ -586,7 +638,7 @@ export class PresBox extends ViewBoxBaseComponent() { const pinDocLayout = (BoolCast(activeItem.presPinLayout) || BoolCast(activeItem.presPinView)) && DocCast(targetDoc.context)?._currentFrame === undefined; if (activeItem.presPinData || activeItem.presPinView || pinDocLayout) { // targetDoc may or may not be displayed. so get the first available document (or alias) view that matches targetDoc and use it - PresBox.restoreTargetDocView(DocumentManager.Instance.getFirstDocumentView(targetDoc), { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500)); + // PresBox.restoreTargetDocView(DocumentManager.Instance.getFirstDocumentView(targetDoc), { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500), undefined, targetDoc); } }; const finishAndRestoreLayout = () => { @@ -660,16 +712,43 @@ export class PresBox extends ViewBoxBaseComponent() { _exitTrail: Opt<() => void>; PlayTrail = (docs: Doc[]) => { - const savedStates = docs.map(doc => (doc._viewType !== CollectionViewType.Freeform ? undefined : { c: doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) })); + const savedStates = docs.map(doc => { + switch (doc.type) { + case DocumentType.COL: + if (doc._viewType === CollectionViewType.Freeform) return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) }; + break; + case DocumentType.INK: + if (doc.data instanceof InkField) { + return { type: doc.type, doc, data: doc.data?.[Copy](), fillColor: doc.fillColor, color: doc.color, x: NumCast(doc.x), y: NumCast(doc.y) }; + } + } + return undefined; + }); this.startPresentation(0); this._exitTrail = () => { savedStates .filter(savedState => savedState) .map(savedState => { - const { x, y, s, c } = savedState!; - c._panX = x; - c._panY = y; - c._viewScale = s; + switch (savedState?.type) { + case CollectionViewType.Freeform: + { + const { x, y, s, doc } = savedState!; + doc._panX = x; + doc._panY = y; + doc._viewScale = s; + } + break; + case DocumentType.INK: + { + const { data, fillColor, color, x, y, doc } = savedState!; + doc.x = x; + doc.y = y; + doc.data = data; + doc.fillColor = fillColor; + doc.color = color; + } + break; + } }); LightboxView.SetLightboxDoc(undefined); Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc); @@ -1869,7 +1948,7 @@ export class PresBox extends ViewBoxBaseComponent() { ); } - scrollFocus = () => { + scrollFocus = (docView: DocumentView, doc: Doc, options: DocFocusOptions) => { // this.gotoDocument(0); // this.startOrPause(false); return undefined; diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 4a7f5d038..fc8f1da49 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -41,7 +41,6 @@ export class AnchorMenu extends AntimodeMenu { @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)'; @observable private _showLinkPopup: boolean = false; - @observable public Highlighting: boolean = false; @observable public Status: 'marquee' | 'annotation' | '' = ''; public onMakeAnchor: () => Opt = () => undefined; // Method to get anchor from text search @@ -121,9 +120,7 @@ export class AnchorMenu extends AntimodeMenu { @action highlightClicked = (e: React.MouseEvent) => { - if (!this.Highlight(this.highlightColor, false, undefined, true) && this.Pinned) { - this.Highlighting = !this.Highlighting; - } + this.Highlight(this.highlightColor, false, undefined, true); AnchorMenu.Instance.fadeOut(true); }; @@ -138,7 +135,7 @@ export class AnchorMenu extends AntimodeMenu { const button = ( diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 2db44788f..9877690f8 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -30,7 +30,7 @@ const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; // The workerSrc property shall be specified. -pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@2.14.305/build/pdf.worker.js'; +pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@2.16.105/build/pdf.worker.js'; interface IViewerProps extends FieldViewProps { Document: Doc; @@ -179,7 +179,7 @@ export class PDFViewer extends React.Component { let focusSpeed: Opt; if (doc !== this.props.rootDoc && mainCont) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - const scrollTo = doc.unrendered ? scrollTop : Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, this._scrollHeight); + const scrollTo = doc.unrendered ? scrollTop : Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight); if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) { if (!this._pdfViewer) this._initialScroll = { loc: scrollTo, easeFunc: options.easeFunc }; else if (!options.instant && !options.preview) this._scrollStopper = smoothScroll((focusSpeed = options.zoomTime ?? 500), mainCont, scrollTo, options.easeFunc, this._scrollStopper); @@ -518,6 +518,10 @@ export class PDFViewer extends React.Component { return this.props.styleProvider?.(doc, props, property); }; + focus = (doc: Doc, options: DocFocusOptions) => { + !doc.unrendered && this.props.DocumentView?.() && this.scrollToAnnotation(doc); + this.props.focus(doc, options); + }; renderAnnotations = (docFilters?: () => string[], mixBlendMode?: any, display?: string) => (
{ PanelWidth={this.panelWidth} ScreenToLocalTransform={this.overlayTransform} dropAction={'alias'} + focus={this.focus} docFilters={docFilters} select={emptyFunction} bringToFront={emptyFunction} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index df49c32f0..ed5eaa756 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -722,13 +722,22 @@ export namespace Doc { return bestAlias ?? Doc.MakeAlias(doc); } - export async function makeClone(doc: Doc, cloneMap: Map, linkMap: Map, rtfs: { copy: Doc; key: string; field: RichTextField }[], exclusions: string[], dontCreate: boolean, asBranch: boolean): Promise { + export async function makeClone( + doc: Doc, + cloneMap: Map, + linkMap: Map, + rtfs: { copy: Doc; key: string; field: RichTextField }[], + exclusions: string[], + topLevelExclusions: string[], + dontCreate: boolean, + asBranch: boolean + ): Promise { if (Doc.IsBaseProto(doc)) return doc; if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; const copy = dontCreate ? (asBranch ? Cast(doc.branchMaster, Doc, null) || doc : doc) : new Doc(undefined, true); cloneMap.set(doc[Id], copy); const fieldExclusions = doc.type === DocumentType.MARKER ? exclusions.filter(ex => ex !== 'annotationOn') : exclusions; - const filter = [...fieldExclusions, ...Cast(doc.cloneFieldFilter, listSpec('string'), [])]; + const filter = [...fieldExclusions, ...topLevelExclusions, ...Cast(doc.cloneFieldFilter, listSpec('string'), [])]; await Promise.all( Object.keys(doc).map(async key => { if (filter.includes(key)) return; @@ -739,10 +748,10 @@ export namespace Doc { const list = await Cast(doc[key], listSpec(Doc)); const docs = list && (await DocListCastAsync(list))?.filter(d => d instanceof Doc); if (docs !== undefined && docs.length) { - const clones = await Promise.all(docs.map(async d => Doc.makeClone(d, cloneMap, linkMap, rtfs, exclusions, dontCreate, asBranch))); + const clones = await Promise.all(docs.map(async d => Doc.makeClone(d, cloneMap, linkMap, rtfs, exclusions, [], dontCreate, asBranch))); !dontCreate && assignKey(new List(clones)); } else if (doc[key] instanceof Doc) { - assignKey(key.includes('layout[') ? undefined : key.startsWith('layout') ? (doc[key] as Doc) : await Doc.makeClone(doc[key] as Doc, cloneMap, linkMap, rtfs, exclusions, dontCreate, asBranch)); // reference documents except copy documents that are expanded template fields + assignKey(key.includes('layout[') ? undefined : key.startsWith('layout') ? (doc[key] as Doc) : await Doc.makeClone(doc[key] as Doc, cloneMap, linkMap, rtfs, exclusions, [], dontCreate, asBranch)); // reference documents except copy documents that are expanded template fields } else { !dontCreate && assignKey(ObjectField.MakeCopy(field)); if (field instanceof RichTextField) { @@ -754,17 +763,18 @@ export namespace Doc { }; if (key === 'proto') { if (doc[key] instanceof Doc) { - assignKey(await Doc.makeClone(doc[key] as Doc, cloneMap, linkMap, rtfs, exclusions, dontCreate, asBranch)); + assignKey(await Doc.makeClone(doc[key] as Doc, cloneMap, linkMap, rtfs, exclusions, [], dontCreate, asBranch)); } } else if (key === 'anchor1' || key === 'anchor2') { if (doc[key] instanceof Doc) { - assignKey(await Doc.makeClone(doc[key] as Doc, cloneMap, linkMap, rtfs, exclusions, true, asBranch)); + assignKey(await Doc.makeClone(doc[key] as Doc, cloneMap, linkMap, rtfs, exclusions, [], true, asBranch)); } } else { if (field instanceof RefField) { assignKey(field); } else if (cfield instanceof ComputedField) { - !dontCreate && assignKey(ComputedField.MakeFunction(cfield.script.originalScript)); + !dontCreate && assignKey(cfield[Copy]()); + // ComputedField.MakeFunction(cfield.script.originalScript)); } else if (field instanceof ObjectField) { await copyObjectField(field); } else if (field instanceof Promise) { @@ -776,7 +786,7 @@ export namespace Doc { }) ); for (const link of Array.from(doc[DirectLinksSym])) { - const linkClone = await Doc.makeClone(link, cloneMap, linkMap, rtfs, exclusions, dontCreate, asBranch); + const linkClone = await Doc.makeClone(link, cloneMap, linkMap, rtfs, exclusions, [], dontCreate, asBranch); linkMap.set(link, linkClone); } if (!dontCreate) { @@ -793,7 +803,7 @@ export namespace Doc { export async function MakeClone(doc: Doc, dontCreate: boolean = false, asBranch = false, cloneMap: Map = new Map()) { const linkMap = new Map(); const rtfMap: { copy: Doc; key: string; field: RichTextField }[] = []; - const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf', 'branches', 'branchOf', 'context'], dontCreate, asBranch); + const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf', 'branches', 'branchOf'], ['context'], dontCreate, asBranch); Array.from(linkMap.entries()).map((links: Doc[]) => LinkManager.Instance.addLink(links[1], true)); rtfMap.map(({ copy, key, field }) => { const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index b23732b45..5f02bd73d 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -185,9 +185,11 @@ export class ComputedField extends ScriptField { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Doc | string | number | boolean }) { + public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Doc | string | number | boolean }, setterscript?: string) { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); - return compiled.compiled ? new ComputedField(compiled) : undefined; + const compiledsetter = setterscript ? ScriptField.CompileScript(setterscript, { ...params, value: 'any' }, false, capturedVariables) : undefined; + const compiledsetscript = compiledsetter?.compiled ? compiledsetter : undefined; + return compiled.compiled ? new ComputedField(compiled, compiledsetscript) : undefined; } public static MakeInterpolatedNumber(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number, defaultVal: Opt) { if (!doc[`${fieldKey}-indexed`]) { diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 33809824f..f461cf3fa 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -501,7 +501,7 @@ export namespace DashUploadUtils { const parseExifData = async (source: string) => { const image = await request.get(source, { encoding: null }); - const { data, error } = await new Promise(resolve => { + const { data, error } = await new Promise<{ data: any; error: any }>(resolve => { new ExifImage({ image }, (error, data) => { let reason: Opt = undefined; if (error) { diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 9b91a35a6..68b003496 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -199,7 +199,7 @@ export namespace WebSocket { return Database.Instance.getDocument(id, callback); } function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { - process.stdout.write(`.`); + process.stdout.write(`+`); GetRefFieldLocal([id, callback]); } -- cgit v1.2.3-70-g09d2 From f1dea8f31886c1e5e3d8bb772434009803b8fb8a Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 28 Feb 2023 14:47:27 -0500 Subject: added view spec capture options to complete link --- src/client/views/DocumentButtonBar.scss | 19 +++--- src/client/views/DocumentButtonBar.tsx | 70 ++++++++++++++++++++-- src/client/views/nodes/DocumentLinksButton.tsx | 63 ++----------------- .../views/nodes/formattedText/FormattedTextBox.tsx | 15 ++++- 4 files changed, 91 insertions(+), 76 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/views/DocumentButtonBar.scss b/src/client/views/DocumentButtonBar.scss index 835d6c8bb..1abf33cac 100644 --- a/src/client/views/DocumentButtonBar.scss +++ b/src/client/views/DocumentButtonBar.scss @@ -18,6 +18,8 @@ $linkGap: 3px; cursor: pointer; } +.documentButtonBar-endLinkTypes, +.documentButtonBar-linkTypes, .documentButtonBar-followTypes, .documentButtonBar-pinTypes { position: absolute; @@ -28,15 +30,6 @@ $linkGap: 3px; height: 20px; align-items: center; } -.documentButtonBar-linkTypes { - position: absolute; - display: none; - width: 60px; - top: -14px; - background: black; - height: 20px; - align-items: center; -} .documentButtonBar-followTypes { width: 20px; display: none; @@ -72,6 +65,14 @@ $linkGap: 3px; } } } +.documentButtonBar-endLink { + color: white; + &:hover { + .documentButtonBar-endLinkTypes { + display: flex; + } + } +} .documentButtonBar-pinIcon { &:hover { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 9298c881c..20c35739e 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -28,6 +28,7 @@ import { TemplateMenu } from './TemplateMenu'; import React = require('react'); import { DocumentType } from '../documents/DocumentTypes'; import { FontIconBox } from './nodes/button/FontIconBox'; +import { PinProps } from './nodes/trails'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -285,6 +286,52 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
); } + @observable subEndLink = ''; + @computed + get endLinkButton() { + const linkBtn = (pinDocLayout: boolean, pinDocContent: boolean, icon: IconProp) => { + const tooltip = `Finish Link and Save ${this.subEndLink} data`; + return !this.view0 ? null : ( + {tooltip}}> +
+ (this.subEndLink = (pinDocLayout ? 'Layout' : '') + (pinDocLayout && pinDocContent ? ' &' : '') + (pinDocContent ? ' Content' : '')))} + onPointerLeave={action(e => (this.subEndLink = ''))} + onClick={e => { + const docs = this.props + .views() + .filter(v => v) + .map(dv => dv!.rootDoc); + this.view0 && + DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.props.Document, true, this.view0, { + pinDocLayout, + pinDocContent, + pinData: !pinDocContent ? {} : { poslayoutview: true, dataannos: true, dataview: true }, + } as PinProps); + + e.stopPropagation(); + }} + /> +
+
+ ); + }; + return !this.view0 ? null : ( +
+
+ {linkBtn(true, false, 'window-maximize')} + {linkBtn(false, true, 'address-card')} + {linkBtn(true, true, 'id-card')} +
+ +
+ ); + } @observable subPin = ''; @computed @@ -497,6 +544,23 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV this._showLinkPopup = !this._showLinkPopup; e.stopPropagation(); }; + + @observable _captureEndLinkLayout = false; + @action + captureEndLinkLayout = (e: React.PointerEvent) => { + this._captureEndLinkLayout = !this._captureEndLinkLayout; + }; + @observable _captureEndLinkContent = false; + @action + captureEndLinkContent = (e: React.PointerEvent) => { + this._captureEndLinkContent = !this._captureEndLinkContent; + }; + + @action + captureEndLinkState = (e: React.PointerEvent) => { + this._captureEndLinkContent = this._captureEndLinkLayout = !this._captureEndLinkLayout; + }; + @action toggleTrail = (e: React.PointerEvent) => { const rootView = this.props.views()[0]; @@ -539,11 +603,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{this.linkButton}
)} - {(DocumentLinksButton.StartLink || Doc.UserDoc()['documentLinksButton-fullMenu']) && DocumentLinksButton.StartLink !== doc ? ( -
- -
- ) : null} + {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== doc ?
{this.endLinkButton}
: null} { Doc.noviceMode ? null :
{this.templateButton}
/*
{this.metadataButton}
*/ diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 5783d0e57..a40599d85 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -128,48 +128,8 @@ export class DocumentLinksButton extends React.Component { - if (doubleTap && !this.props.StartLink) { - if (DocumentLinksButton.StartLink === this.props.View.props.Document) { - DocumentLinksButton.StartLink = undefined; - DocumentLinksButton.StartLinkView = undefined; - DocumentLinksButton.AnnotationId = undefined; - } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) { - const sourceDoc = DocumentLinksButton.StartLink; - const targetDoc = this.props.View.ComponentView?.getAnchor?.(true) || this.props.View.Document; - const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, 'links'); //why is long drag here when this is used for completing links by clicking? - - LinkManager.currentLink = linkDoc; - - runInAction(() => { - if (linkDoc) { - TaskCompletionBox.textDisplayed = 'Link Created'; - TaskCompletionBox.popupX = e.screenX; - TaskCompletionBox.popupY = e.screenY - 133; - TaskCompletionBox.taskCompleted = true; - - LinkDescriptionPopup.popupX = e.screenX; - LinkDescriptionPopup.popupY = e.screenY - 100; - LinkDescriptionPopup.descriptionPopup = true; - - const rect = document.body.getBoundingClientRect(); - if (LinkDescriptionPopup.popupX + 200 > rect.width) { - LinkDescriptionPopup.popupX -= 190; - TaskCompletionBox.popupX -= 40; - } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; - TaskCompletionBox.popupY -= 40; - } - - setTimeout( - action(() => (TaskCompletionBox.taskCompleted = false)), - 2500 - ); - } - }); - } - } + action(e => { + DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View); }) ) ); @@ -280,22 +240,7 @@ export class DocumentLinksButton extends React.Component ) : null} {!this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node -
- DocumentLinksButton.StartLink && - DocumentLinksButton.finishLinkClick( - e.clientX, - e.clientY, - DocumentLinksButton.StartLink, - this.props.View.props.Document, - true, - this.props.View, - (e.shiftKey ? { pinDocLayout: true, pinDocContent: true, pinData: { poslayoutview: true, dataannos: true, dataview: true } } : {}) as PinProps - ) - }> +
) : null} @@ -304,7 +249,7 @@ export class DocumentLinksButton extends React.Component this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation); + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { + if (!pinProps) return this.rootDoc; + const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc, unrendered: true }); + this.addDocument(anchor); + this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true } }, this.rootDoc); + return anchor; + }; @action setupAnchorMenu = () => { @@ -988,8 +996,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000)); } } - - return this._didScroll ? this._focusSpeed : didToggle ? 1 : undefined; // if we actually scrolled, then return some focusSpeed + const finalFocusSpeed = this._didScroll ? this._focusSpeed : didToggle ? 1 : undefined; + PresBox.restoreTargetDocView(docView, textAnchor, finalFocusSpeed ?? 0); + return finalFocusSpeed; // if we actually scrolled, then return some focusSpeed }; // if the scroll height has changed and we're in autoHeight mode, then we need to update the textHeight component of the doc. -- cgit v1.2.3-70-g09d2 From 5e7989da274606638c96f649e97e9d1a979956f5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 28 Feb 2023 20:57:01 -0500 Subject: cleaning up of following inPlace links to overlay current inplaceContainer contents instead of deleting them. --- src/client/util/LinkFollower.ts | 8 ++--- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/LightboxView.tsx | 11 ++---- src/client/views/PropertiesButtons.tsx | 39 ++++++++++------------ src/client/views/PropertiesView.tsx | 6 ++-- src/client/views/collections/CollectionSubView.tsx | 1 + src/client/views/collections/TabDocView.tsx | 12 ++++++- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 ++- src/client/views/nodes/DocumentView.tsx | 9 ++--- src/client/views/nodes/PDFBox.tsx | 10 +++++- src/client/views/nodes/WebBox.tsx | 9 ++++- .../views/nodes/formattedText/FormattedTextBox.tsx | 8 +++++ src/client/views/pdf/PDFViewer.tsx | 2 +- 13 files changed, 72 insertions(+), 49 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index bbfd516da..50bc89ed2 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,11 +1,11 @@ import { action, runInAction } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { List } from '../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; -import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; -import { CollectionDockingView } from '../views/collections/CollectionDockingView'; +import { DocumentType } from '../documents/DocumentTypes'; import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; -import { DocFocusOptions, DocumentViewSharedProps, OpenWhere, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocFocusOptions, DocumentViewSharedProps, OpenWhere, ViewAdjustment } from '../views/nodes/DocumentView'; import { PresBox } from '../views/nodes/trails'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; @@ -35,7 +35,7 @@ export class LinkFollower { const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { const createTabForTarget = (didFocus: boolean) => new Promise(res => { - const where = LightboxView.LightboxDoc ? OpenWhere.inPlace : (StrCast(sourceDoc.followLinkLocation, followLoc) as OpenWhere); + const where = LightboxView.LightboxDoc ? OpenWhere.lightbox : (StrCast(sourceDoc.followLinkLocation, followLoc) as OpenWhere); docViewProps.addDocTab(doc, where); setTimeout(() => { const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 20c35739e..af868ba9c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -243,7 +243,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
this.props.views().map(view => view?.docView?.toggleFollowLink(undefined, undefined, false)))}> + onClick={undoBatch(e => this.props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}>
{followBtn( true, diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index e531bf71c..c9b1dcfd8 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -145,13 +145,6 @@ export class LightboxView extends React.Component { } } public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) => { - if (location !== OpenWhere.lightbox) { - const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; - if (inPlaceView) { - inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); - return true; - } - } SelectionManager.DeselectAll(); return LightboxView.SetLightboxDoc( doc, @@ -318,7 +311,7 @@ export class LightboxView extends React.Component {
{ e.stopPropagation(); LightboxView.LightboxDoc!._fitWidth = !LightboxView.LightboxDoc!._fitWidth; @@ -327,7 +320,7 @@ export class LightboxView extends React.Component {
{ e.stopPropagation(); CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, OpenWhereMod.none); diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index a152b4948..7e33ee495 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -6,6 +6,7 @@ import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; +import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, StrCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; import { DocUtils } from '../documents/Documents'; @@ -129,27 +130,21 @@ export class PropertiesButtons extends React.Component<{}, {}> { onClick => { SelectionManager.Views().forEach(dv => { const containerDoc = dv.rootDoc; - containerDoc.followAllLinks = - containerDoc.noShadow = - containerDoc.noHighlighting = - containerDoc._isLinkButton = - containerDoc._fitContentsToBox = - containerDoc._forceActive = - containerDoc._isInPlaceContainer = - !containerDoc._isInPlaceContainer; - containerDoc.followLinkLocation = containerDoc._isInPlaceContainer ? OpenWhere.inPlace : undefined; + //containerDoc.followAllLinks = + // containerDoc.noShadow = + // containerDoc.noHighlighting = + // containerDoc._forceActive = + containerDoc._fitContentsToBox = containerDoc._isInPlaceContainer = !containerDoc._isInPlaceContainer; containerDoc._xPadding = containerDoc._yPadding = containerDoc._isInPlaceContainer ? 10 : undefined; - const menuDoc = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]).lastElement(); - if (menuDoc) { - menuDoc.hideDecorations = menuDoc._forceActive = menuDoc._fitContentsToBox = menuDoc._isLinkButton = menuDoc._noShadow = menuDoc.noHighlighting = containerDoc._isInPlaceContainer; - if (!dv.allLinks.find(link => link.anchor1 === menuDoc || link.anchor2 === menuDoc)) { - DocUtils.MakeLink({ doc: dv.rootDoc }, { doc: menuDoc }, 'back link to container'); - } - DocListCast(menuDoc[Doc.LayoutFieldKey(menuDoc)]).forEach(menuItem => { - menuItem.followLinkAudio = menuItem.followAllLinks = menuItem._isLinkButton = true; - menuItem._followLinkLocation = OpenWhere.inPlace; + const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]); + dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' }); + containerContents.forEach(doc => { + DocListCast(doc.links).forEach(link => { + doc.isLinkButton = true; + //doc.followLinkLocation = OpenWhere.inPlace; + link.linkDisplay = false; }); - } + }); }); } ); @@ -309,10 +304,12 @@ export class PropertiesButtons extends React.Component<{}, {}> { docView.setToggleDetail(); break; case 'linkInPlace': - docView.toggleFollowLink('inPlace', false, false); + docView.toggleFollowLink(false, false); + docView.props.Document.followLinkLocation = docView.props.Document._isLinkButton ? OpenWhere.inPlace : undefined; break; case 'linkOnRight': - docView.toggleFollowLink('add:right', false, false); + docView.toggleFollowLink(false, false); + docView.props.Document.followLinkLocation = docView.props.Document._isLinkButton ? OpenWhere.addRight : undefined; break; } }); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index f7708d801..e9d1433c3 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1406,7 +1406,7 @@ export class PropertiesView extends React.Component { }); @undoBatch - changeFollowBehavior = action((follow: string) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = follow)); + changeFollowBehavior = action((follow: Opt) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = follow)); @undoBatch changeAnimationBehavior = action((behavior: string) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimEffect = behavior)); @@ -1615,8 +1615,8 @@ export class PropertiesView extends React.Component {

Follow by

- this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}> + diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 27ae3041f..c88ae314e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -67,6 +67,7 @@ export function CollectionSubView(moreProps?: X) { // to its children which may be templates. // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey' @computed get dataField() { + if (this.layoutDoc[this.props.fieldKey]) return this.layoutDoc[this.props.fieldKey]; // sets the dataDoc's data field to an empty list if the data field is undefined - prevents issues with addonly // setTimeout changes it outside of the @computed section !this.dataDoc[this.props.fieldKey] && setTimeout(() => !this.dataDoc[this.props.fieldKey] && (this.dataDoc[this.props.fieldKey] = new List())); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index b75f315ca..01872df84 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -358,7 +358,17 @@ export class TabDocView extends React.Component { if (doc.dockingConfig) return DashboardView.openDashboard(doc); // prettier-ignore switch (whereFields[0]) { - case OpenWhere.inPlace: // fall through to lightbox + case undefined: + case OpenWhere.inPlace: { + if (this.layoutDoc?.isInPlaceContainer) { + const inPlaceView = !doc.annotationOn && DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + const data = inPlaceView?.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)]; + if (inPlaceView && (!data || data instanceof List)) { + inPlaceView.layoutDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } + } + } case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location); case OpenWhere.dashboard: return DashboardView.openDashboard(doc); case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0477c6a16..78804b070 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1395,6 +1395,7 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this.props.isAnnotationOverlay) return this.props.addDocTab(doc, where); switch (where) { case OpenWhere.inParent: return this.props.addDocument?.(doc) || false; @@ -1412,9 +1413,10 @@ export class CollectionFreeFormView extends CollectionSubView(doc instanceof Doc ? [doc] : doc); + this.layoutDoc[this.props.fieldKey] = new List(doc instanceof Doc ? [doc] : doc); return true; } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 039a75a1b..beb0f8e3a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -792,7 +792,7 @@ export class DocumentViewInternal extends DocComponent, zoom?: boolean, setTargetToggle?: boolean): void => { + toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => { this.Document.ignoreClick = false; if (setTargetToggle) { this.Document.followLinkToggle = !this.Document.followLinkToggle; @@ -802,7 +802,6 @@ export class DocumentViewInternal extends DocComponent (this.Document.ignoreClick = !this.Document.ignoreClick), icon: this.Document.ignoreClick ? 'unlock' : 'lock' }); - onClicks.push({ description: this.Document.isLinkButton ? 'Remove Follow Behavior' : 'Follow Link in Place', event: () => this.toggleFollowLink('inPlace', false, false), icon: 'link' }); - !this.Document.isLinkButton && onClicks.push({ description: 'Follow Link on Right', event: () => this.toggleFollowLink('add:right', false, false), icon: 'link' }); - onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(undefined, false, false), icon: 'link' }); - onClicks.push({ description: (this.Document.followLinkToggle ? 'Remove' : 'Make') + ' Target Visibility Toggle', event: () => this.toggleFollowLink(undefined, false, true), icon: 'map-pin' }); + onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' }); + onClicks.push({ description: (this.Document.followLinkToggle ? 'Remove' : 'Make') + ' Target Visibility Toggle', event: () => this.toggleFollowLink(false, true), icon: 'map-pin' }); onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); !existingOnClick && cm.addItem({ description: 'OnClick...', addDivider: true, noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } else if (DocListCast(this.Document.links).length) { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 8d7ab2f0d..6b2f2246a 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -22,7 +22,7 @@ import { LightboxView } from '../LightboxView'; import { CreateImage } from '../nodes/WebBoxRenderer'; import { PDFViewer } from '../pdf/PDFViewer'; import { SidebarAnnos } from '../SidebarAnnos'; -import { DocFocusOptions, DocumentView } from './DocumentView'; +import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { ImageBox } from './ImageBox'; import './PDFBox.scss'; @@ -200,6 +200,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.brushView(view); + sidebarAddDocTab = (doc: Doc, where: OpenWhere) => { + if (DocListCast(this.props.Document[this.props.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { + this.toggleSidebar(false); + return true; + } + return this.props.addDocTab(doc, where); + }; scrollFocus = (docView: DocumentView, anchor: Doc, options: DocFocusOptions) => { let didToggle = false; if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(anchor) && !this.SidebarShown) { @@ -487,6 +494,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { + if (DocListCast(this.props.Document[this.props.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { + this.toggleSidebar(false); + return true; + } + return this.props.addDocTab(doc, where); + }; getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { let ele: Opt = undefined; try { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 123499647..dc7a11e6e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -230,6 +230,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + if (DocListCast(this.props.Document[this.props.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { + this.toggleSidebar(false); + return true; + } + return this.props.addDocTab(doc, where); + }; + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { if (!pinProps) return this.rootDoc; const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc, unrendered: true }); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 9877690f8..ffc49e4f3 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -16,7 +16,7 @@ import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; -import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import { StyleProp } from '../StyleProvider'; -- cgit v1.2.3-70-g09d2 From 8aeab8c3f25c556e39f3e9e58f9c321e79459df8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Mar 2023 12:22:03 -0400 Subject: fixed scriptingbox to remove script if text is empty. fixed scripting with capturedvariables not to cache scripts with lists of captured documents. fixed runtime warnings with stackedTimelined and AudioBox --- src/client/util/Scripting.ts | 8 +++++++- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/MainView.tsx | 3 +-- src/client/views/StyleProvider.tsx | 2 +- src/client/views/TemplateMenu.tsx | 1 - .../views/collections/CollectionStackedTimeline.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 10 +++------- src/client/views/nodes/DocumentView.tsx | 4 ---- src/client/views/nodes/ScriptingBox.tsx | 16 +++++++++------- src/fields/Doc.ts | 9 +-------- 10 files changed, 24 insertions(+), 33 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index d32298c83..f17a98616 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -7,7 +7,9 @@ import * as typescriptlib from '!!raw-loader!./type_decls.d'; import * as ts from 'typescript'; import { Doc, Field } from '../../fields/Doc'; +import { ToScriptString } from '../../fields/FieldSymbols'; import { ObjectField } from '../../fields/ObjectField'; +import { RefField } from '../../fields/RefField'; import { ScriptField } from '../../fields/ScriptField'; import { scriptingGlobals, ScriptingGlobals } from './ScriptingGlobals'; export { ts }; @@ -180,7 +182,11 @@ function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, inde export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult { const captured = options.capturedVariables ?? {}; - const signature = Object.keys(captured).reduce((p, v) => p + `${v}=${captured[v] instanceof ObjectField ? 'XXX' : captured[v].toString()}`, ''); + const signature = Object.keys(captured).reduce((p, v) => { + const formatCapture = (obj: any) => `${v}=${obj instanceof RefField ? 'XXX' : obj.toString()}`; + if (captured[v] instanceof Array) return p + (captured[v] as any).map(formatCapture); + return p + formatCapture(captured[v]); + }, ''); const found = ScriptField.GetScriptFieldCache(script + ':' + signature); if (found) return found as CompiledScript; const { requiredType = '', addReturn = false, params = {}, capturedVariables = {}, typecheck = true } = options; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index af868ba9c..9389fed01 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -518,7 +518,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ) }>
- {} +
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2e04ca3dd..118635a38 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -10,7 +10,7 @@ import 'normalize.css'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { ScriptField } from '../../fields/ScriptField'; -import { DocCast, StrCast } from '../../fields/Types'; +import { StrCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; @@ -57,7 +57,6 @@ import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; -import { PresBox } from './nodes/trails'; import { OverlayView } from './OverlayView'; import { AnchorMenu } from './pdf/AnchorMenu'; import { PreviewCursor } from './PreviewCursor'; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index dba5d703f..b11117b11 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -5,7 +5,7 @@ import { action, runInAction } from 'mobx'; import { extname } from 'path'; import { Doc, Opt } from '../../fields/Doc'; import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../fields/Types'; -import { DashColor, emptyFunction, lightOrDark } from '../../Utils'; +import { DashColor, lightOrDark } from '../../Utils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocFocusOrOpen } from '../util/DocumentManager'; import { LinkManager } from '../util/LinkManager'; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 863829a51..681ff66e0 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -1,7 +1,6 @@ import { action, computed, observable, ObservableSet, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../fields/Doc'; -import { List } from '../../fields/List'; import { ScriptField } from '../../fields/ScriptField'; import { Cast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index f9249e7d5..302d4a464 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -565,7 +565,7 @@ export class CollectionStackedTimeline extends CollectionSubView Math.max(m, o.level), 0) + 2; - return ( + return this.clipDuration === 0 ? null : (
{ - e.stopPropagation(); - }} - onChange={(e: React.ChangeEvent) => { - this.zoom(Number(e.target.value)); - }} + onPointerDown={(e: React.PointerEvent) => e.stopPropagation()} + onChange={(e: React.ChangeEvent) => this.zoom(Number(e.target.value))} />
)} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6ae102a0c..b7a760c1e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1489,10 +1489,6 @@ export class DocumentViewInternal extends DocComponent (params[p.split(':')[0].trim()] = p.split(':')[1].trim())); - const result = CompileScript(this.rawText, { - editable: true, - transformer: DocumentIconContainer.getTransformer(), - params, - typecheck: false, - }); - Doc.SetInPlace(this.rootDoc, this.fieldKey, result.compiled ? new ScriptField(result, undefined, this.rawText) : new ScriptField(undefined, undefined, this.rawText), true); + const result = !this.rawText.trim() + ? ({ compiled: false, errors: undefined } as any) + : CompileScript(this.rawText, { + editable: true, + transformer: DocumentIconContainer.getTransformer(), + params, + typecheck: false, + }); + Doc.SetInPlace(this.rootDoc, this.fieldKey, result.compiled ? new ScriptField(result, undefined, this.rawText) : undefined, true); this.onError(result.compiled ? undefined : result.errors); return result.compiled; }; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 3169031b4..44314dca2 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -518,20 +518,13 @@ export namespace Doc { } export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { if (key.startsWith('_')) key = key.substring(1); - const hasProto = doc.proto instanceof Doc; + const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined; const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1; if (onDeleg || !hasProto || (!onProto && !defaultProto)) { doc[key] = value; } else doc.proto![key] = value; } - export async function SetOnPrototype(doc: Doc, key: string, value: Field) { - const proto = Object.getOwnPropertyNames(doc).indexOf('isPrototype') === -1 ? doc.proto : doc; - - if (proto) { - proto[key] = value; - } - } export function GetAllPrototypes(doc: Doc): Doc[] { const protos: Doc[] = []; let d: Opt = doc; -- cgit v1.2.3-70-g09d2 From e4b76f6c1dee63c49408c48d7b2bc98e62dc813a Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 5 Apr 2023 12:19:01 -0400 Subject: adjusted general context menu items to always appear last. cleaned up makeLink api, --- src/client/documents/Documents.ts | 32 +++++----- src/client/util/DragManager.ts | 1 - src/client/util/LinkFollower.ts | 2 - src/client/views/ContextMenu.tsx | 12 ++-- src/client/views/DocumentButtonBar.tsx | 4 +- src/client/views/MainView.tsx | 1 + src/client/views/SidebarAnnos.tsx | 2 +- .../views/collections/CollectionNoteTakingView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 28 ++++----- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 26 ++------ .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 70 +++++++++++++++------- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 31 +++++----- src/client/views/nodes/VideoBox.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/search/SearchBox.tsx | 2 +- 21 files changed, 117 insertions(+), 118 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9cb480c4a..5623ca218 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -470,7 +470,7 @@ export namespace Docs { DocumentType.AUDIO, { layout: { view: AudioBox, dataField: defaultDataKey }, - options: { _height: 100, forceReflow: true, nativeDimModifiable: true }, + options: { _height: 100, fitWidth: true, forceReflow: true, nativeDimModifiable: true }, }, ], [ @@ -934,13 +934,13 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey); } - export function LinkDocument(source: { doc: Doc; ctx?: Doc }, target: { doc: Doc; ctx?: Doc }, options: DocumentOptions = {}, id?: string) { + export function LinkDocument(source: Doc, target: Doc, options: DocumentOptions = {}, id?: string) { const linkDoc = InstanceFromProto( Prototypes.get(DocumentType.LINK), undefined, { - anchor1: source.doc, - anchor2: target.doc, + anchor1: source, + anchor2: target, ...options, }, id @@ -1294,16 +1294,14 @@ export namespace DocUtils { broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1)); return DocUtils.ActiveRecordings.map(audio => { const sourceDoc = getSourceDoc(); - const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor(true) || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline'); - link && (link.followLinkLocation = OpenWhere.addRight); - return link; + return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { linkDisplay: false, linkRelationship: 'recording annotation:linked recording', description: 'recording timeline' }); }); } - export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = '', description: string = '', id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) { - if (!linkRelationship) linkRelationship = target.doc.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link'; - const sv = DocumentManager.Instance.getDocumentView(source.doc); - if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return; + export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) { + if (!linkSettings.linkRelationship) linkSettings.linkRelationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link'; + const sv = DocumentManager.Instance.getDocumentView(source); + if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target) return; if (target.doc === Doc.UserDoc()) return undefined; const makeLink = action((linkDoc: Doc, showPopup?: number[]) => { @@ -1343,16 +1341,16 @@ export namespace DocUtils { target, { title: ComputedField.MakeFunction('generateLinkTitle(self)') as any, - 'anchor1-useLinkSmallAnchor': source.doc.useLinkSmallAnchor ? true : undefined, - 'anchor2-useLinkSmallAnchor': target.doc.useLinkSmallAnchor ? true : undefined, + 'anchor1-useLinkSmallAnchor': source.useLinkSmallAnchor ? true : undefined, + 'anchor2-useLinkSmallAnchor': target.useLinkSmallAnchor ? true : undefined, 'acl-Public': SharingPermissions.Augment, '_acl-Public': SharingPermissions.Augment, - linkDisplay: true, + linkDisplay: linkSettings.linkDisplay, _linkAutoMove: true, - linkRelationship, + linkRelationship: linkSettings.linkRelationship, _showCaption: 'description', _showTitle: 'linkRelationship', - description, + description: linkSettings.description, }, id ), @@ -1700,7 +1698,7 @@ export namespace DocUtils { _timecodeToShow: Cast(doc._timecodeToShow, 'number', null), }); Doc.AddDocToList(context, annotationField, pushpin); - const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, 'pushpin', ''); + const pushpinLink = DocUtils.MakeLink(pushpin, doc, { linkRelationship: 'pushpin' }, ''); doc._timecodeToShow = undefined; return pushpin; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index cc116fb46..7d2aa813f 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -168,7 +168,6 @@ export namespace DragManager { this.dropDocCreator = dropDocCreator; this.offset = [0, 0]; } - linkSourceDoc?: Doc; dropDocCreator: (annotationOn: Doc | undefined) => Doc; dropDocument?: Doc; offset: number[]; diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 785018990..df61ecece 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -9,8 +9,6 @@ import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; - -type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; /* * link doc: * - anchor1: doc diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 6a530e3ae..e4c3e864b 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -102,13 +102,11 @@ export class ContextMenu extends React.Component { } } @action - moveAfter(item: ContextMenuProps, after: ContextMenuProps) { - if (after && this.findByDescription(after.description)) { - const curInd = this._items.findIndex(i => i.description === item.description); - this._items.splice(curInd, 1); - const afterInd = this._items.findIndex(i => i.description === after.description); - this._items.splice(afterInd + 1, 0, item); - } + moveAfter(item: ContextMenuProps, after?: ContextMenuProps) { + const curInd = this._items.findIndex(i => i.description === item.description); + this._items.splice(curInd, 1); + const afterInd = after && this.findByDescription(after.description) ? this._items.findIndex(i => i.description === after.description) : this._items.length; + this._items.splice(afterInd, 0, item); } @action setDefaultItem(prefix: string, item: (name: string) => void) { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 9389fed01..3e1a0f265 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -416,7 +416,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const targetDoc = this.view0?.props.Document; return !targetDoc ? null : ( {`Open Context Menu`}
}> -
this.openContextMenu(e)}> +
@@ -569,7 +569,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const anchor = rootView.ComponentView?.getAnchor?.(false) ?? rootDoc; const trail = DocCast(anchor.presTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true); if (trail !== anchor.presTrail) { - DocUtils.MakeLink({ doc: anchor }, { doc: trail }, 'link trail'); + DocUtils.MakeLink(anchor, trail, { linkRelationship: 'link trail' }); anchor.presTrail = trail; } Doc.ActivePresentation = trail; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index befb0200d..b0888df68 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -270,6 +270,7 @@ export class MainView extends React.Component { fa.faLaptopCode, fa.faMale, fa.faCopy, + fa.faHome, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 48c0150e6..2d2b0f83e 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -74,7 +74,7 @@ export class SidebarAnnos extends React.Component { }); FormattedTextBox.SelectOnLoad = target[Id]; FormattedTextBox.DontSelectInitialText = true; - const link = DocUtils.MakeLink({ doc: anchor }, { doc: target }, 'inline comment:comment on'); + const link = DocUtils.MakeLink(anchor, target, { linkRelationship: 'inline comment:comment on' }); link && (link.linkDisplay = false); const taggedContent = this.docFilters() diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 121260680..cb5be990d 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -441,7 +441,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' }); this.props.addDocument?.(source); - de.complete.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceGetAnchor() }, 'doc annotation', ''); // TODODO this is where in text links get passed + de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { linkRelationship: 'doc annotation' }); // TODODO this is where in text links get passed e.stopPropagation(); } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); return false; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 64ec419ec..1e02fc9d4 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -3,14 +3,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CursorProperty } from 'csstype'; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; +import { DataSym, Doc, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; -import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType } from '../../documents/DocumentTypes'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -460,7 +460,7 @@ export class CollectionStackingView extends CollectionSubView { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!e.isPropagationStopped()) { - const subItems: ContextMenuProps[] = []; - subItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' }); - subItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' }); - subItems.push({ description: 'Clear All', event: () => (this.dataDoc.data = new List([])), icon: 'times' }); - ContextMenu.Instance.addItem({ description: 'Options...', subitems: subItems, icon: 'eye' }); + const cm = ContextMenu.Instance; + const options = cm.findByDescription('Options...'); + const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : []; + optionItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' }); + optionItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' }); + optionItems.push({ description: 'Clear All', event: () => (this.dataDoc[this.fieldKey ?? 'data'] = new List([])), icon: 'times' }); + !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' }); } }; @@ -735,14 +737,6 @@ export class CollectionStackingView extends CollectionSubView
)} - {/* {this.chromeHidden || !this.props.isSelected() ? (null) : - } */}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 5100d8d67..132ed6fb6 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -335,7 +335,7 @@ export function CollectionSubView(moreProps?: X) { const focusNode = iframe?.contentDocument?.getSelection()?.focusNode as any; if (focusNode) { const anchor = srcWeb?.ComponentView?.getAnchor?.(true); - anchor && DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor }); + anchor && DocUtils.MakeLink(htmlDoc, anchor, {}); } } } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 99b7549c0..75e76019e 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -359,7 +359,7 @@ export class TreeView extends React.Component { if (de.complete.linkDragData) { const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor(); const destDoc = this.doc; - DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, 'tree link', ''); + DocUtils.MakeLink(sourceDoc, destDoc, { linkRelationship: 'tree link' }); e.stopPropagation(); } const docDragData = de.complete.docDragData; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d39668a5d..fb0bd2a19 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -397,7 +397,7 @@ export class CollectionFreeFormView extends CollectionSubView (Doc.UserDoc().defaultTextLayout = undefined), icon: 'eye' }); appearanceItems.push({ description: `${this.fitContentsToBox ? 'Make Zoomable' : 'Scale to Window'}`, @@ -1700,7 +1704,7 @@ export class CollectionFreeFormView extends CollectionSubView TabDocView.PinDoc(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); - //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); + !Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' }); appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); this.props.Document._isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: () => this.transcribeStrokes(false), icon: 'font' }); @@ -1730,27 +1734,9 @@ export class CollectionFreeFormView extends CollectionSubView this.importDocument(e.clientX, e.clientY) }); !mores && ContextMenu.Instance.addItem({ description: 'More...', subitems: moreItems, icon: 'eye' }); }; - importDocument = (x: number, y: number) => { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.zip'; - input.onchange = _e => { - input.files && - Doc.importDocument(input.files[0]).then(doc => { - if (doc instanceof Doc) { - const [xx, yy] = this.getTransform().transformPoint(x, y); - (doc.x = xx), (doc.y = yy); - this.props.addDocument?.(doc); - } - }); - }; - input.click(); - }; - @undoBatch @action transcribeStrokes = (math: boolean) => { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 043fe0bcf..0b4f76fa1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -527,7 +527,7 @@ export class MarqueeView extends React.Component { + drop = (e: Event, de: DragManager.DropEvent) => { if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return; if (this.props.Document === Doc.ActiveDashboard) { alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.'); return; } const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData; - if (linkdrag) linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor(); - if (linkdrag?.linkSourceDoc) { - e.stopPropagation(); - if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) { - de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined); - } - if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) { - const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.props.Document; - de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y - 50]); + if (linkdrag) { + linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor(); + if (linkdrag.linkSourceDoc) { + e.stopPropagation(); + if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) { + de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined); + } + if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) { + const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc; + de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, undefined, [de.x, de.y - 50]); + } } } }; @@ -643,9 +645,9 @@ export class DocumentViewInternal extends DocComponent d.anchor1 === this.props.Document && d.linkRelationship === 'portal to:portal from'); if (!portalLink) { DocUtils.MakeLink( - { doc: this.props.Document }, - { doc: Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _isLightbox: true, _fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' }) }, - 'portal to:portal from' + this.props.Document, + Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _isLightbox: true, _fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' }), + { linkRelationship: 'portal to:portal from' } ); } this.Document.followLinkLocation = OpenWhere.lightbox; @@ -653,6 +655,24 @@ export class DocumentViewInternal extends DocComponent { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.zip'; + input.onchange = _e => { + if (input.files) { + const batch = UndoManager.StartBatch('importing'); + Doc.importDocument(input.files[0]).then(doc => { + if (doc instanceof Doc) { + this.props.addDocTab(doc, OpenWhere.addRight); + batch.end(); + } + }); + } + }; + input.click(); + }; + @action onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => { if (e && this.rootDoc._hideContextMenu && Doc.noviceMode) { @@ -704,9 +724,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); - LinkManager.Links(this.Document).length && - appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? 'Show' : 'Hide'} Link Button`, event: action(() => (this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton)), icon: 'eye' }); - !appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); + !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) { const existingOnClick = cm.findByDescription('OnClick...'); @@ -774,16 +792,21 @@ export class DocumentViewInternal extends DocComponent Utils.CopyText(Doc.globalServerPath(this.props.Document)), icon: 'fingerprint' }); } - moreItems.push({ description: 'Export collection', icon: 'download', event: async () => Doc.Zip(this.props.Document) }); - - (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && moreItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); } - if (this.props.removeDocument && !Doc.IsSystem(this.rootDoc) && Doc.ActiveDashboard !== this.props.Document) { + !more && moreItems.length && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'compass' }); + } + const constantItems: ContextMenuProps[] = []; + + if (!Doc.IsSystem(this.rootDoc)) { + constantItems.push({ description: 'Export as Zip file', icon: 'download', event: async () => Doc.Zip(this.props.Document) }); + constantItems.push({ description: 'Import Zipped file', icon: 'upload', event: ({ x, y }) => this.importDocument() }); + (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); + if (this.props.removeDocument && Doc.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) - moreItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); + constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); } - !more && moreItems.length && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'compass' }); + cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); } const help = cm.findByDescription('Help...'); const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; @@ -834,7 +857,8 @@ export class DocumentViewInternal extends DocComponent !isClick && batch.end(), () => { - this.toggleSidebar(); + onButton && this.toggleSidebar(); batch.end(); } ); @@ -440,17 +440,20 @@ export class PDFBox extends ViewBoxAnnotatableComponent (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform); specificContextMenu = (e: React.MouseEvent): void => { - const funcs: ContextMenuProps[] = []; - funcs.push({ - description: 'Toggle Sidebar Type', - event: () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform), - icon: 'expand-arrows-alt', - }); - funcs.push({ description: 'Copy path', event: () => this.pdfUrl && Utils.CopyText(Utils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' }); - funcs.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' }); - //funcs.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' }); + const cm = ContextMenu.Instance; + const options = cm.findByDescription('Options...'); + const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : []; + optionItems.push({ description: 'Toggle Sidebar Type', event: this.toggleSidebarType, icon: 'expand-arrows-alt' }); + !Doc.noviceMode && optionItems.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' }); + //optionItems.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" }); + !options && ContextMenu.Instance.addItem({ description: 'Options...', subitems: optionItems, icon: 'asterisk' }); + const help = cm.findByDescription('Help...'); + const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; + helpItems.push({ description: 'Copy path', event: () => this.pdfUrl && Utils.CopyText(Utils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' }); + !help && ContextMenu.Instance.addItem({ description: 'Help...', noexpand: true, subitems: helpItems, icon: 'asterisk' }); }; @computed get renderTitleBox() { @@ -523,8 +526,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent ) : (
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}> @@ -568,7 +569,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true)); }; @@ -1031,7 +1031,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || - DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, LinkManager.AutoKeywords)!); + DocUtils.MakeLink(this.props.Document, target, { linkRelationship: LinkManager.AutoKeywords })!); newAutoLinks.add(alink); const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }]; allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? [])); @@ -1273,7 +1273,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { makeLink = action((linkTo: Doc) => { const linkFrom = this.props.linkCreateAnchor?.(); if (linkFrom) { - const link = DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); + const link = DocUtils.MakeLink(linkFrom, linkTo, {}); link && this.props.linkCreated?.(link); } }); -- cgit v1.2.3-70-g09d2 From 38eb3a1b3f005b79a222f76b730e883b7e2b5253 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 5 Apr 2023 14:36:37 -0400 Subject: made pinning from topbar available for all docs. --- src/client/util/CurrentUserUtils.ts | 8 +++---- src/client/views/DocumentButtonBar.tsx | 25 +++++++++++----------- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 +++++++++----- src/client/views/nodes/trails/PresBox.tsx | 1 - src/client/views/nodes/trails/PresElementBox.tsx | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) (limited to 'src/client/views/DocumentButtonBar.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 753cd1cb7..9571209b0 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -682,9 +682,9 @@ export class CurrentUserUtils { CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map, CollectionViewType.Grid, CollectionViewType.NoteTaking]), title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}}, - { title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, toolType:"tab", funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, width: 20, scripts: { onClick: 'pinWithView(_readOnly_, altKey)'}}, - { title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, expertMode: false, toolType:"tab", ignoreClick: true, width: 20, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected - { title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, expertMode: false, toolType:"tab", ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}}, + { title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 20, scripts: { onClick: 'pinWithView(altKey)'}}, + { title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 20, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected + { title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}}, { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: 'toggleOverlay(_readOnly_)'}}, // Only when floating document is selected in freeform { title: "Z order", icon: "z", toolTip: "Bring Forward on Drag",btnType: ButtonType.ToggleButton, expertMode: false, toolType:CollectionViewType.Freeform, funcs: {}, scripts: { onClick: 'toggleRaiseOnDrag(_readOnly_)'}}, // Only when floating document is selected in freeform { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, @@ -693,7 +693,7 @@ export class CurrentUserUtils { { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: { linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(),expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available + { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected { title: "Schema", icon: "Schema", toolTip: "Schema functions", subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected ]; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 3e1a0f265..e83ea00cf 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -289,7 +289,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @observable subEndLink = ''; @computed get endLinkButton() { - const linkBtn = (pinDocLayout: boolean, pinDocContent: boolean, icon: IconProp) => { + const linkBtn = (pinLayout: boolean, pinContent: boolean, icon: IconProp) => { const tooltip = `Finish Link and Save ${this.subEndLink} data`; return !this.view0 ? null : ( {tooltip}
}> @@ -300,7 +300,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV key={icon.toString()} size="sm" icon={icon} - onPointerEnter={action(e => (this.subEndLink = (pinDocLayout ? 'Layout' : '') + (pinDocLayout && pinDocContent ? ' &' : '') + (pinDocContent ? ' Content' : '')))} + onPointerEnter={action(e => (this.subEndLink = (pinLayout ? 'Layout' : '') + (pinLayout && pinContent ? ' &' : '') + (pinContent ? ' Content' : '')))} onPointerLeave={action(e => (this.subEndLink = ''))} onClick={e => { const docs = this.props @@ -309,9 +309,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .map(dv => dv!.rootDoc); this.view0 && DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.props.Document, true, this.view0, { - pinDocLayout, - pinDocContent, - pinData: !pinDocContent ? {} : { poslayoutview: true, dataannos: true, dataview: true }, + pinDocLayout: pinLayout, + pinData: !pinContent ? {} : { poslayoutview: true, dataannos: true, dataview: pinContent }, } as PinProps); e.stopPropagation(); @@ -337,7 +336,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get pinButton() { const targetDoc = this.view0?.props.Document; - const pinBtn = (pinDocLayout: boolean, pinDocContent: boolean, icon: IconProp) => { + const pinBtn = (pinLayoutView: boolean, pinContentView: boolean, icon: IconProp) => { const tooltip = `Pin Document and Save ${this.subPin} to trail`; return !tooltip ? null : ( {tooltip}
}> @@ -351,10 +350,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV onPointerEnter={action( e => (this.subPin = - (pinDocLayout ? 'Layout' : '') + - (pinDocLayout && pinDocContent ? ' &' : '') + - (pinDocContent ? ' Content View' : '') + - (pinDocLayout && pinDocContent ? '(shift+alt)' : pinDocLayout ? '(shift)' : pinDocContent ? '(alt)' : '')) + (pinLayoutView ? 'Layout' : '') + + (pinLayoutView && pinContentView ? ' &' : '') + + (pinContentView ? ' Content View' : '') + + (pinLayoutView && pinContentView ? '(shift+alt)' : pinLayoutView ? '(shift)' : pinContentView ? '(alt)' : '')) )} onPointerLeave={action(e => (this.subPin = ''))} onClick={e => { @@ -364,8 +363,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .map(dv => dv!.rootDoc); TabDocView.PinDoc(docs, { pinAudioPlay: true, - pinDocLayout, - pinData: { dataview: true }, + pinDocLayout: pinLayoutView, + pinData: { dataview: pinContentView }, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null), currentFrame: Cast(docs.lastElement()?.currentFrame, 'number', null), }); @@ -385,7 +384,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinDocContent: e.altKey, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinData: {dataview: e.altKey}, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); e.stopPropagation(); }}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fb0bd2a19..22a2a429f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -2196,11 +2196,17 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) { if (readOnly) return selView[0].ComponentView?.getKeyFrameEditing?.() ? Colors.MEDIUM_BLUE : 'transparent'; runInAction(() => selView[0].ComponentView?.setKeyFrameEditing?.(!selView[0].ComponentView?.getKeyFrameEditing?.())); }); -ScriptingGlobals.add(function pinWithView(readOnly: boolean, pinDocContent: boolean) { - !readOnly && - SelectionManager.Views().forEach(view => - TabDocView.PinDoc(view.rootDoc, { currentFrame: Cast(view.rootDoc.currentFrame, 'number', null), pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) }) - ); +ScriptingGlobals.add(function pinWithView(pinContent: boolean) { + SelectionManager.Views().forEach(view => + view.props.pinToPres(view.rootDoc, { + currentFrame: Cast(view.rootDoc.currentFrame, 'number', null), + pinData: { + poslayoutview: pinContent, + dataview: pinContent, + }, + pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()), + }) + ); }); ScriptingGlobals.add(function bringToFront() { SelectionManager.Views().forEach(view => view.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView.bringToFront(view.rootDoc)); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0afb36214..bfaae8069 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -59,7 +59,6 @@ export interface PinProps { hidePresBox?: boolean; pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected) pinDocLayout?: boolean; // pin layout info (width/height/x/y) - pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text) pinAudioPlay?: boolean; // pin audio annotation pinData?: pinDataTypes; } diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 698a2817e..9a74b5dba 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -312,7 +312,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action updateCapturedViewContents = (presTargetDoc: Doc, activeItem: Doc) => { const target = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; - PresBox.pinDocView(activeItem, { pinDocContent: true, pinData: PresBox.pinDataTypes(target) }, target); + PresBox.pinDocView(activeItem, { pinData: PresBox.pinDataTypes(target) }, target); }; @computed get recordingIsInOverlay() { -- cgit v1.2.3-70-g09d2