From 51f9da2bb6529c102c300a1ceb4ccd23065a76fc Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 29 Aug 2020 17:58:32 -0400 Subject: split out TabDocView from CollectionDockingView (where it had been called DockedFrameRenderer) --- src/client/views/collections/TabDocView.scss | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/client/views/collections/TabDocView.scss (limited to 'src/client/views/collections/TabDocView.scss') diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss new file mode 100644 index 000000000..9a4b5cbd1 --- /dev/null +++ b/src/client/views/collections/TabDocView.scss @@ -0,0 +1,20 @@ + +.miniMap { + position: absolute; + overflow: hidden; + right: 10; + bottom: 10; + border: solid 1px; + box-shadow: black 0.4vw 0.4vw 0.8vw; + + .miniOverlay { + width: 100%; + height: 100%; + position: absolute; + + .miniThumb { + background: #25252525; + position: absolute; + } + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From a4555fb8d5cd64482dd8431aad03878cb173f688 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 1 Sep 2020 03:58:41 -0400 Subject: fixed following link to a doc that is in a hidden tab to show that tab. fixed linear view to hit content bounds accurately. fixed editing of text in tabs somewhat. fixed place ment of link anchor boxes for topMost views. --- src/client/util/DocumentManager.ts | 2 ++ src/client/views/GlobalKeyHandler.ts | 1 - src/client/views/MainView.scss | 1 + src/client/views/MainView.tsx | 4 ++-- .../views/collections/CollectionLinearView.scss | 2 ++ .../views/collections/CollectionLinearView.tsx | 12 +++--------- src/client/views/collections/TabDocView.scss | 4 +++- src/client/views/collections/TabDocView.tsx | 22 +++++++++++++++------- src/client/views/linking/LinkMenu.scss | 2 -- src/client/views/linking/LinkMenu.tsx | 4 ++-- src/client/views/nodes/DocumentLinksButton.tsx | 7 +++++-- src/client/views/nodes/DocumentView.tsx | 5 +++-- src/client/views/search/SearchBox.tsx | 6 +++--- 13 files changed, 41 insertions(+), 31 deletions(-) (limited to 'src/client/views/collections/TabDocView.scss') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index f085f615c..9e55c5a44 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -160,6 +160,8 @@ export class DocumentManager { docView.props.Document.hidden = !docView.props.Document.hidden; } else { + const contView = docContext && getFirstDocView(docContext, originatingDoc); + contView && contView.topMost && contView.select(false); docView.select(false); docView.props.Document.hidden && (docView.props.Document.hidden = undefined); docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 076be3ad6..a52eb649d 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -196,7 +196,6 @@ export class KeyManager { break; case "f": SearchBox.Instance._searchFullDB = "My Stuff"; - SearchBox.Instance.newsearchstring = ""; SearchBox.Instance.enter(undefined); break; case "o": diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 93cc47215..9ca8f348d 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -31,6 +31,7 @@ bottom: 10px; left: calc(100% + 5px); z-index: 1; + pointer-events: none; } .mainView-snapLines { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 4eccbaeb1..01df10aa0 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -370,6 +370,7 @@ export class MainView extends React.Component { @action selectMenu = (button: Doc) => { const title = StrCast(Doc.GetProto(button).title); + const closed = !this._flyoutWidth; this.closeFlyout(); if (this._panelContent !== title || !this._flyoutWidth) { switch (this._panelContent = title) { @@ -378,12 +379,11 @@ export class MainView extends React.Component { break; case "Catalog": SearchBox.Instance._searchFullDB = "My Stuff"; - SearchBox.Instance.newsearchstring = ""; SearchBox.Instance.enter(undefined); break; default: this._sidebarContent.proto = button.target as any; - this.expandFlyout(); + closed && this.expandFlyout(); button._backgroundColor = "lightgrey"; button.color = "black"; this._lastButton = button; diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss index f5c4299a9..ca72b98a5 100644 --- a/src/client/views/collections/CollectionLinearView.scss +++ b/src/client/views/collections/CollectionLinearView.scss @@ -4,10 +4,12 @@ .collectionLinearView-outer { overflow: visible; height: 100%; + pointer-events: none; .collectionLinearView { display: flex; height: 100%; + align-items: center; >span { background: $dark-color; diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index 866d7245a..9eaa02bf8 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -17,6 +17,7 @@ import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { LinkDescriptionPopup } from '../nodes/LinkDescriptionPopup'; import { Tooltip } from '@material-ui/core'; +import { all } from 'bluebird'; type LinearDocument = makeInterface<[typeof documentSchema,]>; @@ -113,12 +114,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { const backgroundColor = StrCast(this.props.Document.backgroundColor, "black"); const color = StrCast(this.props.Document.color, "white"); - const menuOpener = ; @@ -140,6 +136,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { const scalable = pair.layout.onClick || pair.layout.onDragStart; return
@@ -194,9 +191,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { - {/* */} - : null}
; diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss index 9a4b5cbd1..fdb801e03 100644 --- a/src/client/views/collections/TabDocView.scss +++ b/src/client/views/collections/TabDocView.scss @@ -1,4 +1,6 @@ - +input.lm_title:focus { + max-width: max-content !important; +} .miniMap { position: absolute; overflow: hidden; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 31e3fbed6..3cb57f086 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -54,21 +54,29 @@ export class TabDocView extends React.Component { tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true); tab.DashDoc = doc; + const titleEle = tab.titleElement[0]; CollectionDockingView.Instance.tabMap.add(tab); - tab.titleElement[0].onchange = (e: any) => { - tab.titleElement[0].size = e.currentTarget.value.length + 1; + titleEle.onchange = (e: any) => { + titleEle.size = e.currentTarget.value.length + 3; Doc.GetProto(doc).title = e.currentTarget.value; }; - tab.titleElement[0].size = StrCast(doc.title).length + 1; - tab.titleElement[0].value = doc.title; - tab.titleElement[0].style["max-width"] = "100px"; + titleEle.size = StrCast(doc.title).length + 3; + titleEle.value = doc.title; + titleEle.style["max-width"] = "100px"; const gearSpan = document.createElement("span"); gearSpan.className = "collectionDockingView-gear"; gearSpan.style.position = "relative"; gearSpan.style.paddingLeft = "0px"; gearSpan.style.paddingRight = "12px"; const stack = tab.contentItem.parent; - tab.element[0].onclick = (e: any) => e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view!, false); + tab.element[0].onclick = (e: any) => { + if (e.target.className !== "lm_close_tab" && this.view) { + SelectionManager.SelectDoc(this.view, false); + if (Date.now() - titleEle.lastClick < 1000) titleEle.select(); + titleEle.lastClick = Date.now(); + (document.activeElement !== titleEle) && titleEle.focus(); + } + }; // shifts the focus to this tab when another tab is dragged over it tab.element[0].onmouseenter = (e: MouseEvent) => { if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) { @@ -83,7 +91,7 @@ export class TabDocView extends React.Component { }, returnFalse, emptyFunction); }; - tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.props.Document === doc), + tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.topMost && v.props.Document === doc), (selected) => { selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch"); } diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss index 4dc25031d..0e03b46db 100644 --- a/src/client/views/linking/LinkMenu.scss +++ b/src/client/views/linking/LinkMenu.scss @@ -4,8 +4,6 @@ width: auto; height: auto; position: absolute; - top: 0; - left: 0; z-index: 999; .linkMenu-list { diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 31d08edae..f5a1ae8e7 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -91,9 +91,9 @@ export class LinkMenu extends React.Component { render() { const sourceDoc = this.props.docView.props.Document; const groups: Map = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc); - return
+ return
{!this._editingLink ? -
+
{this.renderAllGroups(groups)}
:
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 318f7b7e9..1d346894c 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -25,7 +25,7 @@ export const Flyout = higflyout.default; interface DocumentLinksButtonProps { View: DocumentView; - Offset?: number[]; + Offset?: (number | undefined)[]; AlwaysOn?: boolean; InMenu?: boolean; StartLink?: boolean; @@ -242,7 +242,10 @@ export class DocumentLinksButton extends React.Component; - const linkButton =
+ const linkButton =
(Docu if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { - SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey); + this.select(e.ctrlKey || e.shiftKey); + //SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey); } preventDefault = false; } @@ -855,7 +856,7 @@ export class DocumentView extends DocComponent(Docu return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; } childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); - @computed.struct get linkOffset() { return [-15, 0]; } + @computed.struct get linkOffset() { return this.topMost ? [0, undefined, undefined, 10] : [-15, undefined, undefined, undefined]; } @computed get contents() { const pos = this.props.relative ? "relative " : "absolute"; TraceMobx(); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index d08cc7f5b..c04b1da10 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -102,7 +102,7 @@ export class SearchBox extends ViewBoxBaseComponent { if (!e || e.key === "Enter") { @@ -378,7 +378,7 @@ export class SearchBox extends ViewBoxBaseComponent(docsForFilter) : undefined; collectionView.props.Document._docFilters = docsForFilter?.length && docFilters?.length ? new List(docFilters) : undefined; } - }) + }); render() { const myDashboards = DocListCast(CurrentUserUtils.MyDashboards.data); -- cgit v1.2.3-70-g09d2 From 5b4a692b0c87a58e17c0ae799f935e22a326b856 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 11 Sep 2020 23:42:55 -0400 Subject: moved minimap button to bottom-right of tab panes --- src/client/views/collections/CollectionMenu.tsx | 12 --- src/client/views/collections/TabDocView.scss | 18 +++++ src/client/views/collections/TabDocView.tsx | 100 ++++++++++++------------ 3 files changed, 70 insertions(+), 60 deletions(-) (limited to 'src/client/views/collections/TabDocView.scss') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 5c0a3777f..a58edc604 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -561,11 +561,6 @@ export class CollectionFreeFormViewChrome extends React.Component { - this.document.hideMinimap = !this.document.hideMinimap; - } private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""]; private _width = ["1", "5", "10", "100"]; @@ -849,13 +844,6 @@ export class CollectionFreeFormViewChrome extends React.Component - {this.props.docView.props.renderDepth !== 0 || this.isText || this.props.isDoc ? (null) : - Toggle Mini Map
} placement="bottom"> -
- -
- - } {!this.isText && !this.props.isDoc ? Back Frame
} placement="bottom">
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss index fdb801e03..b808f3ae4 100644 --- a/src/client/views/collections/TabDocView.scss +++ b/src/client/views/collections/TabDocView.scss @@ -1,6 +1,7 @@ input.lm_title:focus { max-width: max-content !important; } +.miniMap-hidden, .miniMap { position: absolute; overflow: hidden; @@ -8,6 +9,9 @@ input.lm_title:focus { bottom: 10; border: solid 1px; box-shadow: black 0.4vw 0.4vw 0.8vw; + width: 100%; + height: 100%; + transition: all 0.5s; .miniOverlay { width: 100%; @@ -19,4 +23,18 @@ input.lm_title:focus { position: absolute; } } +} +.miniMap-hidden { + position: absolute; + bottom: 0; + right: 0; + width: 40px; + height: 40px; + background: transparent; + transform: translate(20px, 20px) rotate(45deg); + border-radius: 30px; + > svg { + margin-top: 3px; + transform: translate(0px, 7px); + } } \ No newline at end of file diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index aa1852250..f4fda67cd 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -27,6 +27,7 @@ import { CollectionDockingViewMenu } from './CollectionDockingViewMenu'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionViewType } from './CollectionView'; import React = require("react"); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; const _global = (window /* browser */ || global /* node */) as any; interface TabDocViewProps { @@ -282,54 +283,57 @@ export class TabDocView extends React.Component { } renderMiniMap() { - return
- -
-
+ return <> + {this._document?.hideMinimap ? (null) : +
+ +
+
+
+
} +
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} > +
-
; + ; } focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.(); setView = action((view: DocumentView) => this._view = view); @@ -363,7 +367,7 @@ export class TabDocView extends React.Component { searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} /> - {this._document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)} + {this._document!._viewType !== CollectionViewType.Freeform ? (null) : this.renderMiniMap()} ; } -- cgit v1.2.3-70-g09d2 From d6094e43606763ef9499f3e1fd42ac619e493135 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 13 Sep 2020 22:30:02 -0400 Subject: updated cursor icons. --- src/client/views/DocumentButtonBar.tsx | 4 ++-- src/client/views/DocumentDecorations.scss | 2 +- src/client/views/collections/CollectionMenu.tsx | 2 +- src/client/views/collections/TabDocView.scss | 7 ++++--- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/client/views/collections/TabDocView.scss') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 0183b0b05..e8b18fca4 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -226,7 +226,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get menuButton() { const targetDoc = this.view0?.props.Document; return !targetDoc ? (null) :
{`Open Context Menu`}
}> -
this.openContextMenu(e)}> +
this.openContextMenu(e)}>
; } @@ -235,7 +235,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get moreButton() { const targetDoc = this.view0?.props.Document; return !targetDoc ? (null) :
{`${CurrentUserUtils.propertiesWidth > 0 ? "Close" : "Open"} Properties Panel`}
}> -
+
CurrentUserUtils.propertiesWidth = CurrentUserUtils.propertiesWidth > 0 ? 0 : 250)}>
; diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 8fcc63d71..f9b8c1940 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -85,7 +85,7 @@ $linkGap : 3px; top: 12; position: relative; pointer-events: all; - cursor: grab; + cursor: nwse-resize; .borderRadiusTooltip { width: 10px; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index ddb33727b..8342c5b12 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -430,7 +430,7 @@ export class CollectionViewBaseChrome extends React.Component{"Tap or Drag to create an alias"}
} placement="top"> -
; diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss index b808f3ae4..c0a46543d 100644 --- a/src/client/views/collections/TabDocView.scss +++ b/src/client/views/collections/TabDocView.scss @@ -28,11 +28,12 @@ input.lm_title:focus { position: absolute; bottom: 0; right: 0; - width: 40px; - height: 40px; - background: transparent; + width: 45px; + height: 45px; + background: white; transform: translate(20px, 20px) rotate(45deg); border-radius: 30px; + padding: 2px; > svg { margin-top: 3px; transform: translate(0px, 7px); -- cgit v1.2.3-70-g09d2 From 6a988e009eb1a43145c14f0d55af405318fd144f Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 15 Sep 2020 14:39:41 -0400 Subject: fixed tabs to activate when following.a link to a contained item. fixed deactivating tabs to not shrink immediately so you can click the close button. --- src/client/util/DocumentManager.ts | 2 -- src/client/views/collections/TabDocView.scss | 12 +++++++++-- src/client/views/collections/TabDocView.tsx | 10 ++++++---- src/fields/Doc.ts | 30 +++++++++++++++------------- 4 files changed, 32 insertions(+), 22 deletions(-) (limited to 'src/client/views/collections/TabDocView.scss') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 903760c58..c3d78a028 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -162,8 +162,6 @@ export class DocumentManager { docView.props.Document.hidden = !docView.props.Document.hidden; } else { - const contView = docContext && getFirstDocView(docContext, originatingDoc); - contView && contView.topMost && contView.select(false); // bcz: change this to a function prop: popTab() that will make sure the tab for the document is topmost; docView.select(false); docView.props.Document.hidden && (docView.props.Document.hidden = undefined); docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss index c0a46543d..5dfb9366a 100644 --- a/src/client/views/collections/TabDocView.scss +++ b/src/client/views/collections/TabDocView.scss @@ -1,5 +1,13 @@ -input.lm_title:focus { - max-width: max-content !important; +input.lm_title:focus, +input.lm_title +{ + max-width: unset !important; + transition-delay: unset; + width: 100%; +} +input.lm_title { + transition-delay: 0.35s; + width: 100px; } .miniMap-hidden, .miniMap { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 62f6d50fc..76ca82c63 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -61,7 +61,6 @@ export class TabDocView extends React.Component { const titleEle = tab.titleElement[0]; titleEle.size = StrCast(doc.title).length + 3; titleEle.value = doc.title; - titleEle.style["max-width"] = "100px"; titleEle.onchange = (e: any) => { titleEle.size = e.currentTarget.value.length + 3; Doc.GetProto(doc).title = e.currentTarget.value; @@ -81,7 +80,7 @@ export class TabDocView extends React.Component { }; // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected - tab.element[0].onclick = (e: any) => { + titleEle.onpointerdown = (e: any) => { if (e.target.className !== "lm_close_tab" && this.view) { SelectionManager.SelectDoc(this.view, false); if (Date.now() - titleEle.lastClick < 1000) titleEle.select(); @@ -197,7 +196,7 @@ export class TabDocView extends React.Component { this._isActive = this.props.glContainer.tab.isActive; (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged(); !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. - this._isActive && this.view && SelectionManager.SelectDoc(this.view, false); + // this._isActive && this.view && SelectionManager.SelectDoc(this.view, false); } } @@ -339,7 +338,10 @@ export class TabDocView extends React.Component { ; } - focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.(); + focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => { + this.tab.header.parent.setActiveContentItem(this.tab.contentItem) + afterFocus?.(); + } setView = action((view: DocumentView) => this._view = view); active = () => this._isActive; @computed get docView() { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index ff45dda80..a8950f1ee 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -688,24 +688,26 @@ export namespace Doc { if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc)) && templateLayoutDoc.PARAMS === StrCast(targetDoc.PARAMS)) { expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params } else { - _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true); templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype - setTimeout(action(() => { - if (!targetDoc[expandedLayoutFieldKey]) { - const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); - // the template's arguments are stored in params which is derefenced to find - // the actual field key where the parameterized template data is stored. - newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params. it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances - newLayoutDoc.rootDocument = targetDoc; - targetDoc[expandedLayoutFieldKey] = newLayoutDoc; - const dataDoc = Doc.GetProto(targetDoc); - newLayoutDoc.resolvedDataDoc = dataDoc; - if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List) { + if (!targetDoc[expandedLayoutFieldKey]) { + const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); + // the template's arguments are stored in params which is derefenced to find + // the actual field key where the parameterized template data is stored. + newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params. it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances + newLayoutDoc.rootDocument = targetDoc; + const dataDoc = Doc.GetProto(targetDoc); + newLayoutDoc.resolvedDataDoc = dataDoc; + + _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true); + setTimeout(() => { + if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List && (templateLayoutDoc[templateField] as any).length) { dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc }); } + targetDoc[expandedLayoutFieldKey] = newLayoutDoc; + _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey + args); - } - }), 0); + }); + } } } return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplateLayout is pending. -- cgit v1.2.3-70-g09d2 From 77c23b7513a5c7609d8833a750988c32b35a43e4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 16 Sep 2020 22:39:51 -0400 Subject: a bunch of changes to dragging/selection of ui buttons to turn off context menus, remove close buttons on doc decoartions, fix the title region fo tabs, --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 78 ++++++++-------------- src/client/util/DragManager.ts | 10 +-- src/client/util/DropConverter.ts | 11 ++- src/client/views/DocumentDecorations.tsx | 32 +++++---- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/MainView.scss | 26 ++++++++ src/client/views/MainView.tsx | 6 +- .../views/collections/CollectionDockingView.tsx | 6 +- src/client/views/collections/CollectionMenu.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 12 ++-- src/client/views/collections/TabDocView.scss | 5 ++ src/client/views/collections/TabDocView.tsx | 9 +-- src/client/views/nodes/DocumentView.tsx | 5 ++ src/client/views/nodes/FilterBox.tsx | 6 +- src/client/views/nodes/FontIconBox.tsx | 10 +-- 16 files changed, 127 insertions(+), 94 deletions(-) (limited to 'src/client/views/collections/TabDocView.scss') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 04c7a0f59..36834d2df 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -92,6 +92,7 @@ export interface DocumentOptions { y?: number; z?: number; author?: string; + _hideContextMenu?: boolean; // whether the context menu can be shown dropAction?: dropActionType; childDropAction?: dropActionType; targetDropAction?: dropActionType; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 3258e1877..2e7fd1b21 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -65,8 +65,7 @@ export class CurrentUserUtils { [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]); doc["template-mobile-button"] = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "mobile button", icon: "mobile" + dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile" }); } @@ -81,8 +80,7 @@ export class CurrentUserUtils { slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); doc["template-button-slides"] = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" + dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card" }); } @@ -128,8 +126,7 @@ export class CurrentUserUtils { doc["template-button-link"] = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "link view", icon: "window-maximize", system: true + dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true }); } @@ -160,8 +157,7 @@ export class CurrentUserUtils { doc["template-button-switch"] = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(box) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "data switch", icon: "toggle-on", system: true + dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true }); } @@ -210,28 +206,7 @@ export class CurrentUserUtils { doc["template-button-detail"] = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(detailView) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "window-maximize", system: true - }); - } - if (doc["template-button-simple"] === undefined) { - const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create; - - const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)"); - const carousel = CarouselDocument([], { - title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10, - onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F", system: true - }); - - const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 }; - const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: "12px" }; - const detailView = Docs.Create.StackingDocument([carousel], { ...shared, ...detailViewOpts, system: true }); - detailView.isTemplateDoc = makeTemplate(detailView); - - doc["template-button-simple"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'), - dragFactory: new PrefetchProxy(detailView) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "simple view", icon: "window-maximize", system: true + dragFactory: new PrefetchProxy(detailView) as any as Doc, title: "detail view", icon: "window-maximize", system: true }); } @@ -239,7 +214,6 @@ export class CurrentUserUtils { doc["template-button-slides"] as Doc, doc["template-mobile-button"] as Doc, doc["template-button-detail"] as Doc, - doc["template-button-simple"] as Doc, doc["template-button-link"] as Doc, //doc["template-button-switch"] as Doc] ]; @@ -247,7 +221,7 @@ export class CurrentUserUtils { doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", hidden: ComputedField.MakeFunction("self.userDoc.noviceMode") as any, - userDoc: doc, + userDoc: doc, _stayInCollection: true, _hideContextMenu: true, _autoHeight: true, _width: 500, _columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true })); @@ -302,8 +276,7 @@ export class CurrentUserUtils { { title: "Note Layouts", _height: 75, system: true })); } else { const curNoteTypes = Cast(doc["template-notes"], Doc, null); - const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, - doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc]; + const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc];//, doc["template-note-Todo"] as any as Doc]; DocListCastAsync(curNoteTypes.data).then(async curNotes => { await Promise.all(curNotes!); requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype)); @@ -484,7 +457,7 @@ export class CurrentUserUtils { { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc }, { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc }, { toolTip: "Tap to create a document previewer in a new pane, drag for a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyDocHolder as Doc }, - { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc, noviceMode: true }, + { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc }, { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, ]; @@ -503,7 +476,7 @@ export class CurrentUserUtils { } const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, ischecked, activeInkPen, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({ - _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _stayInCollection: true, + _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, icon, title, toolTip, @@ -514,7 +487,9 @@ export class CurrentUserUtils { ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined, activeInkPen, backgroundColor, - removeDropProperties: new List(["dropAction"]), + _hideContextMenu: true, + removeDropProperties: new List(["dropAction", "_stayInCollection"]), + _stayInCollection: true, dragFactory, clickFactory, userDoc: noviceMode ? undefined as any : doc, @@ -524,7 +499,7 @@ export class CurrentUserUtils { if (dragCreatorSet === undefined) { doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, + title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _autoHeight: true, _width: 500, _columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true })); @@ -567,12 +542,13 @@ export class CurrentUserUtils { Docs.Create.FontIconDocument({ icon, iconShape: "square", + _stayInCollection: true, + _hideContextMenu: true, title, target, _backgroundColor: "black", dropAction: "alias", - removeDropProperties: new List(["dropAction"]), - childDropAction: "same", + removeDropProperties: new List(["dropAction", "_stayInCollection"]), _width: 60, _height: 60, watchedDocuments, @@ -584,6 +560,7 @@ export class CurrentUserUtils { doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, { title: "menuItemPanel", + childDropAction: "alias", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _backgroundColor: "black", _gridGap: 0, @@ -741,14 +718,14 @@ export class CurrentUserUtils { // setup a color picker if (doc.myColorPicker === undefined) { const color = Docs.Create.ColorDocument({ - title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]), system: true + title: "color picker", _width: 300, dropAction: "alias", _hideContextMenu: true, _stayInCollection: true, forceActive: true, removeDropProperties: new List(["dropAction", "_stayInCollection", "_hideContextMenu", "forceActive"]), system: true }); doc.myColorPicker = new PrefetchProxy(color); } if (doc.myTools === undefined) { const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], { - title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true + title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true, _stayInCollection: true, _hideContextMenu: true, })) as any as Doc; doc.myTools = toolsStack; @@ -810,7 +787,7 @@ export class CurrentUserUtils { if (doc.myFilter === undefined) { doc.myFilter = new PrefetchProxy(Docs.Create.FilterDocument({ title: "FilterDoc", _height: 500, - treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", + treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "none", treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true })); @@ -861,16 +838,16 @@ export class CurrentUserUtils { })) as any as Doc static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ - ...opts, dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true + ...opts, dropAction: "alias", removeDropProperties: new List(["dropAction", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true })) as any as Doc /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window static setupDockedButtons(doc: Doc) { if (doc["dockedBtn-undo"] === undefined) { - doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true }); + doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true }); } if (doc["dockedBtn-redo"] === undefined) { - doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true }); + doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true }); } if (doc.dockedBtns === undefined) { doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]); @@ -902,12 +879,15 @@ export class CurrentUserUtils { // Import sidebar is where shared documents are contained static setupImportSidebar(doc: Doc) { if (doc.myImportDocs === undefined) { - doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, lockedPosition: true, _chromeStatus: "disabled", system: true })); + doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { + title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, + childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, lockedPosition: true, _chromeStatus: "disabled", system: true + })); } if (doc.myImportPanel === undefined) { const uploads = Cast(doc.myImportDocs, Doc, null); - const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _backgroundColor: "black", title: "Import", icon: "upload", system: true }); - doc.myImportPanel = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "My ImportPanel", _yMargin: 20, ignoreClick: true, lockedPosition: true, system: true })); + const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _backgroundColor: "black", _stayInCollection: true, _hideContextMenu: true, title: "Import", icon: "upload", system: true }); + doc.myImportPanel = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "My ImportPanel", _yMargin: 20, ignoreClick: true, _stayInCollection: true, _hideContextMenu: true, lockedPosition: true, system: true })); } } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 7b64d1ccc..91ffab41d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -13,7 +13,7 @@ import * as globalCssVariables from "../views/globalCssVariables.scss"; import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; -export type dropActionType = "alias" | "copy" | "move" | "same" | undefined; // undefined = move +export type dropActionType = "alias" | "copy" | "move" | "same" | "none" | undefined; // undefined = move export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, @@ -129,9 +129,10 @@ export namespace DragManager { treeViewDoc?: Doc; dontHideOnDrop?: boolean; offset: number[]; - dropAction: dropActionType; + userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys + defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action + dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move' removeDropProperties?: string[]; - userDropAction: dropActionType; moveDocument?: MoveFunction; removeDocument?: RemoveFunction; isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts @@ -320,6 +321,7 @@ export namespace DragManager { export let docsBeingDragged: Doc[] = []; export let CanEmbed = false; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { + if (dragData.dropAction === "none") return; const batch = UndoManager.StartBatch("dragging"); eles = eles.filter(e => e); CanEmbed = false; @@ -418,7 +420,7 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { - dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined; + dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction; } if (e?.shiftKey && dragData.draggedDocuments.length === 1) { dragData.dropAction = dragData.userDropAction || "same"; diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 1bbd46938..32817eefd 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -2,12 +2,13 @@ import { DragManager } from "./DragManager"; import { Doc, DocListCast, Opt } from "../../fields/Doc"; import { DocumentType } from "../documents/DocumentTypes"; import { ObjectField } from "../../fields/ObjectField"; -import { StrCast } from "../../fields/Types"; +import { StrCast, Cast } from "../../fields/Types"; import { Docs } from "../documents/Documents"; import { ScriptField, ComputedField } from "../../fields/ScriptField"; import { RichTextField } from "../../fields/RichTextField"; import { ImageField } from "../../fields/URLField"; import { Scripting } from "./Scripting"; +import { listSpec } from "../../fields/Schema"; // // converts 'doc' into a template that can be used to render other documents. @@ -54,7 +55,13 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { let dbox = doc; // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes("FontIconBox")) { - //dbox = Doc.MakeAlias(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon + if (data.removeDropProperties || dbox.removeDropProperties) { + //dbox = Doc.MakeAlias(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon + dbox = Doc.MakeAlias(dbox); + const dragProps = Cast(dbox.removeDropProperties, listSpec("string"), []); + const remProps = (data.removeDropProperties || []).concat(Array.from(dragProps)); + remProps.map(prop => dbox[prop] = undefined); + } } else if (!doc.onDragStart && !doc.isButtonBar) { const layoutDoc = doc;// doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; if (layoutDoc.type !== DocumentType.FONTICON) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 41be364fd..e4e27bec7 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -13,7 +13,7 @@ import { GetEffectiveAcl } from '../../fields/util'; import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick, returnVal } from "../../Utils"; import { DocUtils, Docs } from "../documents/Documents"; import { DocumentType } from '../documents/DocumentTypes'; -import { DragManager } from "../util/DragManager"; +import { DragManager, dropActionType } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from "../util/UndoManager"; @@ -137,8 +137,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0); dragData.offset = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top); - dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument; + dragData.moveDocument = dragDocView.props.moveDocument; dragData.isSelectionMove = true; + dragData.dropAction = dragDocView.props.Document.dropAction as dropActionType; this.Interacting = true; this._hidden = true; DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(dv => dv.ContentDiv!), dragData, e.x, e.y, { @@ -578,20 +579,25 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return (null); } const canDelete = SelectionManager.SelectedDocuments().some(docView => { - const collectionAcl = GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]); - return collectionAcl === AclAdmin || collectionAcl === AclEdit; + const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit; + return !docView.props.Document._stayInCollection && (collectionAcl === AclAdmin || collectionAcl === AclEdit); }); - const minimal = bounds.r - bounds.x < 100 ? true : false; - const closeIcon = canDelete ? ( + const canOpen = SelectionManager.SelectedDocuments().some(docView => !docView.props.Document._stayInCollection); + const closeIcon = !canDelete ? (null) : ( Close
} placement="top">
-
) : (null); +
); + + const openIcon = !canOpen ? (null) : Open In a New Pane
} placement="top">
{ e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}> + {SelectionManager.SelectedDocuments().length === 1 ? : "..."} +
+ ; const titleArea = this._edtingTitle ? this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} /> : -
+
{`${this.selectionTitle}`}
; @@ -627,14 +633,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> }}> {closeIcon} {Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) : titleArea} - {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK || minimal || Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) : + {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK || Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) : {`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}
} placement="top">
} - Open In a New Pane
} placement="top">
{ e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}> - {SelectionManager.SelectedDocuments().length === 1 ? : "..."} -
+ {openIcon}
e.preventDefault()} />
e.preventDefault()} />
e.preventDefault()} /> @@ -654,9 +658,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onPointerDown={useRotation ? this.onRotateDown : this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}>{useRotation && "⟲"}
-
+ {seldoc?.Document.type === DocumentType.FONTICON ? (null) :
-
+
} }
); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 83c02b09b..b231b2171 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -113,7 +113,7 @@ export class KeyManager { } const selected = SelectionManager.SelectedDocuments().slice(); - UndoManager.RunInBatch(() => selected.map(dv => dv.props.removeDocument?.(dv.props.Document)), "delete"); + UndoManager.RunInBatch(() => selected.map(dv => !dv.props.Document._stayInCollection && dv.props.removeDocument?.(dv.props.Document)), "delete"); SelectionManager.DeselectAll(); break; case "arrowleft": UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(-1, 0)), "nudge left"); break; diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index aebb28859..5bab43a3b 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -382,4 +382,30 @@ display: block; width: 500px; height: 1000px; +} + +.lm_drag_tab { + padding: 0; + width: 15px !important; + height: 15px !important; + position: relative !important; + display: inline-flex !important; + align-items: center; + top: 0 !important; + right: unset !important; + left: 0 !important; +} +.lm_close_tab { + padding: 0; + width: 15px !important; + height: 15px !important; + position: relative !important; + display: inline-flex !important; + align-items: center; + top: 0 !important; + right: unset !important; + left: 0 !important; +} +.lm_tab, .lm_tab_active { + display: flex !important; } \ No newline at end of file diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 82261fcf0..c2290dd09 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -445,11 +445,7 @@ export class MainView extends React.Component { remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc); - addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => { - const ret = flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc); - ret && (doc._stayInCollection = undefined); - return ret; - }, true) + addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 306b9187e..4685d2ffc 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -152,7 +152,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns instance._goldenLayout.root.addChild(newContentItem); - } else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row + } else if (instance._goldenLayout.root.contentItems.length === 1 && instance._goldenLayout.root.contentItems[0].contentItems.length === 1 && + instance._goldenLayout.root.contentItems[0].contentItems[0].contentItems.length === 0) { + instance._goldenLayout.root.contentItems[0].contentItems[0].addChild(docContentConfig); + } + else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row switch (pullSide) { default: case "right": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 9e67faed5..0f8a5df0d 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -417,7 +417,7 @@ export class CollectionViewBaseChrome extends React.Component(schemaCtor: (doc: Doc) => T, moreProps?: if (docDragData) { let added = false; const dropAction = docDragData.dropAction || docDragData.userDropAction; - if ((!dropAction || dropAction === "move") && docDragData.moveDocument) { + const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]); + const someMoved = !docDragData.userDropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag)); + if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop); + if ((!dropAction || dropAction === "move" || someMoved) && docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); - const res = addedDocs.length ? this.addDocument(addedDocs) : true; if (movedDocs.length) { const canAdd = this.props.Document._viewType === CollectionViewType.Pile || de.embedKey || !this.props.isAnnotationOverlay || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document); added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse); - } else added = res; + } else { + ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); + added = addedDocs.length ? this.addDocument(addedDocs) : true; + } added && e.stopPropagation(); return added; } else { diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss index 5dfb9366a..edf556c9f 100644 --- a/src/client/views/collections/TabDocView.scss +++ b/src/client/views/collections/TabDocView.scss @@ -4,10 +4,15 @@ input.lm_title max-width: unset !important; transition-delay: unset; width: 100%; + cursor: text; } input.lm_title { transition-delay: 0.35s; width: 100px; + cursor: pointer; +} +.tabDocView-drag { + margin: auto; } .miniMap-hidden, .miniMap { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index bd5032536..f89285923 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -91,16 +91,13 @@ export class TabDocView extends React.Component { //attach the selection doc buttons menu to the drag handle const stack = tab.contentItem.parent; - const dragHdl = document.createElement("span"); - dragHdl.className = "collectionDockingView-gear"; - dragHdl.style.position = "relative"; - dragHdl.style.paddingLeft = "0px"; - dragHdl.style.paddingRight = "12px"; + const dragHdl = document.createElement("div"); + dragHdl.className = "lm_drag_tab"; tab._disposers.buttonDisposer = reaction(() => this.view, view => view && [ReactDOM.render( [view]} Stack={stack} />, dragHdl), tab._disposers.buttonDisposer?.()], { fireImmediately: true }); tab.reactComponents = [dragHdl]; - tab.element.append(dragHdl); + tab.closeElement.before(dragHdl); // highlight the tab when the tab document is brushed in any part of the UI tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index def9d8554..5ca57a193 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -752,6 +752,11 @@ export class DocumentView extends DocComponent(Docu @action onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => { + if (e && this.rootDoc._hideContextMenu && Doc.UserDoc().noviceMode) { + e.preventDefault(); + e.stopPropagation(); + !this.isSelected(true) && SelectionManager.SelectDoc(this, false); + } // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 if (e) { if (e.button === 0 && !e.ctrlKey || e.isDefaultPrevented()) { diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index eab365445..7a010532f 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -94,13 +94,13 @@ export class FilterBox extends ViewBoxBaseComponent; if (facetHeader === "text" || rtfields / allCollectionDocs.length > 0.1) { - newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true }); + newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true }); Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox newFacet._textBoxPadding = 4; const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`; newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" }); } else if (facetHeader !== "tags" && nonNumbers / facetValues.length < .1) { - newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true }); + newFacet = Docs.Create.SliderDocument({ title: facetHeader, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", treeViewOpen: true }); const newFacetField = Doc.LayoutFieldKey(newFacet); const ranged = Doc.readDocRangeFilter(targetDoc, facetHeader); Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox @@ -118,7 +118,7 @@ export class FilterBox extends ViewBoxBaseComponent( useAsPrototype = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); }; specificContextMenu = (): void => { - const cm = ContextMenu.Instance; - cm.addItem({ description: "Show Template", event: this.showTemplate, icon: "tag" }); - !Doc.UserDoc().noviceMode && cm.addItem({ description: "Use as Render Template", event: this.dragAsTemplate, icon: "tag" }); - !Doc.UserDoc().noviceMode && cm.addItem({ description: "Use as Prototype", event: this.useAsPrototype, icon: "tag" }); + if (!Doc.UserDoc().noviceMode) { + const cm = ContextMenu.Instance; + cm.addItem({ description: "Show Template", event: this.showTemplate, icon: "tag" }); + cm.addItem({ description: "Use as Render Template", event: this.dragAsTemplate, icon: "tag" }); + cm.addItem({ description: "Use as Prototype", event: this.useAsPrototype, icon: "tag" }); + } } componentWillUnmount() { -- cgit v1.2.3-70-g09d2