ExtJS/Script# - Adding a double-click event to a button - extjs

Creating a calculator-like dialog, I noticed that quickly clicking on a button in IE will not fire the click event twice (Chrome/FF work as expected), but rather throws the click event, then a double-click event. Experimenting with some simple code, I essentially want to duplicate this behavior:
<script language=javascript>
function minus(num)
{
var i = document.getElementById('0001');
if (i.value > 1)
{
i.value -= num;
return true;
}
}
</script>
<input type="button" onclick="minus(1);" ondblclick="minus(1);" value="minus">
<input type="text" id="0001" name="0001" value=10>
I need to do this in ExtJS 3.1, but my efforts have been stymied. Here is the code I have tried:
Button btn = new Ext.Button(new ButtonConfig()
.text(text)
.tooltip(tooltip)
.tooltipType("title")
.scope(this)
.handler(delgateFunction)
.x(x)
.y(y)
.tabIndex(_tabIndex++)
.width(width).height(height)
.ToDictionary());
btn.addListener("mouseenter", new EventHandler(mouseHandler));
btn.addListener("mouseover", new EventHandler(mouseHandler));
btn.addListener("mouseout", new EventHandler(mouseLeave));
if (Ext.isIE)
{
//btn.on("dblclick", new EventHandler(DoubleClick));
//btn.addListener("dblclick", new EventHandler(DoubleClick));
//btn.addListener("ondblclick", new EventHandler(DoubleClick));
}
None of those three lines seemed to work. Any suggestions?

try the following after the button is rendered:
btn.el.on("dblclick", new EventHandler(DoubleClick));
Ext.Button itself hasn't the "dblclick" event (check the api) while its underlying el(Ext.Element) has.
Complete Sample:
new Ext.Button({id:'btn', text:'dblclick', renderTo:Ext.getBody() });
Ext.getCmp('btn').el.on('dblclick', function(){alert('db click');});

Mr. Zhu led me to the correct answer:
Events.AddEvent(_zeroBtn.getEl().dom, "dblclick", DoubleClickZero);

Related

Why does Selenium sometimes skip checkboxes?

I'm having troubles regarding webdriver not being able to click checkboxes sometime and just skipping them, both in Firefox and Chrome.
I've tried different solutions such as
click();
action.moveToElement(checkbox).clickAndHold(checkbox).release().perform();
jse.javascriptExecutor(argument[0].click(),checkbox).
Here I provide the Javascript code I have for the click event
...
var selectCorrectOption = function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
$(this).find('> input').prop('checked', false);
} else {
$(this).addClass('selected');
$(this).find('> input').prop('checked', true);
}
};
$('.option > .input-container').on('click', selectCorrectOption);
...
the HTML code where it is attached the javascript click event
<div class="input-container selected" data-choice-id="2">
<input type="radio">
</div>
the Java code data uses a data-attribute to access the element is question. Notice also that once the div is clicked, a 'selected' class appears(which is the current state) on the code below.
WebDriverWait wait = new WebDriverWait(driver, 20);
JavascriptExecutor jse = (JavascriptExecutor)driver;
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("[data-choice-id='"+ wrongOptionVal +"']")));
radio=wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("[data-choice-id='"+ wrongOptionVal +"']")));
jse.executeScript("arguments[0].scrollIntoView()", radio);
jse.executeScript("arguments[0].click()", radio);
I expected it to be consistent ,most of the times work, but there are always that one or two times it fails.
I do not know why this happens, I do however know how this can be addressed. You can implement a FluentWait with polling mechanism, which will do three things:
locate the element,
select the radio box,
return getAttribute("class").contains("selected") value.
If getAttribute("class").contains("selected") will result in false the process should repeat.
FluentWait<WebDriver> fluentWait = new FluentWait<>(driver)
.pollingEvery(Duration.ofMillis(300))
.withTimeout(Duration.ofSeconds(10));
fluentWait.until(new Function<WebDriver, Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
WebElement element = driver.findElement(By.cssSelector(radioCssSelector));
element.click();
return element.getAttribute("class").contains("selected");
}
});

Modal is closed when cursor is released outside the modal after Chrome update (angularjs and bootstrap-ui)

