Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the onClick event to handle both mouseUp and mouseDown #4982

Open
4 of 8 tasks
matteobruni opened this issue May 15, 2023 · 3 comments
Open
4 of 8 tasks

Change the onClick event to handle both mouseUp and mouseDown #4982

matteobruni opened this issue May 15, 2023 · 3 comments
Assignees
Labels
enhancement New feature or request feature_request good first issue Good for newcomers Hacktoberfest help wanted Extra attention is needed pinned Pinned issues plugin A feature that could become a plugin sweep Assigns Sweep to an issue or pull request. up-for-grabs

Comments

@matteobruni
Copy link
Collaborator

matteobruni commented May 15, 2023

The onClick event can be a bit confusing, since some events are triggered on mousedown and some are triggered on mouseup.

This is an opportunity to improve the options, using two different triggers for those events, or a flag in the onClick options or something like that.

I think this is something that belongs to v3.0, it depends on how breaking it is. If new events are the best way to achieve it, the onClick can't exist anymore, since there's a conflict.

Version 3.0 is ignoring more deprecated values, the onClick there will be changed anyway, it depends if this can be supported in 2.x as well.

Checklist
  • engine/src/Options/Classes/Interactivity/Events/Events.ts ✅ Commit b73f4c9
  • engine/src/Core/Utils/EventListeners.ts ✅ Commit 81fefd0
  • interactions/external/bubble/src/Bubbler.ts ✅ Commit 5c56c9e
  • engine/src/Options/Classes/Interactivity/Events/DivEvent.ts ✅ Commit e270ba3
  • engine/src/Options/Interfaces/Interactivity/Events/IEvents.ts
  • engine/src/Options/Interfaces/Interactivity/Events/IClickEvent.ts
  • engine/src/Options/Classes/Interactivity/Events/ClickEvent.ts
  • markdown/Options/Interactivity/Events.md
@matteobruni matteobruni self-assigned this May 15, 2023
@matteobruni matteobruni added enhancement New feature or request help wanted Extra attention is needed good first issue Good for newcomers up-for-grabs plugin A feature that could become a plugin pinned Pinned issues Core and removed triage Core labels May 15, 2023
@matteobruni matteobruni pinned this issue May 15, 2023
@ARSHIL1804
Copy link

I would like to work on this

@matteobruni
Copy link
Collaborator Author

I would like to work on this

Sure, I haven't started yet on this

@matteobruni matteobruni added the sweep Assigns Sweep to an issue or pull request. label Sep 18, 2023
@sweep-ai
Copy link

sweep-ai bot commented Sep 18, 2023

Sweeping

50%

⚡ Sweep Free Trial: I'm creating this ticket using GPT-4. You have 4 GPT-4 tickets left for the month and 2 for the day. For more GPT-4 tickets, visit our payment portal.

Actions (click)

  • ↻ Restart Sweep

Step 1: 🔎 Searching

I found the following snippets in your repository. I will now analyze these snippets and come up with a plan.

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

