Ensure the double-click event is not ignored in the browser tree.
parent
a410b15e30
commit
98f6b1ff12
|
@ -0,0 +1,18 @@
|
|||
import { useSingleAndDoubleClick } from '../../../custom_hooks';
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CustomPropTypes from '../../../../js/custom_prop_types';
|
||||
|
||||
export default function DoubleClickHandler({onSingleClick, onDoubleClick, children}){
|
||||
const onClick = useSingleAndDoubleClick(onSingleClick, onDoubleClick) ;
|
||||
return(
|
||||
<div onClick={(e)=>onClick(e)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
DoubleClickHandler.propTypes = {
|
||||
onSingleClick: PropTypes.func,
|
||||
onDoubleClick: PropTypes.func,
|
||||
children: CustomPropTypes.children
|
||||
};
|
|
@ -12,9 +12,9 @@ import * as React from 'react';
|
|||
import { ClasslistComposite } from 'aspen-decorations';
|
||||
import { Directory, FileEntry, IItemRendererProps, ItemType, RenamePromptHandle, FileType, FileOrDir} from 'react-aspen';
|
||||
import {IFileTreeXTriggerEvents, FileTreeXEvent } from '../types';
|
||||
import _ from 'lodash';
|
||||
import { Notificar } from 'notificar';
|
||||
|
||||
import _ from 'lodash';
|
||||
import DoubleClickHandler from './DoubleClickHandler';
|
||||
interface IItemRendererXProps {
|
||||
/**
|
||||
* In this implementation, decoration are null when item is `PromptHandle`
|
||||
|
@ -58,7 +58,6 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||
|
||||
public render() {
|
||||
const { item, itemType, decorations } = this.props;
|
||||
|
||||
const isRenamePrompt = itemType === ItemType.RenamePrompt;
|
||||
const isNewPrompt = itemType === ItemType.NewDirectoryPrompt || itemType === ItemType.NewFilePrompt;
|
||||
const isDirExpanded = itemType === ItemType.Directory
|
||||
|
@ -93,7 +92,6 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||
data-depth={item.depth}
|
||||
onContextMenu={this.handleContextMenu}
|
||||
onClick={this.handleClick}
|
||||
onDoubleClick={this.handleDoubleClick}
|
||||
onDragStart={this.handleDragStartItem}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
|
@ -107,8 +105,8 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||
: null
|
||||
}
|
||||
|
||||
<span className='file-label'>
|
||||
{
|
||||
<DoubleClickHandler onDoubleClick={this.handleDoubleClick} onSingleClick={this.handleClick} >
|
||||
<span className='file-label'>{
|
||||
item._metadata?.data?.icon ?
|
||||
<i className={cn('file-icon', item._metadata?.data?.icon ? item._metadata.data.icon : fileOrDir)} /> : null
|
||||
}
|
||||
|
@ -121,7 +119,8 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||
{tag.text}
|
||||
</div>
|
||||
))}
|
||||
</span>
|
||||
</span>
|
||||
</DoubleClickHandler>
|
||||
</div>);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,32 @@ export function useInterval(callback, delay) {
|
|||
}, [delay]);
|
||||
}
|
||||
|
||||
/* React hook for handling double and single click events */
|
||||
export function useSingleAndDoubleClick(handleSingleClick, handleDoubleClick, delay = 250) {
|
||||
const clickCountRef = useRef(0);
|
||||
const timerRef = useRef(null);
|
||||
|
||||
const handleClick = (e) => {
|
||||
// Handle the logic here, no need to pass the event
|
||||
clickCountRef.current += 1;
|
||||
|
||||
// Clear any previous timeout to ensure the double-click logic is triggered only once
|
||||
clearTimeout(timerRef.current);
|
||||
|
||||
// Set the timeout to handle click logic after the delay
|
||||
timerRef.current = setTimeout(() => {
|
||||
if (clickCountRef.current === 1) handleSingleClick(e);
|
||||
else if (clickCountRef.current === 2) handleDoubleClick(e);
|
||||
|
||||
// Reset the click count and props after handling
|
||||
clickCountRef.current = 0;
|
||||
}, delay);
|
||||
};
|
||||
|
||||
return handleClick;
|
||||
}
|
||||
|
||||
|
||||
export function useDelayedCaller(callback) {
|
||||
let timer;
|
||||
useEffect(() => {
|
||||
|
|
|
@ -19,7 +19,7 @@ class TreeAreaLocators:
|
|||
@staticmethod
|
||||
def server_group_node_exp_status(server_group_name):
|
||||
return "//i[@class='directory-toggle open']/following-sibling::" \
|
||||
"span//span[starts-with(text(),'%s')]" % server_group_name
|
||||
"div//span[starts-with(text(),'%s')]" % server_group_name
|
||||
|
||||
# Server Node
|
||||
@staticmethod
|
||||
|
@ -31,7 +31,7 @@ class TreeAreaLocators:
|
|||
@staticmethod
|
||||
def server_node_exp_status(server_name):
|
||||
return "//i[@class='directory-toggle open']/following-sibling::" \
|
||||
"span//span[starts-with(text(),'%s')]" % server_name
|
||||
"div//span[starts-with(text(),'%s')]" % server_name
|
||||
|
||||
# Server Connection
|
||||
@staticmethod
|
||||
|
@ -43,36 +43,37 @@ class TreeAreaLocators:
|
|||
# Databases Node
|
||||
@staticmethod
|
||||
def databases_node(server_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//span[text()='Databases']" % server_name
|
||||
|
||||
@staticmethod
|
||||
def databases_node_exp_status(server_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
"following-sibling::div//span[span[text()='Databases']]/" \
|
||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//div[span[span[text()='Databases']]]/" \
|
||||
"preceding-sibling::i[@class='directory-toggle open']" \
|
||||
% server_name
|
||||
|
||||
# Database Node
|
||||
@staticmethod
|
||||
def database_node(database_name):
|
||||
return "//div[@data-depth='4']/span/span[text()='%s']" % database_name
|
||||
return "//div[@data-depth='4']/div/span/span[text()='%s']" \
|
||||
% database_name
|
||||
|
||||
@staticmethod
|
||||
def database_node_exp_status(database_name):
|
||||
return "//i[@class='directory-toggle open']/following-sibling::" \
|
||||
"span//span[text()='%s']" % database_name
|
||||
"div//span[text()='%s']" % database_name
|
||||
|
||||
# Schemas Node
|
||||
@staticmethod
|
||||
def schemas_node(database_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//span[text()='Schemas']" % database_name
|
||||
|
||||
@staticmethod
|
||||
def schemas_node_exp_status(database_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
"following-sibling::div//span[span[text()='Schemas']]/" \
|
||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//div[span[span[text()='Schemas']]]/" \
|
||||
"preceding-sibling::i[@class='directory-toggle open']" \
|
||||
% database_name
|
||||
|
||||
|
@ -85,28 +86,28 @@ class TreeAreaLocators:
|
|||
@staticmethod
|
||||
def schema_node_exp_status(schema_name):
|
||||
return "//i[@class='directory-toggle open']/" \
|
||||
"following-sibling::span//span[text()='%s']" % schema_name
|
||||
"following-sibling::div//span[text()='%s']" % schema_name
|
||||
|
||||
# Tables Node
|
||||
@staticmethod
|
||||
def tables_node(schema_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
return "//div[divdiv[[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//span[text()='Tables']" % schema_name
|
||||
|
||||
@staticmethod
|
||||
def tables_node_exp_status(schema_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
"following-sibling::div//span[span[text()='Tables']]/" \
|
||||
"following-sibling::div//div[span[span[text()='Tables']]]/" \
|
||||
"preceding-sibling::i[@class='directory-toggle open']"\
|
||||
% schema_name
|
||||
|
||||
# Schema child
|
||||
child_node_exp_status = \
|
||||
"//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
"following-sibling::div//span[span[text()='%s']]/" \
|
||||
"//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//div[span[span[text()='%s']]]/" \
|
||||
"preceding-sibling::i[@class='directory-toggle open']"
|
||||
|
||||
child_node = "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
child_node = "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//span[text()='%s']"
|
||||
|
||||
@staticmethod
|
||||
|
@ -120,8 +121,8 @@ class TreeAreaLocators:
|
|||
|
||||
@staticmethod
|
||||
def schema_child_node_expand_icon_xpath(schema_name, child_node_name):
|
||||
return "//div[div[span[span[starts-with(text(),'%s')]]]]/" \
|
||||
"following-sibling::div//span[text()='%s']/../" \
|
||||
return "//div[div[div[span[span[starts-with(text(),'%s')]]]]]/" \
|
||||
"following-sibling::div//div[span[text()='%s']]/../" \
|
||||
"preceding-sibling::i" % (schema_name, child_node_name)
|
||||
|
||||
# Database child
|
||||
|
@ -147,17 +148,17 @@ class TreeAreaLocators:
|
|||
# Table Node
|
||||
@staticmethod
|
||||
def table_node(table_name):
|
||||
return "//div[@data-depth='8']/span/span[text()='%s']" % table_name
|
||||
return "//div[@data-depth='8']/div/span/span[text()='%s']" % table_name
|
||||
|
||||
# Function Node
|
||||
@staticmethod
|
||||
def function_node(table_name):
|
||||
return "//div[@data-depth='8']/span/span[text()='%s']" % table_name
|
||||
return "//div[@data-depth='8']/div/span/span[text()='%s']" % table_name
|
||||
|
||||
# Role Node
|
||||
@staticmethod
|
||||
def role_node(role_name):
|
||||
return "//div[@data-depth='4']/span/span[text()='%s']" % role_name
|
||||
return "//div[@data-depth='4']/div/span/span[text()='%s']" % role_name
|
||||
|
||||
# Context element option
|
||||
@staticmethod
|
||||
|
|
Loading…
Reference in New Issue