Guarantee non-conflicness - javascript

I would like to make an addon to browser, that would show image of question mark if something was selected, and to show a tooltip with translation upon click on the image. Something like on nytimes web page when reading articles, but more user friendly. For showing the image I use this:
function ShowQuestionMark(e)
{
if (window.getSelection().toString() != "")
{
/* add an img tag */
document.onmouseup = RemoveQuestionMark;
}
}
function RemoveQuestionMark(e)
{
/* remove img tag */
document.onmouseup = ShowQuestionMark;
}
document.onmouseup = ShowQuestionMark;
My goal is to make it work on every web page (or at as many as possible).
Now my first question. I assume, when I use it this way and load a page, which by default have a handler for onmouseup event, I override it and whatever was the handler, it won't be executed when firing onmouseup event. Am I correct?
Second question, how can I guarantee, that my script won't override/break any default behavior? Should I use binding? Or should I create new unique event? Or something entirely else?

I don't know the answer to your first question, because I've never directly assigned an event handler like that while writing an extension, knowing a conflict would occur. But I think the page's event handler would override yours. Either way, you need to avoid the conflict.
Anyway, here's how you avoid the conflict: use addEventListener():
function ShowQuestionMark(e) {
if (window.getSelection().toString() != "") {
document.removeEventListener("mouseup", ShowQuestionMark);
/* add an img tag */
yourImgTag.addEventListener("click", RemoveQuestionMark);
}
}
function RemoveQuestionMark(e) {
yourImgTag.removeEventListener("click", RemoveQuestionMark);
/* remove img tag */
document.addEventListener("mouseup", ShowQuestionMark);
}
document.addEventListener("mouseup", ShowQuestionMark);
Now, if the page is kind enough not to override or cancel the event (which it can still do), both your event handler and the page's event handler will be run.

Related

Stop browser from sending certain JavaScript events

There is a website which fires a function on when the tab is blurred. I don't want that to happen.
Is there a way I can stop javascript from firing window.onBlur event?
From initial search, I have come to the conclusion that I need to override the default function of javascript, which can be done using userscript managers like Greesemonkey.
I tried the following script in Greesemonkey:
window.onblur = null
This doesn't seem to have any effect and the webpage behaves same as previously.
Have look at Event.preventDefault() and Event.stopPropagation() if it helps your case.
If you would like to override the function which is called on the event, you can simply redefine it and insert it using a script manager. For example:
var originalCallbackFunction = callbackFuntion;
callbackFunction = function() { // Redefinition
/* Do something else */
}

How to grab some mouse events, send others to iframe?