Sometimes when I want to quickly select the entire text of an input (within a modal), I begin selecting from the end of the text and move the mouse to the left until the entire text is selected and then I release.
Sometimes this release will occur outside the modal because the mouse movement is fast.
Picture describing the movement:
The problem is that the modal is closed when I release outside.
Question: how can I prevent the modal from closing when releasing outside?
I'm okay with the modal being closed with a click outside. But not okay with the release event.
I'm using:
angularjs 1.5.8
angular-bootstrap 2.5.0 (aka bootstrap-ui)
bootstrap 3.3.7 (only css!!! not js, because js is provided by the above)
Update:
I've created a plunkr and a GIF:
https://plnkr.co/edit/mxDLAdnrQ4p0KKyw?p=info
<div class="modal-body">
<div class="form-group">
<label for="">Foo</label>
<input type="text" class="form-control input-sm" ng-model="foo">
<p>Do this: select the text from right to left and release the mouse outside the modal.</p>
</div>
</div>
GIF:
Update 2
I have new information! This started happening after the last Goole Chrome update! I tried with another computer that had the previous version of Chrome and the modal doesn't close.
//prevent modal close when click starts in modal and ends on backdrop
$(document).on('mousedown', '.modal', function(e){
window.clickStartedInModal = $(e.target).is('.modal-dialog *');
});
$(document).on('mouseup', '.modal', function(e){
if(!$(e.target).is('.modal-dialog *') && window.clickStartedInModal) {
window.preventModalClose = true;
}
});
$("#modal").on("hide.bs.modal", function (e) {
if(window.preventModalClose){
window.preventModalClose = false;
return false;
}
});
The original repository has been archived and no contributions are accepted.
I forked a version and added my fixes for those who are interested:
https://github.com/peteriman/bootstrap
The comparison below:
https://github.com/angular-ui/bootstrap/compare/master...peteriman:modal-patch
= // moved from template to fix issue #2280
- element.on('click', scope.close);
+ var ignoreClick = false;
+ element.on('mousedown', function(evt1) {
+ element.one('mouseup', function(evt2) {
+ if (evt1.target !== evt2.target)
+ ignoreClick = true;
+ });
+ });
+ element.on('click', function(){
+ if (ignoreClick) ignoreClick = false;
+ else scope.close.apply(this, arguments);
+ });
As mousedown and mouseup events trigger before click event, the code checks if mousedown and mouseup are on the same element. If on different elements, it sets ignoreClick=true for the click event to not trigger.
Maintains backward compatibility for click event for existing codes that calls element.click() programmatically.
Original problem:
https://plnkr.co/edit/mxDLAdnrQ4p0KKyw?p=info&preview
Solution by me: (plkr, modal.js, line 103-114)
https://plnkr.co/edit/V42G9NcTUnH9n9M4?p=info&preview
I updated only the code referring to "Modal.js" in bootstrap.js and bootstrap.min.js
Corrected version:
* Bootstrap: modal.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#modals
bootstrap.js print
Yes, this started happening again after the last Goole Chrome update Version 74.0.3729.169, is this a bug with Chrome we can't fix and that we'll just have to wait for a Chrome update for it to be resolved?
or a bootstrap maintainer will update the code for fixing this?
Issue url: https://github.com/twbs/bootstrap/issues/28844
This problem is not recent is already mentioned on github
https://github.com/angular-ui/bootstrap/issues/5810
the following solution works very well with small improvements if necessary.
$rootScope.$watch(() => document.querySelectorAll('.modal').length, val => {
//everytime the number of modals changes
for (let modal of document.querySelectorAll('.modal')) {
if ($uibModalStack.getTop().value.backdrop !== 'static') { // Testing if the
modal is supposed to be static before attaching the event
modal.addEventListener('mousedown', e => {
if (e.which === 1) {
$uibModalStack.getTop().key.dismiss()
}
})
modal.querySelector('.modal-content').addEventListener('mousedown', e => {
e.stopPropagation()
})
}
}
if (val > 0) {
$uibModalStack.getTop().value.backdrop = 'static'
}
})
Another solution on the same principle that keeps the draggrable footer and header of the modal
$rootScope.$watch(function () {
return $document.find('.modal').length;
}, function (val) {
if(openedWindows.top() ) {
var modal = $document.find('.modal');
angular.forEach(modal, function(value) {
if ($modalStack.getTop().value.backdrop !== 'static') {
value.addEventListener('mousedown', function (e) {
if (value === e.target && e.which === 1 && openedWindows.top()) {
$modalStack.getTop().key.dismiss();
}
});
}
});
if (val>0) {
$modalStack.getTop().value.backdrop = 'static';
}
}
});
I'm using Bootstrap v3.0.0 and ran into the same problem. In the end, I had to change a click event to a mousedown event.
In my bootstrap.js file, under the modal.js section, I changed this.$element.on('click.dismiss.modal', $.proxy(function (e) to this.$element.on('mousedown.dismiss.modal', $.proxy(function (e). and everything appears to be working. You may also have to change this in the bootstrap.min.js file.
Note, this will immediately close the modal on mouse down of backdrop so if for some reason you want a user to be able to click down on the backdrop, then drag the mouse and release on the modal, this will not work.
Have you tried using backdrop: 'static'. I think that should do the trick. It is present in the documentation here
Add css padding around modal window and resize it larger. Click outside still works but releasing mouse while dragging over the edge won't close it.
I had a similar situation with range slider. leaving click during slide outside the modal closes it. so I removed data-toggle="modal" and data-target="#mymodal" and added a click event with extra parameters
jQuery('button#modal_toggler').click(function(){
jQuery('#myModal').modal({
backdrop: 'static',
keyboard: false
})
})
backdrop to disable modal close on clicking outside
keyboard this is for my scenario, to disable keyboard entry for closing modal
I have figured out different way to solve the problem, idk if it will cause a problem later but anyway it works, so basically, I put modal-dialog to another <div> object (I call it modal-helper) and then put it to modal. The modal-helper element width and height are inherited (100%) as default but there is small space on top so you can use some margin and padding to close it.
<div class="modal fade" id="login-modal" tabindex="-1" aria-labelledby="loginModalLabel" style="display: none;" aria-hidden="true">
<div id="modal-helper" style="pointer-events: auto;">
<div class="modal-dialog">
...
</div>
</div>
</div>
Then I have used some JS to hide modal when modal-helper (as backdrop) is clicked (by the 'clicked' I mean when pointerup event triggered after pointerdown event on modal-helper).
The code below sets the value of isPointerDownToModalHelper true when pointerdown event triggered on modal-helper, then when the pointerup event triggered on any object it hides the modal and sets the value of isPointerDownToModalHelper back to false:
var login_modal_helper = document.getElementById('modal-helper')
var isPointerDownToModalHelper = false;
addEventListener('pointerdown', (event) => {
var objectID = event['path']['0']['id'];
if (objectID === login_modal_helper.id) { // if pointer was over modal-helper
isPointerDownToModalHelper = true;
}
});
addEventListener('pointerup', (event) => {
if (isPointerDownToModalHelper === true) {
isPointerDownToModalHelper = false;
$('#login-modal').modal('hide'); // hide the modal
}
});
It seems to work fine for now, I hope it can help someone :).

how to toggle medium editor option on click using angularjs

I am trying to toggle the medium editor option (disableEditing) on button click. On the click the value for the medium editor option is changed but the medium editor does not use 'updated' value.
AngularJS Controller
angular.module('myApp').controller('MyCtrl',
function MyCtrl($scope) {
$scope.isDisableEdit = false;
});
Html Template
<div ng-app='myApp' ng-controller="MyCtrl">
<span class='position-left' medium-editor ng-model='editModel' bind-options="{'disableEditing': isDisableEdit, 'placeholder': {'text': 'type here'}}"></span>
<button class='position-right' ng-click='isDisableEdit = !isDisableEdit'>
Click to Toggle Editing
</button>
<span class='position-right'>
toggle value - {{isDisableEdit}}
</span>
</div>
I have created a jsfiddle demo.
I think initialising medium editor on 'click' could solve the issue, but i am not sure how to do that either.
using thijsw angular medium editor and yabwe medium editor
For this specific use case, you could try just disabling/enabling the editor when the button is clicked:
var editor = new MediumEditor(iElement);
function onClick(event) {
if (editor.isActive) {
editor.destroy();
} else {
editor.setup();
}
}
In the above example, the onClick function is a handler for that toggle button you defined.
If you're just trying to enable/disable the user's ability to edit, I think those helpers should work for you.
MediumEditor does not currently support changing configuration options on an already existing instance. So, if you were actually trying to change a value for a MediumEditor option (ie disableEditing) you would need to .destroy() the previous instance, and create a new instance of the editor:
var editor = new MediumEditor(iElement),
editingAllowed = true;
function onClick(event) {
editor.destroy();
if (editingAllowed) {
editor = new MediumEditor(iElement, { disableEditing: true });
} else {
editor = new MediumEditor(iElement);
}
editingAllowed = !editingAllowed;
}
Once instantiated, you can use .setup() and .destroy() helper methods to tear-down and re-initialize the editor respectively. However, you cannot pass new options unless you create a new instance of the editor itself.
One last note, you were calling the init() method above. This method is not officially supported or documented and it may be going away in future releases, so I would definitely avoid calling that method if you can.
Or you could just use this dirty hack : duplicate the medium-editor element (one with disableEditing enabled, the other with disableEditing disabled), and show only one at a time with ng-show / ng-hide :)
<span ng-show='isDisableEdit' class='position-left' medium-editor ng-model='editModel' bind-options="{'disableEditing': true ,'disableReturn': isDisableEdit, 'placeholder': {'text': 'type here'}}"></span>
<span ng-hide='isDisableEdit' class='position-left' medium-editor ng-model='editModel' bind-options="{'disableEditing':false ,'disableReturn': isDisableEdit, 'placeholder': {'text': 'type here'}}"></span>
You can see jsfiddle.

Why is my click event called twice in jquery?

Why is my click event fired twice in jquery?
HTML
<ul class=submenu>
<li><label for=toggle><input id=toggle type=checkbox checked>Show</label></li>
</ul>
Javascript
$("ul.submenu li:contains('Show')").on("click", function(e) {
console.log("toggle");
if ($(this).find("[type=checkbox]").is(":checked")) console.log("Show");
else console.log("Hide");
});
This is what I get in console:
toggle menu.js:39
Show menu.js:40
toggle menu.js:39
Hide menu.js:41
> $("ul.submenu li:contains('Show')")
[<li>​ ]
<label for=​"toggle">​
<input id=​"toggle" type=​"checkbox" checked>​
"Show"
</label>​
</li>​
If I remember correctly, I've seen this behavior on at least some browsers, where clicking the label both triggers a click on the label and on the input.
So if you ignore the events where e.target.tagName is "LABEL", you'll just get the one event. At least, that's what I get in my tests:
Example with both events | Source
Example filtering out the e.target.tagName = "LABEL" ones | Source
I recommend you use the change event on the input[type="checkbox"] which will only be triggered once. So as a solution to the above problem you might do the following:
$("#toggle").on("change", function(e) {
if ($(this).is(":checked"))
console.log("toggle: Show");
else
console.log("toggle: Hide");
});
https://jsfiddle.net/ssrboq3w/
The vanilla JS version using querySelector which isn't compatible with older versions of IE:
document.querySelector('#toggle').addEventListener('change',function(){
if(this.checked)
console.log('toggle: Show');
else
console.log('toggle: Hide');
});
https://jsfiddle.net/rp6vsyh6/
This behavior occurs when the input tag is structured within the label tag:
<label for="toggle"><input id="toggle" type="checkbox" checked>Show</label>
If the input checkbox is placed outside label, with the use of the id and for attributes, the multiple firing of the click event will not occur:
<label for="toggle">Show</label>
<input id="toggle" type="checkbox" checked>
I found that when I had the click (or change) event defined in a location in the code that was called multiple times, this issue occurred. Move definition to click event to document ready and you should be all set.
Not sure why this wasn't mentioned. But if:
You don't want to move the input outside of the label (possibly because you don't want to alter the HTML).
Checking by e.target.tagName or even e.target doesn't work for
you because you have other elements inside the label
(in my case it had spans holding an SVG with a path so e.target.tagName sometimes showed SVG and other times it showed PATH).
You want the click handler to stay on the li (possibly because you have
other items in the li besides the checkbox).
Then this should do the trick nicely.
$('label').on('click', function(e) {
e.stopPropagation();
});
$('#toggle').on('click', function(e) {
e.stopPropagation();
$(this).closest('li').trigger('click');
});
Then you can write your own li click handler without worrying about events being triggered twice. Personally, I prefer to use a data-selected attribute that changes from false to true and vice versa each time the li is clicked instead of relying on the input's value:
$('ul.submenu li').on('click', function() {
let _li = $(this),
ticked = _li.attr('data-selected');
ticked = (ticked === 'false') ? true : false;
_li.attr('data-selected', ticked);
_li.find('#toggle').prop('checked', ticked);
});

Add class to DIV if checkbox is checked onload

I need help with a script to add an "active" class to a div when a hidden checkbox is checked. This all happening within a somewhat complex form that can be saved and later edited. Here's the process:
I have a series of hidden checkboxes that are checked when a visible DIV is clicked. Thanks to a few people, especially Dimitar Christoff from previous posts here, I have a few simple scripts that handle everything:
A person clicks on a div:
<div class="thumb left prodata" data-id="7"> yadda yadda </div>
An active class is added to the div:
$$('.thumb').addEvent('click', function(){
this.toggleClass('tactive');
});
The corresponding checkbox is checked:
document.getElements("a.add_app").addEvents({
click: function(e) {
if (e.target.get("tag") != 'input') {
var checkbox = document.id("field_select_p" + this.get("data-id"));
checkbox.set("checked", !checkbox.get("checked"));
}
}
});
Now, I need a fourth ( and final ) function to complete the project (using mootools or just plain javascript, no jQuery). When the form is loaded after being saved, I need a way to add the active class back to the corresponding div. Basically reverse the process. I AM trying to figure it out myself, and would love to post an idea but anything I've tried is, well, bad. I thought I'd at least get this question posted while I work on it. Thanks in advance!
window.addEvents({
load: function(){
if (checkbox.checked){
document.getElements('.thumb').fireEvent('click');
}
}
});
Example: http://jsfiddle.net/vCH9n/
Okay, in case anyone is interested, here is the final solution. What this does is: Create a click event for a DIV class to toggle an active class onclick, and also correlates each DIV to a checkbox using a data-id="X" that = the checkbox ID. Finally, if the form is reloaded ( in this case the form can be saved and edited later ) the final piece of javascript then sees what checkboxes are checked on page load and triggers the active class for the DIV.
To see it all in action, check it out here: https://www.worklabs.ca/2/add-new/add-new?itemetype=website ( script is currently working on the third tab, CHOOSE STYLE ). You won't be able to save/edit it unless you're a member however, but it works:) You can unhide the checkboxes using firebug and toggle the checkboxes yourself to see.
window.addEvent('domready', function() {
// apply the psuedo event to some elements
$$('.thumb').addEvent('click', function() {
this.toggleClass('tactive');
});
$$('.cbox').addEvent('click', function() {
var checkboxes= $$('.cbox');
for(i=1; i<=checkboxes.length; i++){
if(checkboxes[i-1].checked){
if($('c_'+checkboxes[i-1].id))
$('c_'+checkboxes[i-1].id).set("class", "thumb tactive");
}
else{
if($('c_'+checkboxes[i-1].id))
$('c_'+checkboxes[i-1].id).set("class", "thumb");
}
}
});
// Add the active class to the corresponding div when a checkbox is checked onLoad... basic idea:
var checkboxes= $$('.cbox');
for(i=1; i<=checkboxes.length; i++){
if(checkboxes[i-1].checked){
$('c_field_tmp_'+i).set("class", "thumb tactive");
}
}
document.getElements("div.thumb").addEvents({
click: function(e) {
if (e.target.get("tag") != 'input') {
var checkbox = document.id("field_tmp_" + this.get("data-id"));
checkbox.set("checked", !checkbox.get("checked"));
}
}
});
});

Resources