How to prevent default functionality of paste event in monaco editor - javascript

How can I prevent default functionality for paste event (when trigger from browser menu option Edit->Paste) for monaco editor?
I am handling paste event in the following way:
editor.getContainerDomNode().addEventListener('paste', (event) => {
event.preventDefault();
event.stopPropagation();
}
I also tried to handle the paste event on the textarea which is the source element in event propagation.
let textarea = editor.getContainerDomNode().querySelectorAll("textarea.inputarea.monaco-mouse-cursor-text")[0];
textarea.addEventListener('paste', (event) => {
event.preventDefault();
event.stopPropagation();
});
But here also seems like preventDefault is not working. It is pasting into editor whatever the text is copied.
Bascially I want to disable paste action when triggered from browser Edit menu. Need to know how this can be achieve in monaco-editor. Am I doing anything wrong here or it is a bug of monaco editor?

Your problem comes from the way an event is handled by listeners, when they are set on different ancestor elements.
An event is generally treated on a target element, then it "bubbles" on its ancestors.
On your case, you are adding a listener on a parent element of the editor. Which means that your listener will be executed after any listener on the actual target (which is actually how monaco handles the paste event).
So you are trying to prevent an action that was already executed.
Luckily, there is a way to achieve what you want! It is called "capturing".
By specifying in the call to addEventListener that you want to capture the event on its way down. This can be done by adding a third argument {capture: true}, or simply true:
editor.getDomNode().addEventListener('paste', (event) => {
event.stopPropagation();
event.preventDefault();
}, true);
This should prevent the editor from actually executing the action.
See Documentation on bubbling and capturing events.

Related

Is it possible to monitor the event listeners in an HTML element to know when one of them is removed?

I have a problem in a page with an event not being fired under certain circumstances. It's not my code and I'm trying to debug minified and obscured JavaScript code and I'm going crazy.
When replying to a comment in our website, if the text of the reply is empty this event (an analytics event to register that the user clicked the reply button) is fired. If there's text, the event isn't fired.
The element is a <span> tag, but the event listener is actually attached to the <body> tag. My current theory is that some code that's being executed when there's actually text in the reply is removing that event listener and therefore it's not being fired.
So, is there a way to monitor the event listeners in <body> to know when (and where in the code) is this event listener being removed?
Update
We found the problem. The third-party library we use for the comments is removing the parent element of the button and that's making impossible for the event to propagate to body.
If you can run script code before the event handler is removed, you can replace removeEventListener on document.body with your own function:
const original = document.body.removeEventListener;
document.body.removeEventListener = function(...args) {
console.log("Removed");
return original.apply(this, args);
};
function handler() {
console.log("Clicked");
}
document.body.addEventListener("click", handler);
document.body.removeEventListener("click", handler);
(To cover your bases you might also convert onclick (or whatever is being used) to an accessor so you can capture it if code does document.body.onclick = null;)
There are other ways a handler can be added and removed, but hopefully whatever library you're using uses the standard.
Side note: To confirm your theory about the handler being removed, you can inspect the handlers on an element in Chrome's devtools: Right-click on the page and choose "Inspect element", navigate up to body, and look on the Event Listeners tab.
I think you can use also the google developers tools that you can open with a button on the top right corner on the window. In the source section you can see al the event listener

How to make all page elements not to react on clicks

I'm trying to make an extension with 'pick' functionality: letting the user click on any element on the page and see the xpath for it.
However, to make it usable I have to prevent the element from reacting on clicking: I don't want clicking on hyperlinks to forward me to another page, buttons to submit forms, etc., etc.
How would I do that?
UPD: I need it only for Chrome
The cleanest way in my opinion would be to bind one event handler to body in the capturing phase and prevent the event from propagating/the default behavior.
You can get a reference to the clicked element with event.target:
document.body.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
console.log(event.target);
}, true);
The advantage is that this event handler will be the very first that is triggered, no matter which other event handlers are bound to elements in the page (unless of course the page binds a similar event handler to body, but usually event handlers are bound in the bubbling phase).
For more information see quirksmode.org - Event order and MDN - addEventListener.
DEMO
For a CSS only solution:
* {
pointer-events: none;
}
Try this
$('body *').on('click',function(e){
return false;
});
In your click event handler make sure you either call preventDefault() in the event object, or return false from your function. For example:
function myClickHandler(e) {
e.preventDefault() // e is the event object
// Do your click stuff here
.
.
.
return false; // not required if you've called e.preventDefault()
}

