CanJS right click event - javascript

how can I bind a right click event in CanJS?
I've attempted the following, but I guess click only captures left clicks (as ev.which doesn't log 3 on right clicks).
'.btn click': function (el, ev) {
console.log(ev.which);
switch(ev.which) {
case 1:
var val = 1;
break;
case 3:
ev.preventDefault();
var val = -1;
break;
}
var item = can.data(el.closest('tr'), 'item');
item.attr('rel', item.rel + val);
}

I don't know what CanJS is, but I would use oncontextmenu:
elem.oncontextmenu = function(e) {
e = e || window.event;
if(e.preventDefault) e.preventDefault();
e.returnValue = false;
// Your code
};

I think you were looking for contextmenu event: https://developer.mozilla.org/en/docs/Web/Events/contextmenu
You can use this in CanJS events:
'.btn contextmenu': function (el, ev) {
// your code
}

Related

Javascript Tab keydown when pressed and hold tab, it flickers infinitely

I have written some simple keydown event handler on a group of inputs, like such
$('.a, .b, .c').on('keydown', function (e) {
switch(keycode) {
case 9:
e.preventDefault();
e.stopPropagation();
if($('.a'))
// focus next
else if($('.b'))
// focus next
....
break;
}
})
However when I press the tab and hold, the cursor flickers infinitely and the event does not fire anymore, I have to focus outside the window and comeback for it to stop.
Have been trying to figure it out for many a days now, can anyone shine some light on how do I stop this behaviour?
Ok guys i have edited the code and reproduced the error in which i found out the mistake and fixed the issue.. Here is the code producing the effect.
$(document).ready(function(){
$('.c, .d').on('focus', function (e) {
if (e.relatedTarget) {
var v = $(this).val();
var n = v.toString().replace(/,/g, "");
$(this).val(n);
var $elementThis = $(this);
setTimeout(function () { $elementThis.select(); }, 50);
}
});
$('.a, .b').on('focus', function (e) {
if (e.relatedTarget) {
var $elementThis = $(this);
setTimeout(function () { $elementThis.select(); }, 50);
}
});
$('.a, .b, .c, .d').on('keydown', function(e) {
var keycode = e.charCode || e.keyCode || 0;
switch (keycode) {
case 9:
{
e.preventDefault();
e.stopImmediatePropagation();
if ($(this).hasClass('a')) { $('.b').focus(); }
else if ($(this).hasClass('b')) { $('.c').focus(); }
else if ($(this).hasClass('c')) { $('.d').focus(); }
else if ($(this).hasClass('d')) { $('.a').focus(); }
break;
}
}
})
});
The part that is giving me the problem is the
setTimeout(function () { $elementThis.select(); }, 50);
causing it to flicker non-stop.
I am finding an alternative to it. Any suggestions are welcome.
And please remove the downvote. I hope this insight will be of help to someone in the future.
You have a mistake. It should be e.keyCode:
$('.a, .b, .c').on('keydown', function (e) {
switch(e.keyCode) { // Change this. Also better to check if `e.which`
case 9:
e.preventDefault(); // Change this
e.stopPropagation();
if($('.a'))
;//focus next
else if($('.b'))
;//focus next
....
break;
}
});
The full version:
$('.a, .b, .c').on('keydown', function (e) {
var charCode = e.which || e.keyCode;
switch(charCode) {
case 9:
e.preventDefault();
e.stopPropagation();
if($('.a'))
;//focus next
else if($('.b'))
;//focus next
....
break;
}
});
key code should be accessed like this e.keyCode
$('.a, .b, .c').on('keydown', function (e) {
switch(e.keyCode)
{
case 9:
e.preventDefault();
e.stopPropagation();
if($('.a'))
//focus next
else if($('.b'))
//focus next
....
break;
}
})

Prevent spaces in input field on keypress event

I'm using the following code to detect multiple keys on a keypress event:
var down = [];
$(document).keydown(function (e) {
down[e.keyCode] = true;
}).keyup(function (e) {
if (down[17] && down[32]) {
// Do something
}
down[e.keyCode] = false;
});
However, this hotkey (CTRL + SPACE) is meant to be used while an input field has focus. So whenever I press the key combination, it also adds a space to the input field.
How can I prevent this from happening? I've looked at ways to disable spaces in input (like this), but I can't figure out how to make it work inside my keypress event only.
You may try this. I hope it helps.
var down = [];
$(document).keydown(function (e) {
down[e.keyCode] = true;
}).keypress(function (e) {
if (down[17] && down[32]) {
var $sampleTextBox = $("input#sampleTextBox");
$sampleTextBox.val($sampleTextBox.val().replace(/\s/g, ''));
alert($sampleTextBox.val().length)
alert("Ctrl + Space Pressed!");
}
down[e.keyCode] = false;
}).keyup(function (e) {
if (down[17] && down[32]) {
var $sampleTextBox = $("input#sampleTextBox");
$sampleTextBox.val($sampleTextBox.val().replace(/\s/g, ''));
alert($sampleTextBox.val().length)
alert("Ctrl + Space Pressed!");
}
down[e.keyCode] = false;
});
--
Thanks,
SuperCoder
I ended up using a different approach, as MelanciaUK suggested.
On the keyup event, it removes the last character in the input field.
var down = [];
$(document).keydown(function (e) {
down[e.keyCode] = true;
}).keyup(function (e) {
if (down[17] && down[32]) {
// Do something
input = $(':focus');
input.val(function (index, value) {
return value.substr(0, value.length - 1);
});
}
down[e.keyCode] = false;
});
While it doesn't prevent the space from being added, it removes it immediately.

