Js custom HTML - custom context menu issues

What I’m trying to do:
create custom js context menu for my custom html form
What I’ve tried and what’s not working:
When I embed my custom HTML form within another form and right-click my mouse, the custom context menu appears at a location distant from the mouse pointer. Additionally, when I select any option from this menu, the entire page refreshes, but this occurs only the first time I run the application.
Code Sample:

<!DOCTYPE html>
<html>

<head>
	<style type="text/css">
		.context-menu {
			position: absolute;
			text-align: center;
			background: lightgray;
			border: 1px solid black;
		}

		.context-menu ul {
			padding: 0px;
			margin: 0px;
			min-width: 150px;
			list-style: none;
		}

		.context-menu ul li {
			padding-bottom: 7px;
			padding-top: 7px;
			border: 1px solid black;
		}

		.context-menu ul li a {
			text-decoration: none;
			color: black;
		}

		.context-menu ul li:hover {
			background: darkgray;
		}
	</style>

</head>

<body>
	<h1 style="text-align: center;">
	 click here to open contexxt menu
	</h1>
	<h1 style="text-align: center;">
		Hi, We are creating a
		custom context menu here.
	</h1>

	<div id="contextMenu" class="context-menu"
		style="display:none">
		<ul>
			<li><a href="#">Element-1</a></li>
			<li><a href="#">Element-2</a></li>
			<li><a href="#">Element-3</a></li>
			<li><a href="#">Element-4</a></li>
			<li><a href="#">Element-5</a></li>
			<li><a href="#">Element-6</a></li>
			<li><a href="#">Element-7</a></li>
		</ul>
	</div>

	<script>
		document.onclick = hideMenu;
		document.oncontextmenu = rightClick;

		function hideMenu() {
			document.getElementById(
				"contextMenu").style.display = "none"
		}

		function rightClick(e) {
			e.preventDefault();

			if (document.getElementById(
				"contextMenu").style.display == "block")
				hideMenu();
			else {
				var menu = document
					.getElementById("contextMenu")
					
				menu.style.display = 'block';
				menu.style.left = e.pageX + "px";
				menu.style.top = e.pageY + "px";
			}
		}
	</script>
</body>

</html>

app

clone

This issue has to do with anchor tags (<a> elements), when clicked, these can trigger a page reload if no href attribute is defined or if it’s set to "#"

But I am still unable to solve the incorrect positioning of the context menu, which works fine if the starting form is the HTML form, but once I insert the HTML form inside another form the positioning issue appears :man_shrugging:

I found the solution: adjusting the positioning by taking into account the offset of the parent container to calculate the correct coordinates by using the getBoundingClientRect method.


<!DOCTYPE html>
<html>

<head>
	<style type="text/css">
		.context-menu {
			position: absolute;
			text-align: center;
			background: lightgray;
			border: 1px solid black;
		}

		.context-menu ul {
			padding: 0px;
			margin: 0px;
			min-width: 150px;
			list-style: none;
		}

		.context-menu ul li {
			padding-bottom: 7px;
			padding-top: 7px;
			border: 1px solid black;
		}

		.context-menu ul li a {
			text-decoration: none;
			color: black;
		}

		.context-menu ul li:hover {
			background: darkgray;
		}
	</style>

</head>

<body>
	<h1 style="text-align: center;">
	 click here to open contexxt menu
	</h1>
	<h1 style="text-align: center;">
		Hi, We are creating a
		custom context menu here.
	</h1>

	<div id="contextMenu" class="context-menu"
		style="display:none">
		<ul>
			<li><a href="#">Element-1</a></li>
			<li><a href="#">Element-2</a></li>
			<li><a href="#">Element-3</a></li>
			<li><a href="#">Element-4</a></li>
			<li><a href="#">Element-5</a></li>
			<li><a href="#">Element-6</a></li>
			<li><a href="#">Element-7</a></li>
		</ul>
	</div>

	<script>
		document.onclick = hideMenu;
		document.oncontextmenu = rightClick;

		function hideMenu() {
			document.getElementById(
				"contextMenu").style.display = "none"
		}

		function rightClick(e) {
    e.preventDefault();

    if (document.getElementById("contextMenu").style.display == "block") {
        hideMenu();
    } else {
        var menu = document.getElementById("contextMenu");
        var rect = menu.parentElement.getBoundingClientRect(); // Get the parent's bounding rectangle

        menu.style.display = 'block';
        menu.style.left = (e.pageX - rect.left) + "px"; // Adjusting the X-coordinate
        menu.style.top = (e.pageY - rect.top) + "px"; // Adjusting the Y-coordinate
    }
}

	</script>
</body>

</html>

2 Likes

Pleased you found a solution!

It’s probably not relevant anymore but here’s a little proof of concept context menu helper.
Using anvil.js


class Form1(Form1Template):
    def __init__(self, **properties):
        self.init_components(**properties)
        add_context_menu_handler(self.button_1, self.on_context_menu)

    def on_context_menu(self, event, sender, **event_args):
        result = context_menu(content=ContextMenu(), event=event)
        print(result)
        if result:
            sender.text = result

And the api is similar to an anvil alert
The ContextMenu form has to raise the "x-close-context-menu" event with the result.

A8CrYCYh1o

1 Like

Wow that is awesome :star_struck:. Thank you for sharing @stucork!

1 Like