Determining whether focus was received as result of a click event

I have an <input> element that can either have the focus set via code, or as the result of a mouse click.
If the user clicks on the input, then the click event handler will fire - all well and good. If the element receives the focus via some other way (e.g. via code) then I want to manually trigger the click event so that the handler will also fire.
I could do this:
$elem = $('input');
$elem
.on('focus', function() { $(this).trigger('click') })
.on('click', function() { alert('Clicked!') });
However, this will result in click handler being fired twice; once for the click event and once for the focus event.
Is there any way to selectively trigger the click handler only if the focus was not received as the result of a click event?
UPDATE
This is a very simplified version of my problem, so I can't do things like bind both handlers to the focus event etc. I'm trying to merge two third-party pieces of code.
The .trigger() function adds a property isTrigger in the event object to identify that the event was triggered by its usage. Although, it is not documented the property is still present in jQuery 1.8.3 but it seems to only be used internally.
Anyways, you can make use of the extraParameters parameter to add a custom property to the event object. For instance,
$(this).trigger('click', {
isTrigger: true
});
It will keep the compatibility with isTrigger even if it is gone in a future release.
After doing some more research it appears that there is no way of guaranteeing which event will fire first: click or focus. (There doesn't seem to be a standard that dictates the order of events.)
This means that when the focus event fires there's no way to determine if a click event will or will not be triggered by the browser shortly afterwards.
I managed to solve the issue by using setTimeout() to run a test about 100ms after the focus event fired to check if the click event had fired. The third-party code that I was using (bound to the click event) added an extra class to the <input>, so I was able to check for that.
You can tap into the mousedown event which fires before the focus event. When you click a focusable object the order of events is as follows... mousedown, focus, mouseup, click.
You could set a flag in the mousedown event and then check for it in the focus event to see if the focus came from a mouse click. Obviously make sure to clear the flag in the focus event handler. Every application is different, but tapping into the mousedown event allows you to figure out a solution.
Here is a JSFiddle demonstrating the order of events... http://jsfiddle.net/ek7v7/
$elem = $('input');
$elem
.on('focus', function() { alert("Focused!") })
Focus can be fired by focusing the input by using tab, clicking it, or by using .focus()
Is there a reason for on('click', ...)?

Disable all actions on elements inside a container

I'm implementing an interactive tutorial for a js-heavy web application. I highlight some container and expect the user to click on some element inside it. At the same time, I want to prevent the user from doing anything else, e.g. clicking on a different link.
The main problem is that I don't want to unbind any events - when the tutorial's closed, the application must work like it did before.
I started with registering a handler on all the containter's descendant elements:
element.on("click.tutorialLock", function(e){
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}
Then I set its "priority", so that it executes before any other events:
handlers = element.data("events").click;
our = handlers.pop();
handlers.splice(0, 0, our);
Finally, when I want to unlock some element, I just disable the event on it:
elementToEnable.off(".tutorialLock")
That works, but is very heavy. I tried registering the event only on elements which have some custom event handlers defined, but it omits anchors and other basic elements. Maybe you could come up with some good idea?
I would get the active parent element and pass it into a function which would disable every event other than the events in parent
$('.className').live ('click', function (e)
{
if (!$(this).parents('#targetParent').length))
return false; // same as e.preventDefault() & e.stopPropogation()
});
Hope this is similar to what you want

disable all click events on page (javascript)

Whats the easiest way to temporarily disable all mouse click/drag etc events through javascript?
I thought I could do document.onclick = function() { return false; }; ...etc, but that's not working.
If the objective is to disable click on the whole page then you can do something like this
document.addEventListener("click", handler, true);
function handler(e) {
e.stopPropagation();
e.preventDefault();
}
true argument in addEventListener would ensure that the handler is executed on the event capturing phase i.e a click on any element would first be captured on the document and the listener for document's click event would be executed first before listener for any other element. The trick here is to stop the event from further propagation to the elements below thus ending the dispatch process to make sure that the event doesn't reach the target.
Also you need to stop default behavior associated with event target elements explicitly as they would be executed by default after the dispatch process has finished even if the event was stopped propagating further from above
It can be further modified to use selectively.
function handler(e) {
if(e.target.className=="class_name"){
e.stopPropagation();
e.preventDefault();
}
}
handler modified this way would disable clicks only on elements with class "class_name".
function handler(e) {
if(e.target.className!=="class_name") {
e.stopPropagation()
}
}
this would enable clicks only on elements with class "class_name".
Hope this helped :)
Dynamically disable all clicks on page
let freezeClic = false; // just modify that variable to disable all clics events
document.addEventListener("click", e => {
if (freezeClic) {
e.stopPropagation();
e.preventDefault();
}
}, true);
I often use it while loading or to avoid user to accidentally clic twice on an action button. Simple and performance friendly :)
Please check this working example
Alternative CSS way
Another one that I really like because of the visual feedback the user have:
/* style.css */
.loading {
cursor: wait; /* busy cursor feedback */
}
.loading * {
/* disable all mouse events on children elements */
pointer-events: none;
}
A simple example to dynamically add the .loading class:
const elm = document.getElementById('myElm')
elm.classList.add('loading')
myAsyncFunction().then(() => elm.classList.remove('loading'))
If you want absolutely nothing draggable/clickable, disabling typing in input fields etc, I'd consider showing a absolutely positioned transparent div over the entire page, so that every click will be on the div, which will do nothing. That will grant you swift and neat switching on and off of this click-disabler, without having to register heaps of listeners
The winning answer works well, but if you had pass the capture true boolean value, at the moment you want to remove the listener, you have to pass the exact same value. Otherwise, the listener removal will not work.
Example:
listener addition
document.addEventListener('click', DisableClickOnPage.handler, true);
listener removal
document.removeEventListener('click', DisableClickOnPage.handler, true);
Doc: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
window.addEventListener("click", (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}, true)
If we added a listener to document instead of window anyone can add a listener to window and it works. Because of document child of window and its events trigger always after window events.
We use 3 method of Event object.
stopPropagation for prevent all capturing and bubbling
stopImmediatePropagation for prevent same listeners (e.g. another window click listeners)
preventDefault for prevent all user agent event (e.g anchor href or form submit)
If onclick = null has been executed how to revoke the onclick event to normal functioning.. or
Link text
<script type="text/javascript">
function yourFunction(anchor)
{ if(anchor.disabled) return;
/* Your function here */
}
</script>
This article would probably be useful:
http://www.computerhowtoguy.com/how-to-use-the-jquery-unbind-method-on-all-child-elements/
One part in particular is a recursive function that removes all click events. Remember that jQuery will remove click events IF the click event was created using jQuery. the function given in the article will remove both those created with jQuery and those that were not. The function given is this:
function RecursiveUnbind($jElement) {
// remove this element's and all of its children's click events
$jElement.unbind();
$jElement.removeAttr('onclick');
$jElement.children().each(function () {
RecursiveUnbind($(this));
});
}
You would call the function like this:
RecursiveUnbind($('#container'));
That function takes a jQuery object parameter, but you could easily change it up to pass a string as the name of the ID for the element, or however you think is best.
To prevent the default behavior of an event, use event.stopPropagation() and event.preventDefault() in your event handler. And don't forget, return false; is another method for indicating that you want to cancel the default action...
The Event property returnValue indicates whether the default action for this event has been prevented or not. It is set to true by default, allowing the default action to occur. Setting this property to false prevents the default action. (Source: MDN Web Docs: Event.returnValue.)
Typically, we return a value from any function when it has any meaningful or useful purpose -- return false to cancel an event is meaningful because it indicates a failed event, and it's useful because the event-handler uses it.
For greatest cross-browser compatibility, remember to return false;...
document.addEventListener("click",handler,true);
function handler(e){
e.stopPropagation();
e.preventDefault();
return false;
}

Categories

Resources