How can I disable mouse hover effect when user is using keyboard?

I'm trying to implement a search as you type feature on my site. I'm working on the front-end side right now and using mockjax to pull in fake data.
My problem: When the drop down menu pops up you have the option to go over your choices (which highlight in yellow). I realized today though that if your using the arrow keys to scroll through your choices and move your mouse over the menu then it will cause two options to be highlighted! I don't want to confuse my users so I only want it to highlight one at a time. If they are using their keyboard and hover over with the mouse than the keyboard selection would jump to where the mouse is.
(In case I'm not being clear and you need an example, go to amazon and use their search with your arrow keys and then hover the mouse over an option, it changes. I want it like that!)
Most of the html, css and mockjax can't be included in this fiddle so it looks funky- but just case someone needs to see my code.
http://jsfiddle.net/2JGHu/
(function (Backbone, _, context) {
"use strict";
var SuggestiveSearch = Backbone.View.extend({
tracking: function (action, label) {
_gaq.push(['_trackEvent', 'SearchAsYouType2.0', action, label]);
},
fetchTemplate: function (name) {
var callback = _.bind(function (template) {
this.template = tmpl(template);
}, this);
$.get("/js/templates/" + name + ".html", callback);
},
close: function () {
this.$suggestionList.addClass("hide");
this.tracking('Close', 'Clicked-Off');
// Reset our list selection index
this.model.set("currentIndex", null);
},
open: function () {
this.$suggestionList.removeClass("hide");
this.tracking('Open', 'Clicked-On');
},
preventCloseHandler: function (e) {
e.stopPropagation();
},
directionSelectionHandler: function (keyCode) {
var currentIndex = this.model.get("currentIndex"),
incr = keyCode === 40 ? 1 : -1,
newIndex = currentIndex + incr,
choicesLen = this.$choices.length - 1,
isOutOfRange = newIndex > choicesLen || newIndex < 0;
// If index is out of range set it either to the first or last choice
if (isOutOfRange) {
newIndex = newIndex < 0 ? choicesLen : 0;
}
// Remove previous selected
// class on li's
this.$choices
.removeClass("is-selected");
this.$choices
.eq(newIndex)
.addClass("is-selected");
// Store our index
this.model.set("currentIndex", newIndex);
},
enterHandler: function (e) {
var currentIndex = this.model.get("currentIndex");
if (currentIndex !== 0) {
this.tracking('Enter', 'Selected-Choice');
window.location = this.$choices.eq(currentIndex).find("a").attr('href');
}
},
keyDownHandler: function (e) {
var keyCode = e.which,
isArrowKeys = keyCode === 40 || keyCode === 38;
if (!isArrowKeys) {
return;
}
e.preventDefault();
},
keyUpHandler: function (e) {
var $input = $(e.currentTarget),
query = $input.val(),
keyCode = e.which;
switch (keyCode) {
case 40:
case 38:
this.directionSelectionHandler(keyCode);
this.tracking('Keyboard navigate', 'Selected-Choice');
e.preventDefault();
break;
case 13:
this.enterHandler(e);
break;
default:
this.model.set("query", query);
}
},
choiceClickHandler: function (e) {
this.tracking('Click', 'Selected-Choice');
e.stopPropagation();
},
render: function () {
this.$suggestionList
.html(this.template(_.pick(this.model.attributes, "ProductSuggestions", "FilterSuggestions")));
// Store our list of choices but also add our already cached input to that collection
this.$choices = this.$suggestionList.find(".autocomplete__choice", this.$el).add(this.$input);
this.open();
},
events: {
"keyup input": "keyUpHandler",
"keydown input": "keyDownHandler",
"click .autocomplete__choice": "choiceClickHandler",
"click": "preventCloseHandler"
},
bindings: function () {
this.listenTo(this.model, "sync", this.render);
$(document).on('click', _.bind(this.close, this));
},
initialize: function () {
this.fetchTemplate("suggestions");
this.$suggestionList = this.$el.find(".autocomplete");
this.$input = this.$el.find("input");
this.bindings();
}
});
context.Views = context.Views || {};
context.Views.SuggestiveSearch = SuggestiveSearch;
}(Backbone, _, =|| {}));
Let me know if I need to include anymore information. Thank you in advance!
Since your JSFiddle doesn't produce the behavior, it's not easy for me to write code that solves your problem, but I can give you advice that might help you do it yourself.
The way I recommend solving this issue is by removing the .hover highlighting in your CSS and implementing a function that adds the class is-selected to an object when it is being hovered over and removing the class from all other elements. That way it will be compatible with your current directionSelectionHandler:

Add a second onChange event?

Hi I found this script online that adds an onChange event to an element and I would like to now add a second onChange event to the same element. Heres the script:
document.getElementById('piname').onchange =
function() {
removeChildren({
parentId: 'account_table',
childName: 'extraaccount'
});
}
And the onChange event i want to add is:
showAccount(this.value)
Use addEventListener() (and attachEvent as a fallback, if needed).
Example:
document.getElementById('piname').addEventListener("change", function(e){
e = e || event;
showAccount(e.target.value);
}, false);
Example, with fallback:
var element = document.getElementById('piname');
if(element.addEventListener){
element.addEventListener("change", function(e){
e = e || event;
showAccount(e.target.value);
}, false);
}
else if(element.attachEvent){
element.attachEvent("onchange", function(e){
e = e || event;
showAccount(e.target.value);
});
}
The simplest way is to cache the old function and call it from the new one:
var el = document.getElementById('piname'),
old = el.onchange;
el.onchange = function () {
old.call(el);
showAccount(this.value);
}
Other than that, you could use addEventListener (W3C standards) and attachEvent (IE8 and lower):
var el = document.getElementById('piname'),
fn = function (e) {
e = e || window.event;
showAccount((e.target || e.srcElement).value);
};
if ("addEventListener" in el) {
el.addEventListener("change", fn, false);
}
else {
el.attachEvent("onchange", fn);
}
Those methods allow you to attach as many handlers to events as you like.

Trying to implement Google's Fast Button

I'm trying to implement Google's Fast button for the mobile touch events, and I seem to be stuck. I'm trying to set it up so that I can make links into fastbuttons, but I can't seem to get my library structure right. What ends up happening is the fastbutton re-inits itself when I try to run a for loop on the links.
I'm sure it's just the way I'm setting up the library. Can someone please check it out?
http://code.google.com/mobile/articles/fast_buttons.html
;(function() {
/*Construct the FastButton with a reference to the element and click handler.*/
this.FastButton = function(element, handler) {
console.log('fastbutton init');
this.element = element;
this.handler = handler;
console.log(this);
element.addEventListener('touchstart', this, false);
element.addEventListener('click', this, false);
};
/*acts as an event dispatcher*/
this.FastButton.prototype.handleEvent = function(event) {
console.log(event);
switch (event.type) {
case 'touchstart': this.onTouchStart(event); break;
case 'touchmove': this.onTouchMove(event); break;
case 'touchend': this.onClick(event); break;
case 'click': this.onClick(event); break;
}
};
/*Save a reference to the touchstart coordinate and start listening to touchmove and
touchend events. Calling stopPropagation guarantees that other behaviors don’t get a
chance to handle the same click event. This is executed at the beginning of touch.*/
this.FastButton.prototype.onTouchStart = function(event) {
event.stopPropagation();
this.element.addEventListener('touchend', this, false);
document.body.addEventListener('touchmove', this, false);
this.startX = event.touches[0].clientX;
this.startY = event.touches[0].clientY;
};
/*When /if touchmove event is invoked, check if the user has dragged past the threshold of 10px.*/
this.FastButton.prototype.onTouchMove = function(event) {
if (Math.abs(event.touches[0].clientX - this.startX) > 10 ||
Math.abs(event.touches[0].clientY - this.startY) > 10) {
this.reset(); //if he did, then cancel the touch event
}
};
/*Invoke the actual click handler and prevent ghost clicks if this was a touchend event.*/
this.FastButton.prototype.onClick = function(event) {
event.stopPropagation();
this.reset();
this.handler(event);
if (event.type == 'touchend') {
console.log('touchend');
//clickbuster.preventGhostClick(this.startX, this.startY);
}
};
this.FastButton.prototype.reset = function() {
this.element.removeEventListener('touchend', this, false);
document.body.removeEventListener('touchmove', this, false);
};
this.clickbuster = function() {
console.log('init clickbuster');
}
/*Call preventGhostClick to bust all click events that happen within 25px of
the provided x, y coordinates in the next 2.5s.*/
this.clickbuster.preventGhostClick = function(x, y) {
clickbuster.coordinates.push(x, y);
window.setTimeout(this.clickbuster.pop, 2500);
};
this.clickbuster.pop = function() {
this.clickbuster.coordinates.splice(0, 2);
};
/*If we catch a click event inside the given radius and time threshold then we call
stopPropagation and preventDefault. Calling preventDefault will stop links
from being activated.*/
this.clickbuster.onClick = function(event) {
for (var i = 0; i < clickbuster.coordinates.length; i += 2) {
console.log(this);
var x = clickbuster.coordinates[i];
var y = clickbuster.coordinates[i + 1];
if (Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
event.stopPropagation();
event.preventDefault();
}
}
};
})(this);
document.addEventListener('click', clickbuster.onClick, true);
clickbuster.coordinates = [];
Try calling the constructor with new?
new FastButton(el, function() {});

Categories

Resources