How to prevent a button added by a userscript [GreaseMonkey/TamperMonkey] from submitting a form - event-handling

Let me start off by saying that the code in question is part of a UserScript and, as such, normal DOM rules and Javascript methods do not work.
Here is the situation:
I have written a UserScript that interacts with an online chat site. I have a number of button that are generated within the user script. Some of these buttons are located inside of a form, while many of them are not.
Elements added through GreaseMonkey live in two worlds -- they live on the page DOM and they live in the slightly elevated world of UserScripts, which mean that these lines:
event.preventDefault = true;
event.stopPropagation = true;
prevent the rest of the UserScript actions from running, but it does not stop the button from causing a form submit.
As a work around, I am building span elements instead of a button. This works, but it really breaks the visual layout of the chat room.
Does anyone know a way to prevent elements added by UserScripts to prevent form submissions? Failing that, I'll dream that someone knows how to make a span look like a native button.
Edit: I have a solution which seems to be working -- but I haven't fully tested it under every UserScript environment:
// Yes, yes, poorly named but it was a SPAN
// userWindow is an alias for unsafeWindow.
// (Used to run under a userScript environment for IE and I had to emulate a lot)
var span = document.createElement("input");
span.value = text;
span.type = "button";
span.className = "cpbutton";
// Add it to the body just long enough to set up a page-level, DOM0 event handler
var body = userWindow.document.getElementsByTagName("body")[0];
var tname = "IAmTheVeryModelOfAModernMajorGeneral";
span.id = tname;
body.appendChild(span);
userWindow.document.getElementById(tname).onclick = function() {return false;};
body.removeChild(span);
span.id = "";

See the W3C spec for <button>.
By default, a <button> element acts as a submit button inside a form. This means that event.preventDefault() (the correct usage, BTW), on the click handler, may not be enough to stop the form submit.
In that case you could intercept the form's submit event too BUT, the smart thing to do is to use the type attribute to tell the browser not to treat the button as a submit button.
EG:
<button type="button">Your button markup</button>

when you say
to prevent elements added by UserScripts to prevent form submissions
i'm not sure if you want to allow or prevent submiting the form...
anyway, here is a link and a div disguised as a button: http://jsfiddle.net/RASG/PvhUb/
and if you post some of your code, i can help you with your script.

Related

One Click vs Two Clicks

Scenario:
Testing web application using Protractor
Element needs to be clicked on to open another page
Designed the test to have one click on the element
Issue:
Sometimes elements needs one click and the test passes but if I run it again the same element needs double clicks
This is causing my test to fails randomly
I verified this by changing the command to have a double click in protractor and it passed.
This is causing inconsistency as I don't know when the element needs one or double clicks.
Any Suggestion is appreciated?
You may just need to put the element into focus explicitly via mouseMove() and then issue a click() action:
browser.actions().mouseMove(elm).click().perform();
Inconsistency might be because of element is not yet ready to click. So you need to wait until element become clickable and click it. Below code will help you in achieving consistency.
Code Snippet:
var EC = protractor.ExpectedConditions;
var elementToBeClick=element(locator);
var timeOut=10000;
browser.wait(EC.elementToBeClickable(elementToBeClick), timeOut).
thenCatch(function () {
assert.fail(' target element is not clickable');
});
elementToBeClick.click();
you can use browser.executeScripts to inject native javascript code into the browser and click the required button. this will execute the click event on the required element that you pass into the function
try the below code,
var elementToBeClick=element(locator);
browser.executeScript("arguments[0].click()",elementToBeClick.getWebElement())

Google Closure add onclick to button after adding this button with custom editor plugin

I am making a custom plugin for the editor provided by Google Closure. The plugin makes it able to add a button.
I am having problems by setting an onclick on the button, the other values are nicely set.
button.innerHTML = event.label;
button.className = event.initialClass;
var extraClasses = event.extraClasses;
if (extraClasses)
{
button.className += ' ' + extraClasses
}
button.onclick = function() { event.onclick };
Does anyone know what I am doing wrong and how I can fix this?
After creating a button it is added to the editors SeamlessField. A second problem that I currently have is that after creating the button, my pointer is inside the button and I can't seem to get it out of there.
I've got the follow piece of code for handling this at the moment. The var button is the created button. button contains: <button class="orange">test</button>
// We want to insert the button in place of the user's selection.
// So we restore it first, and then use it for insertion.
this.restoreOriginalSelection();
var range = this.fieldObject.getRange();
button = range.replaceContentsWithNode(button);
// Done making changes, notify the editor.
this.fieldObject.dispatchChange();
// Put the user's selection right after the newly inserted button.
goog.editor.range.placeCursorNextTo(button, false);
// Dispatch selection change event because we just moved the selection.
this.fieldObject.dispatchSelectionChangeEvent();
Any ideas about how I could fix this second problem aswell?
For the first, it does not look like you have begun using Google Closure event code. Wiring up the button to the 'click' event in Google Closure would be as follows:
goog.events.listen(button, goog.events.EventType.CLICK, event.onclick)
You should also be investigating the goog.dom and goog.dom.classes namespaces if you'd like to use Google Closure's wrappers around standard CSS class and text DOM manipulation.
For the second, were you testing in Chrome? If so, you might have ran into a range issue in Webkit, documented within the Closure code itself:
https://code.google.com/p/closure-library/source/browse/closure/goog/editor/range.js#174
I have gotten around this in the past by inserting an empty <span> element as a sibling after the offending element (the button, in your case), and placing the cursor next to the <span> instead. However, there's nothing stopping the user from moving the cursor back inside your button. You'll have to add more logic to prevent a user from placing the cursor within the button's text.

form textbox - keep focus during page load

On my homepage I have a form with a search textbox. If you click on the input and start typing when the page in still loading, something steals the focus so you have to click back in the input textbox.
Is there a way to prevent this from happening? Do I need to find what is stealing the focus?
Sounds like one of your scripts is setting something to focus on load.
Put this at the bottom of your HTML right before </body>. Your console will show you the HTML of the item that is gaining focus.
<script>
$(window).load(function() { // NB not document ready
console.log($(':focus')[0]);
// alert($(':focus')[0]); // if you don't know what console is
});
</script>
Hopefully there will be an ID in the element that you can search your script for, or enough clues to let you find what's being told to focus on load. Then you can remove/alter that line.
Addendum
It turns out this is the culprit
$('#f input#livesearch').clearableTextField();
That clearable function is only ever going to be required if the user uses that field, so let's make it contextual, i.e. only when it's given focus, make that function available. This should stop the naughty plugin stealing focus.
$('#f input#livesearch').on('focus', function(){
$(this).clearableTextField();
});
It's generally best to write contextually - you'll find pages with dozens of binds and "live" events being set up on onload, but they are rarely used. If it's something that doesn't need to happen until the user does something or until you can tell a user is about to do something, write it that way.

"Send" button popup not appearing correctly

I'm using the Facebook Like/Send buttons along with dynamically generated HTML (loaded via AJAX requests). I've found that even though the Send button works fine when the element exists on page load, dynamically created Send buttons aren't working correctly. Clicking the button activates it and the button greys out, but the popup doesn't appear.
Here is a demonstration of what is happening: http://jsfiddle.net/Daniel15/VxpSj/
Any suggestions?
Thanks!
Yes, I can confirm the problem from your fiddle.
function addLikeButton()
{
// […]
FB.XFBML.parse(newEl);
document.getElementById('container').appendChild(newEl);
}
For some reason, this seems to be “the wrong way around”. Reverse the order of these two lines – put the new element into the DOM first and let FB.XFBML.parse parse it afterwards, then (from my test with your fiddle) it seems to work in the desired way.

How to create a "New xxx" popup?

I have a Grid object and added a [ (+) New Client ] button which I'd like to open a popup form to create the new client with a couple fields.
I've looked at the code examples in the website but haven't found how to do it (sorry if I've missed something).
This is the current page code:
function page_clients_listing($p){
$g = $p->add('Grid');
$g->addColumn('text','first_name');
$g->addColumn('text','last_name');
$g->addColumn('inline','telephone');
$g->addColumn('expander','comments');
$g->setSource('client');
$g->addButton('With Icon')->set('Add New Client')->setIcon('Plus');
}
Thanks in advance!
You can either create a popup or a dialog. Dialog is based on jQuery UI dialog implementation. Popups are likely to be blocked and are harder to control.
This is actually working for any object (you can apply to view, button, image, icon, etc), but I'll use button).
$b=$g->addButton('Add New Client')->setIcon('Plus');
$b->js('click')->univ()->frameURL($title,$url);
// OR
$b->js('click')->univ()->dialogURL($title,$url);
$url would most likely be returned by api->getDestinationURL(). The other page would be loaded and scripts on that page will be evaluated. Let's say you are on other page and now need to close the window.
$result = $this->addButton('Close')->js('click')->univ()->closeDialog();
closeDialog() returns a jQuery chain object pointing to a view which originally opened the frame. As a result if you do $result->hide(); then after dialog is closed, the original button ('add new client') will also be hidden.
Here is example to show some additional things you can do with frames, reloading and custom event handlers:
http://agiletoolkit.org/example/refresh1