From 13e301dea2f537b67b338cc6a98d3f3b5a8e1f36 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 18 Jun 2019 20:58:32 -0400 Subject: Fixed linter errors --- src/client/views/ContextMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index da374455e..eb1937683 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,8 +1,8 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; import { observable, action } from "mobx"; -import { observer } from "mobx-react" -import "./ContextMenu.scss" +import { observer } from "mobx-react"; +import "./ContextMenu.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSearch, faCircle } from '@fortawesome/free-solid-svg-icons'; -- cgit v1.2.3-70-g09d2 From 35e73f369a2145d8a042e0011a43e71763d57998 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 19 Jun 2019 15:02:48 -0400 Subject: added better search to context menu --- src/client/views/ContextMenu.scss | 23 ++++++++++ src/client/views/ContextMenu.tsx | 83 +++++++++++++++++++++++++----------- src/client/views/ContextMenuItem.tsx | 7 +-- src/client/views/MainView.tsx | 2 +- 4 files changed, 84 insertions(+), 31 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index e363c5158..a1a2b06f1 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -53,6 +53,29 @@ font-size: 20px; } +.contextMenu-group { + // width: 11vw; //10vw + height: 30px; //2vh + background: rgb(200, 200, 200); + display: flex; //comment out to allow search icon to be inline with search text + justify-content: left; + align-items: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + border-width: .11px; + border-style: none; + border-color: $intermediate-color; // rgb(187, 186, 186); + border-bottom-style: solid; + // padding: 10px 0px 10px 0px; + white-space: nowrap; + font-size: 20px; +} + .contextMenu-item:hover { transition: all 0.1s; background: $lighter-alt-accent; diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index eb1937683..1133f70a1 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; -import { observable, action } from "mobx"; +import { observable, action, computed } from "mobx"; import { observer } from "mobx-react"; import "./ContextMenu.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; @@ -17,11 +17,12 @@ export class ContextMenu extends React.Component { @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault(), icon: "smile" }]; @observable private _pageX: number = 0; @observable private _pageY: number = 0; - @observable private _display: string = "none"; + @observable private _display: boolean = false; @observable private _searchString: string = ""; // afaik displaymenu can be called before all the items are added to the menu, so can't determine in displayMenu what the height of the menu will be @observable private _yRelativeToTop: boolean = true; + private _searchRef = React.createRef(); private ref: React.RefObject; @@ -36,7 +37,6 @@ export class ContextMenu extends React.Component { @action clearItems() { this._items = []; - this._display = "none"; } @action @@ -62,34 +62,70 @@ export class ContextMenu extends React.Component { this._searchString = ""; - this._display = "flex"; - } - - intersects = (x: number, y: number): boolean => { - if (this.ref.current && this._display !== "none") { - let menuSize = { width: this.ref.current.getBoundingClientRect().width, height: this.ref.current.getBoundingClientRect().height }; + this._display = true; - let upperLeft = { x: this._pageX, y: this._yRelativeToTop ? this._pageY : window.innerHeight - (this._pageY + menuSize.height) }; - let bottomRight = { x: this._pageX + menuSize.width, y: this._yRelativeToTop ? this._pageY + menuSize.height : window.innerHeight - this._pageY }; - - if (x >= upperLeft.x && x <= bottomRight.x) { - if (y >= upperLeft.y && y <= bottomRight.y) { - return true; - } - } + if (this._searchRef.current) { + this._searchRef.current.focus(); } - return false; } @action closeMenu = () => { this.clearItems(); + this._display = false; } - render() { - let style = this._yRelativeToTop ? { left: this._pageX, top: this._pageY, display: this._display } : - { left: this._pageX, bottom: this._pageY, display: this._display }; + @computed get filteredItems() { + const searchString = this._searchString.toLowerCase().split(" "); + const matches = (descriptions: string[]): boolean => { + return searchString.every(s => descriptions.some(desc => desc.includes(s))); + }; + const createGroupHeader = (contents: any) => { + return ( +
+
{contents}
+
+ ); + }; + const createItem = (item: ContextMenuProps) => ; + const flattenItems = (items: ContextMenuProps[], groupFunc: (contents: any) => JSX.Element, getPath: () => string[]) => { + let eles: JSX.Element[] = []; + + for (const item of items) { + const description = item.description.toLowerCase(); + const path = [...getPath(), description]; + if ("subitems" in item) { + const children = flattenItems(item.subitems, contents => groupFunc(<>{item.description} -> {contents}), () => path); + if (children.length || matches(path)) { + eles.push(groupFunc(item.description)); + eles = eles.concat(children); + } + } else { + if (!matches(path)) { + continue; + } + eles.push(createItem(item)); + } + } + return eles; + }; + return flattenItems(this._items, createGroupHeader, () => []); + } + + @computed get menuItems() { + if (!this._searchString) { + return this._items.map(item => ); + } + return this.filteredItems; + } + + render() { + if (!this._display) { + return null; + } + let style = this._yRelativeToTop ? { left: this._pageX, top: this._pageY } : + { left: this._pageX, bottom: this._pageY }; return (
@@ -97,10 +133,9 @@ export class ContextMenu extends React.Component { - + - {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1). - map(prop => )} + {this.menuItems}
); } diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index dc0751049..88ebd95bc 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -21,9 +21,6 @@ export interface SubmenuProps { closeMenu?: () => void; } -export interface ContextMenuItemProps { - type: ContextMenuProps | SubmenuProps; -} export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @observer @@ -67,7 +64,6 @@ export class ContextMenuItem extends React.Component { return; } this.currentTimeout = setTimeout(action(() => this.overItem = false), ContextMenuItem.timeout); - } render() { @@ -84,8 +80,7 @@ export class ContextMenuItem extends React.Component { ); - } - else { + } else if ("subitems" in this.props) { let submenu = !this.overItem ? (null) :
{this._items.map(prop => )} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 7f979cd3b..e3d4ff8b5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -118,7 +118,7 @@ export class MainView extends React.Component { const targets = document.elementsFromPoint(e.x, e.y); if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { - ContextMenu.Instance.clearItems(); + ContextMenu.Instance.closeMenu(); } }), true); } -- cgit v1.2.3-70-g09d2 From 565b27cca8953a60067de367cae4c0a99beb3cab Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 19 Jun 2019 16:21:03 -0400 Subject: started adding selection to context menu --- src/client/views/ContextMenu.scss | 4 +++ src/client/views/ContextMenu.tsx | 58 +++++++++++++++++++++++------------- src/client/views/ContextMenuItem.tsx | 6 ++-- 3 files changed, 45 insertions(+), 23 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index a1a2b06f1..254163b53 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -53,6 +53,10 @@ font-size: 20px; } +.contextMenu-itemSelected { + background: rgb(136, 136, 136) +} + .contextMenu-group { // width: 11vw; //10vw height: 30px; //2vh diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 1133f70a1..33de57cfa 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,5 +1,5 @@ import React = require("react"); -import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; +import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from "./ContextMenuItem"; import { observable, action, computed } from "mobx"; import { observer } from "mobx-react"; import "./ContextMenu.scss"; @@ -21,6 +21,7 @@ export class ContextMenu extends React.Component { @observable private _searchString: string = ""; // afaik displaymenu can be called before all the items are added to the menu, so can't determine in displayMenu what the height of the menu will be @observable private _yRelativeToTop: boolean = true; + @observable selectedIndex = -1; private _searchRef = React.createRef(); @@ -75,49 +76,63 @@ export class ContextMenu extends React.Component { this._display = false; } - @computed get filteredItems() { + @computed get filteredItems(): (OriginalMenuProps | string[])[] { const searchString = this._searchString.toLowerCase().split(" "); const matches = (descriptions: string[]): boolean => { - return searchString.every(s => descriptions.some(desc => desc.includes(s))); + return searchString.every(s => descriptions.some(desc => desc.toLowerCase().includes(s))); }; - const createGroupHeader = (contents: any) => { - return ( -
-
{contents}
-
- ); - }; - const createItem = (item: ContextMenuProps) => ; - const flattenItems = (items: ContextMenuProps[], groupFunc: (contents: any) => JSX.Element, getPath: () => string[]) => { - let eles: JSX.Element[] = []; + const flattenItems = (items: ContextMenuProps[], groupFunc: (groupName: any) => string[]) => { + let eles: (OriginalMenuProps | string[])[] = []; + const leaves: OriginalMenuProps[] = []; for (const item of items) { - const description = item.description.toLowerCase(); - const path = [...getPath(), description]; + const description = item.description; + const path = groupFunc(description); if ("subitems" in item) { - const children = flattenItems(item.subitems, contents => groupFunc(<>{item.description} -> {contents}), () => path); + const children = flattenItems(item.subitems, name => [...groupFunc(description), name]); if (children.length || matches(path)) { - eles.push(groupFunc(item.description)); + eles.push(path); eles = eles.concat(children); } } else { if (!matches(path)) { continue; } - eles.push(createItem(item)); + leaves.push(item); } } + eles = [...leaves, ...eles]; + return eles; }; - return flattenItems(this._items, createGroupHeader, () => []); + return flattenItems(this._items, name => [name]); + } + + @computed get filteredViews() { + const createGroupHeader = (contents: any) => { + return ( +
+
{contents}
+
+ ); + }; + const createItem = (item: ContextMenuProps, selected: boolean) => ; + let itemIndex = 0; + return this.filteredItems.map(value => { + if (Array.isArray(value)) { + return createGroupHeader(value.join(" -> ")); + } else { + return createItem(value, ++itemIndex === this.selectedIndex); + } + }); } @computed get menuItems() { if (!this._searchString) { return this._items.map(item => ); } - return this.filteredItems; + return this.filteredViews; } render() { @@ -143,5 +158,8 @@ export class ContextMenu extends React.Component { @action onChange = (e: React.ChangeEvent) => { this._searchString = e.target.value; + if (this._searchString && this.selectedIndex === -1) { + this.selectedIndex = 0; + } } } \ No newline at end of file diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 88ebd95bc..ebcac7428 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -24,7 +24,7 @@ export interface SubmenuProps { export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @observer -export class ContextMenuItem extends React.Component { +export class ContextMenuItem extends React.Component { @observable private _items: Array = []; @observable private overItem = false; @@ -69,7 +69,7 @@ export class ContextMenuItem extends React.Component { render() { if ("event" in this.props) { return ( -
+
{this.props.icon ? ( @@ -86,7 +86,7 @@ export class ContextMenuItem extends React.Component { {this._items.map(prop => )}
; return ( -
+
{this.props.icon ? ( -- cgit v1.2.3-70-g09d2 From 05e50f27a15e8a02ffb27606c51026d1b85bc677 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 19 Jun 2019 17:36:52 -0400 Subject: Added basic keyboard controls to context menu --- src/client/views/ContextMenu.tsx | 40 ++++++++++++++++++++++++++++---- src/client/views/ContextMenuItem.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 41 +++++++++++++++++---------------- src/client/views/nodes/IconBox.tsx | 6 ++--- 4 files changed, 61 insertions(+), 30 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 33de57cfa..59a0de2a0 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -14,7 +14,7 @@ library.add(faCircle); export class ContextMenu extends React.Component { static Instance: ContextMenu; - @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault(), icon: "smile" }]; + @observable private _items: Array = []; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable private _display: boolean = false; @@ -109,6 +109,10 @@ export class ContextMenu extends React.Component { return flattenItems(this._items, name => [name]); } + @computed get flatItems(): OriginalMenuProps[] { + return this.filteredItems.filter(item => !Array.isArray(item)) as OriginalMenuProps[]; + } + @computed get filteredViews() { const createGroupHeader = (contents: any) => { return ( @@ -123,7 +127,7 @@ export class ContextMenu extends React.Component { if (Array.isArray(value)) { return createGroupHeader(value.join(" -> ")); } else { - return createItem(value, ++itemIndex === this.selectedIndex); + return createItem(value, itemIndex++ === this.selectedIndex); } }); } @@ -148,18 +152,44 @@ export class ContextMenu extends React.Component { - + {this.menuItems}
); } + @action + onKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "ArrowDown") { + if (this.selectedIndex < this.flatItems.length - 1) { + this.selectedIndex++; + } + e.preventDefault(); + } else if (e.key === "ArrowUp") { + if (this.selectedIndex > 0) { + this.selectedIndex--; + } + e.preventDefault(); + } else if (e.key === "Enter") { + const item = this.flatItems[this.selectedIndex]; + item.event(); + this.closeMenu(); + } + } + @action onChange = (e: React.ChangeEvent) => { this._searchString = e.target.value; - if (this._searchString && this.selectedIndex === -1) { - this.selectedIndex = 0; + if (!this._searchString) { + this.selectedIndex = -1; + } + else { + if (this.selectedIndex === -1) { + this.selectedIndex = 0; + } else { + this.selectedIndex = Math.min(this.flatItems.length - 1, this.selectedIndex); + } } } } \ No newline at end of file diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index ebcac7428..9bbb97d7e 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -9,7 +9,7 @@ library.add(faAngleRight); export interface OriginalMenuProps { description: string; - event: (e: React.MouseEvent) => void; + event: () => void; icon?: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } @@ -37,7 +37,7 @@ export class ContextMenuItem extends React.Component) => { if ("event" in this.props) { - this.props.event(e); + this.props.event(); this.props.closeMenu && this.props.closeMenu(); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f7836d947..2062fe1b5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faUnlock, faLock, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faShare, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; +import * as fa from '@fortawesome/free-solid-svg-icons'; import { action, computed, IReactionDisposer, reaction, trace, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; @@ -34,23 +34,24 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { RouteStore } from '../../../server/RouteStore'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? -library.add(faTrash); -library.add(faShare); -library.add(faExpandArrowsAlt); -library.add(faCompressArrowsAlt); -library.add(faLayerGroup); -library.add(faAlignCenter); -library.add(faCaretSquareRight); -library.add(faSquare); -library.add(faConciergeBell); -library.add(faFolder); -library.add(faMapPin); -library.add(faLink); -library.add(faFingerprint); -library.add(faCrosshairs); -library.add(faDesktop); -library.add(faUnlock); -library.add(faLock); +library.add(fa.faTrash); +library.add(fa.faShare); +library.add(fa.faExpandArrowsAlt); +library.add(fa.faCompressArrowsAlt); +library.add(fa.faLayerGroup); +library.add(fa.faExternalLinkAlt); +library.add(fa.faAlignCenter); +library.add(fa.faCaretSquareRight); +library.add(fa.faSquare); +library.add(fa.faConciergeBell); +library.add(fa.faFolder); +library.add(fa.faMapPin); +library.add(fa.faLink); +library.add(fa.faFingerprint); +library.add(fa.faCrosshairs); +library.add(fa.faDesktop); +library.add(fa.faUnlock); +library.add(fa.faLock); const linkSchema = createSchema({ title: "string", @@ -447,7 +448,7 @@ export class DocumentView extends DocComponent(Docu this.templates = this.templates; } - freezeNativeDimensions = (e: React.MouseEvent): void => { + freezeNativeDimensions = (): void => { let proto = Doc.GetProto(this.props.Document); if (proto.ignoreAspect === undefined && !proto.nativeWidth) { proto.nativeWidth = this.props.PanelWidth(); @@ -476,7 +477,7 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); - cm.addItem({ description: "Open...", subitems: subitems }); + cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: () => this.props.Document.lockedPosition = BoolCast(this.props.Document.lockedPosition) ? undefined : true, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 00021bc78..d6ab2a34a 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -37,14 +37,14 @@ export class IconBox extends React.Component { return ; } - setLabelField = (e: React.MouseEvent): void => { + setLabelField = (): void => { this.props.Document.hideLabel = !BoolCast(this.props.Document.hideLabel); } - setUseOwnTitleField = (e: React.MouseEvent): void => { + setUseOwnTitleField = (): void => { this.props.Document.useOwnTitle = !BoolCast(this.props.Document.useTargetTitle); } - specificContextMenu = (e: React.MouseEvent): void => { + specificContextMenu = (): void => { ContextMenu.Instance.addItem({ description: BoolCast(this.props.Document.hideLabel) ? "Show label with icon" : "Remove label from icon", event: this.setLabelField -- cgit v1.2.3-70-g09d2 From 01aee875e626c695fe208addaaa6f58aad387dd6 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 20 Jun 2019 10:02:08 -0400 Subject: Mostly keep context menu on screen --- src/client/views/ContextMenu.tsx | 74 +++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 24 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 59a0de2a0..fd2f970da 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -6,6 +6,7 @@ import "./ContextMenu.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSearch, faCircle } from '@fortawesome/free-solid-svg-icons'; +import Measure from "react-measure"; library.add(faSearch); library.add(faCircle); @@ -23,15 +24,12 @@ export class ContextMenu extends React.Component { @observable private _yRelativeToTop: boolean = true; @observable selectedIndex = -1; - private _searchRef = React.createRef(); - - private ref: React.RefObject; + @observable private _width: number = 0; + @observable private _height: number = 0; constructor(props: Readonly<{}>) { super(props); - this.ref = React.createRef(); - ContextMenu.Instance = this; } @@ -51,23 +49,42 @@ export class ContextMenu extends React.Component { return this._items; } + static readonly buffer = 20; + get pageX() { + const x = this._pageX; + if (x < 0) { + return 0; + } + const width = this._width; + if (x + width > window.innerWidth - ContextMenu.buffer) { + return window.innerWidth - ContextMenu.buffer - width; + } + return x; + } + + get pageY() { + const y = this._pageY; + if (y < 0) { + return 0; + } + const height = this._height; + if (y + height > window.innerHeight - ContextMenu.buffer) { + return window.innerHeight - ContextMenu.buffer - height; + } + return y; + } + @action displayMenu(x: number, y: number) { //maxX and maxY will change if the UI/font size changes, but will work for any amount //of items added to the menu - let maxX = window.innerWidth - 150; - let maxY = window.innerHeight - ((this._items.length + 1/*for search box*/) * 34 + 30); - this._pageX = x > maxX ? maxX : x; - this._pageY = y > maxY ? maxY : y; + this._pageX = x; + this._pageY = y; this._searchString = ""; this._display = true; - - if (this._searchRef.current) { - this._searchRef.current.focus(); - } } @action @@ -143,19 +160,28 @@ export class ContextMenu extends React.Component { if (!this._display) { return null; } - let style = this._yRelativeToTop ? { left: this._pageX, top: this._pageY } : - { left: this._pageX, bottom: this._pageY }; + let style = this._yRelativeToTop ? { left: this.pageX, top: this.pageY } : + { left: this.pageX, bottom: this.pageY }; + + console.log(this._pageX); + console.log(this.pageX); + console.log(); return ( -
- - - - - - - {this.menuItems} -
+ { this._width = r.offset.width; this._height = r.offset.height; })}> + {({ measureRef }) => ( +
+ + + + + + + {this.menuItems} +
+ ) + } +
); } -- cgit v1.2.3-70-g09d2 From af8e5cf1bfbfa2d57b4fd89c72306a71d8cabe1d Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 20 Jun 2019 11:32:54 -0400 Subject: Fixed context menu search --- src/client/views/ContextMenu.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index fd2f970da..69692dbb8 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -167,17 +167,22 @@ export class ContextMenu extends React.Component { console.log(this.pageX); console.log(); + const contents = ( + <> + + + + + + + {this.menuItems} + + ); return ( { this._width = r.offset.width; this._height = r.offset.height; })}> {({ measureRef }) => (
- - - - - - - {this.menuItems} + {contents}
) } -- cgit v1.2.3-70-g09d2 From d98ab1aae1510f1cf1c0f4a32553a7971a660b66 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 1 Jul 2019 12:13:47 -0400 Subject: Couple of undo things --- src/client/util/UndoManager.ts | 1 + src/client/views/ContextMenu.tsx | 4 ---- src/client/views/DocumentDecorations.tsx | 5 ++++- src/client/views/MainView.tsx | 4 +++- src/client/views/collections/CollectionTreeView.tsx | 2 ++ 5 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index c0ed015bd..156390fd3 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -94,6 +94,7 @@ export namespace UndoManager { } export function PrintBatches(): void { + console.log("Open Undo Batches:"); GetOpenBatches().forEach(batch => console.log(batch.batchName)); } diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 69692dbb8..c163c56a0 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -163,10 +163,6 @@ export class ContextMenu extends React.Component { let style = this._yRelativeToTop ? { left: this.pageX, top: this.pageY } : { left: this.pageX, bottom: this.pageY }; - console.log(this._pageX); - console.log(this.pageX); - console.log(); - const contents = ( <> diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 61e9d209a..946a152e2 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -12,7 +12,7 @@ import { Docs } from "../documents/Documents"; import { DocumentManager } from "../util/DocumentManager"; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; -import { undoBatch } from "../util/UndoManager"; +import { undoBatch, UndoManager } from "../util/UndoManager"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { CollectionView } from "./collections/CollectionView"; import './DocumentDecorations.scss'; @@ -50,6 +50,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _downX = 0; private _downY = 0; private _iconDoc?: Doc = undefined; + private _resizeUndo?: UndoManager.Batch; @observable private _minimizedX = 0; @observable private _minimizedY = 0; @observable private _title: string = ""; @@ -347,6 +348,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this._isPointerDown = true; this._resizing = e.currentTarget.id; this.Interacting = true; + this._resizeUndo = UndoManager.StartBatch("DocDecs resize"); document.removeEventListener("pointermove", this.onPointerMove); document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -548,6 +550,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (e.button === 0) { e.preventDefault(); this._isPointerDown = false; + this._resizeUndo && this._resizeUndo.end(); document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index fb88c284f..d28e3b837 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faArrowDown, faArrowUp, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons'; +import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faArrowDown, faArrowUp, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut, faExclamation } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; @@ -108,6 +108,7 @@ export class MainView extends React.Component { } library.add(faFont); + library.add(faExclamation); library.add(faImage); library.add(faFilePdf); library.add(faObjectGroup); @@ -310,6 +311,7 @@ export class MainView extends React.Component {
)} +
  • diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 927aa363f..f5dd76b71 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -251,6 +251,8 @@ class TreeView extends React.Component { e.stopPropagation(); } } + + @undoBatch treeDrop = (e: Event, de: DragManager.DropEvent) => { let x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); let rect = this._header!.current!.getBoundingClientRect(); -- cgit v1.2.3-70-g09d2