I need to capture certain user events (i.e. double-click) but let the rest pass to the iframe below. Some of these events may be enabled/disabled over time. I also don't want to block the iframe from receiving simple events like click or scroll. It seems, however, that iframe gets dibs on both bubble events (makes sense) and capture (this doesn't make sense, as it violates the order of propagation).
It seems like the only way to prevent the iframe from stealing all events is by putting an invisible div above it. In that case, however, I'd need to write handlers for all events to create a fake fall-through to the iframe, because even the events the div doesn't capture will no longer hit the iframe.
I see the following potential problems with this approach:
I may not be able to pass-through/simulate a click event into a foreign iframe (most iframes would be generated via srcdoc, so they'd be local, but some may reference foreign location via src)
I will need to write handlers for just about every mouse event to simulate a pass-through
It may be problematic to send the event to iframe itself and let it resolve the coordinates rather than detecting which element inside the iframe should receive the event
I may be wrong about my assumptions, so feel free to correct me.
Another approach I played around with involves detecting when iframe gets focus:
function clickListener() {
var monitor = setInterval(function(){
var elem = document.activeElement;
if(elem && elem.tagName == 'IFRAME'){
message.innerHTML = 'Clicked';
setInterval(function() {
message.innerHTML = '';
}, 100);
clearInterval(monitor);
elem.blur();
clickListener();
}
}, 100);
}
clickListener();
iframe {
width: 500px;
height: 300px;
}
<iframe id="iframe" src="//example.com"></iframe>
<div id="message"></div>
Problems with this approach:
the 100ms loop isn't ideal when I have 20+ elements on the page doing this
it ignores hover events and lumps all click-like events into a click
These two problems (especially the 2nd) are actually pretty severe show-stoppers, as I want to be able to detect double-click and drag events as well.
Does anyone have suggestions for how to tackle this?
You can check for the click coordinates on the fly and see if they match to your iframe. If they do, then its a double click on iframe, else, let other elements handle the event.
document.addEventListener("dblclick", check);
function check(event) {
if(document.elementFromPoint(event.clientX, event.clientY).id == "message") {
alert('iframe clicked');
} else {
alert('something else dude');
}
}
And obviously, stop iframe from receiving any clicks:
iframe {
pointer-events: none;
}
Here's a fiddle: https://jsfiddle.net/rg59yaau/1/

javascript/jquery How to cancel .on when a class is present

I have several places throughout my code where I use .on to attach events (usually to delegate the events). We're changing around how we're doing a few things, and we're now wanting to add a .disabled class to the elements that we want to be disabled. I'd like to block all the events on disabled items without having to refactor each location, I'm wondering if it's possible.
Example code: I've added this to the top of my script
$('body').on('click', '.disabled', function(event){
console.log("blocked");
event.stopImmediatePropagation();
// event.preventDefault();
// event.stopPropogation();
return false;
});
And an example of my normal events:
$('.ActionsContainer').on('click', '.Link', functions.ClickAction);
Problem is that even with the return false and all the others it still runs both the "blocked" and functions.ClickAction
Is there anyway around refactoring every one? I mean I can change that line below to:
$('.ActionsContainer').on('click', '.Link:not(.disabled)', functions.ClickAction);
but that's really annoying, and feels brittle.
It's not too hard. You'll need to take advantage of jQuery's special events and basically override calls to any of the original event handlers setup in the existing code. jQuery's special events hooks let you override a number of features of the event system. jQuery essentially sets up it's own handler on an element the first time a listener is attached, and then adds the callback for the listener to its queue. As other listeners get attached to the element later, their callbacks get added to this queue as well.
Using the 'events.special.click' hook, we can add a function that gets called prior to any callbacks on that element's event queue which lets us intercept the call and check for, as you mentioned, that the element has a 'disabled' class and if so, stop the original callback from executing; or if it doesn't have the class, allow the original callback to execute normally.
I've put together a jsFiddle to show how it works. See if that solves your issue. The code for the override using special events is embedded below the link:
http://jsfiddle.net/datchley/bthcv/
// ADDED TO OVERRIDE CLICKS ON 'DISABLED' ELEMENTS
(function($) {
$.event.special.click = {
add: function(handle) {
// Save original handler
var orig_handlefn = handle.handler,
$el = $(this);
// Reassign our new handler to intercept here
handle.handler = function(ev) {
if ($el.hasClass('disabled')) {
// Don't allow clicks on disabled elements
$('.output').html('<b>Warning</b> You clicked a disabled element!');
ev.preventDefault();
}
else {
return orig_handlefn.apply(this, arguments);
}
};
}
};
})(jQuery);
Assuming every .Link has that container and you're handling all events at that container, this is the most straightforward way:
$('.disabled').click( function(e){ e.stopPropagation(); } );
stopProp prevents that event from ever bubbling up to the action containers.

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;
}

Javascript and onbeforeunload?

I have
<span class="cssButton"> <img src="http://uber-upload.com/img/icons/up_16.png" alt=""/> Uber-Upload! </span>
And i want to make it so that if you press that button, it also sets a variable that makes it so that if you try to leave the page, it will pop up one of those "Are you sure you want to leave this page" alerts to prevent people from accidently leaving while there is an upload going on.
Dont worry about unsetting the variable after the upload finishes, i'll add that, i just need one of you smart coders to make me a framework.
Thanks!
Add this declaration to the page:
var upcount = 0;
Change your onclick to:
onclick="++upcount; swfu.startUpload();"
If the swfu gives you some kind of event when it's done uploading, put this on it:
--upcount;
And add this handler:
window.onbeforeunload = function() {
if (upcount > 0) {
return "The upload is still in progress, leaving the page will cancel it.";
}
}
Where browsers respect the onbeforeunload, that'll work. And most of them do, most of the time. Where they don't, well, you tried. Note that by using a counter, you're allowing for multiple uploads.
You might consider attachEvent (IE) or addEventListener (standard) (or a library like Prototype or jQuery that evens out the differences for you) for attaching your events rather than using attributes. Using attributes (aka DOM0 handlers) is fairly old-fashioned and a bit limiting (only one handler per event per element). But it does still work.
function warnUser()
{
if(dataIsDirty)
{
return "You have made changes. They will be lost if you continue.";
}
else
{
// Reset the flag to its default value.
dataIsDirty = false;
}
}
function isDirty()
{
dataIsDirty = true;
}
function isClean()
{
dataIsDirty = false;
}
Then you use it just like on the onbeforeunload event.
window.onbeforeunload = warnUser;
dataIsDirty = false; //Or true, depending on if you want it to show up even if they dont' make changes)
Then to use it, just use the 'isClean' function to anything you don't want to trigger it(Save, for instance), or you can attach 'isDirty' to any event you want to trigger it before they leave (say, editing a form field).
Relying on onbeforeunload is sketchy at best. Because spammers have abused the behavior in the same way you're suggesting the ability for people to do this has been basically removed.
You can now only respond to onbeforeunload if the close event was fired from activating a button or such.

Categories

Resources