import { executeOnSingleOrMultiple, isBoolean } from "../../../../Utils/Utils";
import { ClickEvent } from "./ClickEvent";
import { DivEvent } from "./DivEvent";
import { HoverEvent } from "./HoverEvent";
import type { IEvents } from "../../../Interfaces/Interactivity/Events/IEvents";
import type { IOptionLoader } from "../../../Interfaces/IOptionLoader";
import type { RecursivePartial } from "../../../../Types/RecursivePartial";
import { ResizeEvent } from "./ResizeEvent";
import type { SingleOrMultiple } from "../../../../Types/SingleOrMultiple";
/**
* [[include:Options/Interactivity/Events.md]]
*/
export class Events implements IEvents, IOptionLoader<IEvents> {
onClick;
onDiv: SingleOrMultiple<DivEvent>;
onHover;
resize;
constructor() {
this.onClick = new ClickEvent();
this.onDiv = new DivEvent();
this.onHover = new HoverEvent();
this.resize = new ResizeEvent();
}
/**
* @deprecated this property is obsolete, please use the new onClick
* @returns the onClick event
*/
get onclick(): ClickEvent {
return this.onClick;
}
/**
* @deprecated this property is obsolete, please use the new onClick
* @param value -
*/
set onclick(value: ClickEvent) {
this.onClick = value;
}
/**
* @deprecated this property is obsolete, please use the new onDiv
* @returns the onDiv event
*/
get ondiv(): SingleOrMultiple<DivEvent> {
return this.onDiv;
}
/**
* @deprecated this property is obsolete, please use the new onDiv
* @param value -
*/
set ondiv(value: SingleOrMultiple<DivEvent>) {
this.onDiv = value;
}
/**
* @deprecated this property is obsolete, please use the new onHover
* @returns the onHover event
*/
get onhover(): HoverEvent {
return this.onHover;
}
/**
* @deprecated this property is obsolete, please use the new onHover
* @param value -
*/
set onhover(value: HoverEvent) {
this.onHover = value;
}
load(data?: RecursivePartial<IEvents>): void {
if (!data) {
return;
}
this.onClick.load(data.onClick ?? data.onclick);
const onDiv = data.onDiv ?? data.ondiv;
if (onDiv !== undefined) {
this.onDiv = executeOnSingleOrMultiple(onDiv, (t) => {
const tmp = new DivEvent();
tmp.load(t);
return tmp;
});
}
this.onHover.load(data.onHover ?? data.onhover);
if (isBoolean(data.resize)) {
this.resize.enable = data.resize;
} else {
this.resize.load(data.resize);
}
}

this._handlers = {
mouseDown: (): void => this._mouseDown(),
mouseLeave: (): void => this._mouseTouchFinish(),
mouseMove: (e): void => this._mouseTouchMove(e),
mouseUp: (e): void => this._mouseTouchClick(e),
touchStart: (e): void => this._touchStart(e),
touchMove: (e): void => this._mouseTouchMove(e),
touchEnd: (e): void => this._touchEnd(e),
touchCancel: (e: Event): void => this._touchEnd(e),
touchEndClick: (e): void => this._touchEndClick(e),
visibilityChange: (): void => this._handleVisibilityChange(),
themeChange: (e): void => this._handleThemeChange(e),
oldThemeChange: (e): void => this._handleThemeChange(e),
resize: (): void => {
this._handleWindowResize();
},
};
}
/**
* Adding all listeners
*/
addListeners(): void {
this._manageListeners(true);
}
/**
* Removing all listeners
*/
removeListeners(): void {
this._manageListeners(false);
}
/**
* Mouse/Touch click/tap event implementation
* @param e - the click event arguments
*/
private readonly _doMouseTouchClick: (e: Event) => void = (e) => {
const container = this.container,
options = container.actualOptions;
if (this._canPush) {
const mouseInteractivity = container.interactivity.mouse,
mousePos = mouseInteractivity.position;
if (!mousePos) {
return;
}
mouseInteractivity.clickPosition = { ...mousePos };
mouseInteractivity.clickTime = new Date().getTime();
const onClick = options.interactivity.events.onClick;
executeOnSingleOrMultiple(onClick.mode, (mode) => this.container.handleClickMode(mode));
}
if (e.type === "touchend") {
setTimeout(() => this._mouseTouchFinish(), 500);
}
};
/**
* Handle browser theme change
* @param e - the media query event
* @internal
*/
private readonly _handleThemeChange: (e: Event) => void = (e) => {
const mediaEvent = e as MediaQueryListEvent,
container = this.container,
options = container.options,
defaultThemes = options.defaultThemes,
themeName = mediaEvent.matches ? defaultThemes.dark : defaultThemes.light,
theme = options.themes.find((theme) => theme.name === themeName);
if (theme && theme.default.auto) {
container.loadTheme(themeName);
}
};
/**
* Handles blur event
* @internal
*/
private readonly _handleVisibilityChange: () => void = () => {
const container = this.container,
options = container.actualOptions;
this._mouseTouchFinish();
if (!options.pauseOnBlur) {
return;

clear(particle: Particle, delta: IDelta, force?: boolean): void {
if (particle.bubble.inRange && !force) {
return;
}
delete particle.bubble.div;
delete particle.bubble.opacity;
delete particle.bubble.radius;
delete particle.bubble.color;
}
init(): void {
const container = this.container,
bubble = container.actualOptions.interactivity.modes.bubble;
if (!bubble) {
return;
}
container.retina.bubbleModeDistance = bubble.distance * container.retina.pixelRatio;
if (bubble.size !== undefined) {
container.retina.bubbleModeSize = bubble.size * container.retina.pixelRatio;
}
}
async interact(delta: IDelta): Promise<void> {
const options = this.container.actualOptions,
events = options.interactivity.events,
onHover = events.onHover,
onClick = events.onClick,
hoverEnabled = onHover.enable,
hoverMode = onHover.mode,
clickEnabled = onClick.enable,
clickMode = onClick.mode,
divs = events.onDiv;
/* on hover event */
if (hoverEnabled && isInArray(HoverMode.bubble, hoverMode)) {
this._hoverBubble();
} else if (clickEnabled && isInArray(ClickMode.bubble, clickMode)) {
this._clickBubble();
} else {
divModeExecute(DivMode.bubble, divs, (selector, div): void =>
this._singleSelectorHover(delta, selector, div),
);
}
}
isEnabled(particle?: Particle): boolean {
const container = this.container,
options = container.actualOptions,
mouse = container.interactivity.mouse,
events = (particle?.interactivity ?? options.interactivity).events,
{ onClick, onDiv, onHover } = events,
divBubble = isDivModeEnabled(DivMode.bubble, onDiv);
if (!(divBubble || (onHover.enable && mouse.position) || (onClick.enable && mouse.clickPosition))) {
return false;
}
return isInArray(HoverMode.bubble, onHover.mode) || isInArray(ClickMode.bubble, onClick.mode) || divBubble;
}
loadModeOptions(
options: Modes & BubbleMode,
...sources: RecursivePartial<(IModes & IBubbleMode) | undefined>[]
): void {
if (!options.bubble) {
options.bubble = new Bubble();
}
for (const source of sources) {
options.bubble.load(source?.bubble);
}
}
reset(particle: Particle): void {
particle.bubble.inRange = false;
}
private readonly _clickBubble: () => void = () => {
const container = this.container,
options = container.actualOptions,
mouseClickPos = container.interactivity.mouse.clickPosition,
bubbleOptions = options.interactivity.modes.bubble;
if (!bubbleOptions || !mouseClickPos) {
return;

# Full Screen
- [`enable`](#enable)
- [`zIndex`](#zIndex)
## Enable
This property sets the canvas to a full window size acting like a background, the most common configuration. The default
value is `true`, so the canvas will be full screen acting like an animated background.
This is really helpful since there's no need to write CSS code to have a full size tsParticles instance.
## Z-Index
This is the CSS `z-index` property set to the canvas, the default value is `0`.

import type { DivMode } from "../../../../Enums/Modes/DivMode";
import { DivType } from "../../../../Enums/Types/DivType";
import type { IDivEvent } from "../../../Interfaces/Interactivity/Events/IDivEvent";
import type { IOptionLoader } from "../../../Interfaces/IOptionLoader";
import type { RecursivePartial } from "../../../../Types/RecursivePartial";
import type { SingleOrMultiple } from "../../../../Types/SingleOrMultiple";
import { executeOnSingleOrMultiple } from "../../../../Utils/Utils";
/**
* [[include:Options/Interactivity/Div.md]]
*/
export class DivEvent implements IDivEvent, IOptionLoader<IDivEvent> {
/**
* The div event handler enabling mode
*/
enable;
/**
* Div mode values described in {@link DivMode}, an array of these values is also valid.
*/
mode: SingleOrMultiple<DivMode | keyof typeof DivMode | string>;
selectors: SingleOrMultiple<string>;
type: DivType | keyof typeof DivType;
constructor() {
this.selectors = [];
this.enable = false;
this.mode = [];
this.type = DivType.circle;
}
/**
* The element id to detect the event
* @deprecated this property is obsolete, please use the new selectors
* @returns the element id
*/
get el(): SingleOrMultiple<string> {
return this.elementId;
}
/**
* The element id to detect the event
* @deprecated this property is obsolete, please use the new selectors
* @param value -
*/
set el(value: SingleOrMultiple<string>) {
this.elementId = value;
}
/**
* The element id to detect the event
* @deprecated this property is obsolete, please use the new selectors
* @returns the element id
*/
get elementId(): SingleOrMultiple<string> {
return this.ids;
}
/**
* The element id to detect the event
* @deprecated this property is obsolete, please use the new selectors
* @param value -
*/
set elementId(value: SingleOrMultiple<string>) {
this.ids = value;
}
/**
* The element id to detect the event
* @deprecated this property is obsolete, please use the new ids
* @returns the element id
*/
get ids(): SingleOrMultiple<string> {
return executeOnSingleOrMultiple(this.selectors, (t) => t.replace("#", ""));
// this is the best we can do, if a non-id selector is used the old property won't work
// but ids is deprecated so who cares.
}
/**
* The element id to detect the event
* @deprecated this property is obsolete, please use the new ids
* @param value -
*/
set ids(value: SingleOrMultiple<string>) {
this.selectors = executeOnSingleOrMultiple(value, (t) => `#${t}`);
}
load(data?: RecursivePartial<IDivEvent>): void {
if (!data) {
return;
}
const ids = data.ids ?? data.elementId ?? data.el;
if (ids !== undefined) {
this.ids = ids;
}
if (data.selectors !== undefined) {
this.selectors = data.selectors;
}
if (data.enable !== undefined) {
this.enable = data.enable;
}
if (data.mode !== undefined) {
this.mode = data.mode;
}
if (data.type !== undefined) {
this.type = data.type;
}
}


Step 2: ⌨️ Coding

  • engine/src/Options/Classes/Interactivity/Events/Events.ts ✅ Commit b73f4c9
• Add new properties `onMouseDown` and `onMouseUp` of type `ClickEvent`. • Initialize these properties in the constructor. • Add new getters and setters for these properties. • Update the `load` method to load these new properties from the provided data.
  • engine/src/Core/Utils/EventListeners.ts ✅ Commit 81fefd0
• Update the `_handlers` object to include new handlers for `mousedown` and `mouseup` events. • Update the `_doMouseTouchClick` method to handle these new events.
  • interactions/external/bubble/src/Bubbler.ts ✅ Commit 5c56c9e
• Update the `interact` method to use the new `onMouseDown` and `onMouseUp` events.
  • engine/src/Options/Classes/Interactivity/Events/DivEvent.ts ✅ Commit e270ba3
• Add new properties `onMouseDown` and `onMouseUp` of type `SingleOrMultiple`. • Initialize these properties in the constructor. • Add new getters and setters for these properties. • Update the `load` method to load these new properties from the provided data.
  • engine/src/Options/Interfaces/Interactivity/Events/IEvents.ts
• Add new properties `onMouseDown` and `onMouseUp` of type `IClickEvent`.
  • engine/src/Options/Interfaces/Interactivity/Events/IClickEvent.ts
• Add new properties `onMouseDown` and `onMouseUp` of type `SingleOrMultiple`.
  • engine/src/Options/Classes/Interactivity/Events/ClickEvent.ts
• Add new properties `onMouseDown` and `onMouseUp` of type `SingleOrMultiple`. • Initialize these properties in the constructor. • Add new getters and setters for these properties. • Update the `load` method to load these new properties from the provided data.
  • markdown/Options/Interactivity/Events.md
• Document the new `onMouseDown` and `onMouseUp` events.

Step 3: 🔁 Code Review

Working on it...


🎉 Latest improvements to Sweep:


💡 To recreate the pull request edit the issue title or description. To tweak the pull request, leave a comment on the pull request.
Join Our Discord

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request feature_request good first issue Good for newcomers Hacktoberfest help wanted Extra attention is needed pinned Pinned issues plugin A feature that could become a plugin sweep Assigns Sweep to an issue or pull request. up-for-grabs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants