I would like to see if anyone in the community can improve on this code.
GOAL: The application is full of input elements that are styled up to look like custom buttons. They are of various types e.g. 'submit', 'reset' and 'button'. When the user hits the button (i.e. clicks it with their mouse on PC or touches the screen on the right place on a touch-screen device e.g. BlackBerry) the button text and background should change to indicate the button has been pushed. The text and background should revert before the action associated with the button is executed - to indicate the button has been released.
Here is the snippet of the code that I have for my solution - can anyone see ways to improve/slim/refactor?
<script type="text/javascript">
$(document).ready(function () {
RegisterJQueryFunctions();
});
</script>
In an external file:
function RegisterJQueryFunctions() {
$('input[type=submit], input[type=button], input[type=reset]').mousedown(function () {
// Record the original font and BG colors so we can revert back to them in 'delight'
var originalFont = $(this).css("color");
var originalBG = $(this).css("background-color");
$(this).data("originalFont", originalFont);
$(this).data("originalBG", originalBG);
$(this).highlightBG();
$(this).highlightFont();
});
$('input[type=submit], input[type=button], input[type=reset]').mouseup(function () {
$(this).revertFont();
$(this).revertBG();
});
$.fn.highlightFont = function (highlightFontColor) {
var highlightFont = highlightFontColor || "#FFFFFF"; // Defaults to white
$(this).css("color", highlightFont);
};
$.fn.highlightBG = function (highlightBGColor) {
var highlightBg = highlightBGColor || "#FF7F00"; // Defaults to orange
$(this).css("background-color", highlightBg);
};
$.fn.revertFont = function () {
var originalFont = $(this).data("originalFont");
if (!originalFont.length)
originalFont = "#000000"; // Defaults to black in case data attribute wasn't set properly in highlightFont
$(this)
.css("color", originalFont);
};
$.fn.revertBG = function () {
var originalBG = $(this).data("originalBG");
if (!originalBG.length)
originalBG = "#FEC800"; // Defaults to orange in case data attribute wasn't set properly in highlightFont
$(this)
.css("background-color", originalBG);
};
}
This is how you would do it with CSS. If you want the pressed look to be the following CSS
.pressed { color : #ffffff; background-color : #FEC800; }
Then your functions are simple:
function RegisterJQueryFunctions() {
$('input[type=submit], input[type=button], input[type=reset]')
.mousedown(function () { $(this).toggleClass("pressed",true); })
.mouseup(function () { $(this).toggleClass("pressed",false); });
}
You can have different pressed looks for different input types (using standard CSS selectors).
You are separating the styling from the code (always a good thing.)
Using CSS (class), you can reduce the size of your code drastically. Secondly CSS will give the option of changing colors without altering your javascript (Themes). The sole purpose of CSS is to give look and feel to the site & for javascript, add dynamic behavior to the site.
Hope this helps.
If you're using the same jQuery selector several times you should cache the
first jQuery object returned and reuse it
If you're calling several jQuery methods on the same jQuery object you can chain them
I dislike single-use variables: if a variable is only assigned a value in one
place and that value is only used in one (other) place then you don't need it
If setting more than one value with .data() (or .attr() or in several other jQuery methods) you can do all with a single call by putting the properties in a map
So:
function RegisterJQueryFunctions() {
$('input[type=submit], input[type=button], input[type=reset]').mouseup(function () {
$(this).revertFont().revertBG();
})
.mousedown(function () {
// Record the original font and BG colors so we can revert back to them in 'delight'
var $this = $(this);
$this.data({"originalFont" : $this.css("color"),
"originalBG" :, $this.css("background-color")
})
.highlightBG()
.highlightFont();
});
$.fn.highlightFont = function (highlightFontColor) {
$(this).css("color", highlightFontColor || "#FFFFFF");// Defaults to white
};
$.fn.highlightBG = function (highlightBGColor) {
$(this).css("background-color", highlightBGColor || "#FF7F00";);
};
$.fn.revertFont = function () {
var $this = $(this);
// Defaults to black in case data attribute wasn't set properly in highlightFont
$this.css("color", $this.data("originalFont") || "#000000");
};
$.fn.revertBG = function () {
var $this = $(this);
// Defaults to orange in case data attribute wasn't set properly in highlightFont
$this.css("background-color", $this.data("originalBG") || "#FEC800");
};
}
Using a combination of the above advice, this is the solution is ended up with:
$('input[type=submit], input[type=button], input[type=reset]')
.mousedown(function () { $(this).toggleClass("pressed", true); })
.mouseup(function () { $(this).toggleClass("pressed", false); })
.focusout(function () { $(this).toggleClass("pressed",false); });
$('a,a>*')
.mousedown(function () { $(this).toggleClass("pressed",true); })
.mouseup(function () { $(this).toggleClass("pressed", false); })
.focusout(function () {
$(this).toggleClass("pressed", false);
$(this).children().toggleClass("pressed", false); // call explictily because some elements don't raise the 'focusout' event
});
Related
I am using the jQuery plugin radiosToSlider (http://rubentd.com/radios-to-slider/) and need to make sure that all radio button groups are checked and to give an alert when they are
I can do this if they are just radio buttons by checking the length but because the plugin changes the input buttons I am having difficulties
My fiddle is
http://jsfiddle.net/yFaAj/270/
$(document).ready(function () {
$(".radios").radiosToSlider();
});
$(":radio").change(function () {
var names = {};
$(':radio').each(function () {
names[$(this).attr('name')] = true;
});
var count = 0;
$.each(names, function () {
count++;
});
if ($(':radio:checked').length === count) {
alert("all answered");
}
}).change();
thanks
The problem isn't that the plugin changes your structure (although it does add some ins elements, which I don't agree with), it's that the plugin doesn't fire a change event for the converted radio controls, and setting the checked property interactively doesn't appear to do so either.
Since the plugin author doesn't publish an API for this use case, it's hard to know whether this is by design or oversight, but the source code definitely doesn't fire the event when the slider is clicked:
this.bearer.find('.slider-level').click( function(){
var radioId = $(this).attr('data-radio');
slider.bearer.find('#' + radioId).prop('checked', true);
slider.setSlider();
});
Your options, as I see them:
Contact the API author and ask for a bug fix, or the intended way to support this case
Downside: Time: dependent on the author to respond
Attach your "check" function to the click event of the .slider-level class, as the API does.
Downside: Brittle: future versions of the plugin may attach the behavior to different selectors
Attach your function to the click event of your radio group, and catch click events on the bubble
Downside: Inefficient: It will check for every click in the radio control
Here's a sample implementation of option 3. DEMO.
$(document).ready(function () {
$(".radios").radiosToSlider();
});
var makeIsRadioGroupChecked = function(selector) {
var $radioGroup = $(selector);
return function isRadioGroupChecked() {
return $radioGroup.find(':checked').length > 0;
};
};
var isOptionsChecked = makeIsRadioGroupChecked('#optionsRadioGroup');
var isSizeChecked = makeIsRadioGroupChecked('#sizeRadioGroup');
var areAllGroupsChecked = function() {
return isOptionsChecked() && isSizeChecked();
};
var alertIfAllGroupsChecked = function() {
if (areAllGroupsChecked()) {
alert("all answered");
}
};
$('.radios').on('click', alertIfAllGroupsChecked);
I am trying to create a tagging system just like SO has.
I have added the tags,now I want to remove them.
MyQuestion:
How do I remove the tags appended?
how do I make the cross button(a span) look identical to that in SO tagging system?
SO TAGGING
var tags = [];
$("#textBox").keypress(function (e) {
if (e.which === 13) {
$(".target").append("X</span>'+ "");
function remove_tag(){
//what to do here?
}
tags.push(this.value);
this.value = "";
}
});
Here's my JSFiddle: http://jsfiddle.net/Wky2Z/11/
Basically, listen on the .cross to be clicked, and then remove from array and delete element
//enter something in textbox and press enter....
var tags = [];
$("#textBox").keypress(function (e) {
if (e.which === 13) {
$(".target").append("X</span>'+ "");
tags.push(this.value);
this.value = "";
}
});
$('body').on('click','.cross',function(){
tags.splice($(this).parent('a').html(), 1);
$(this).parent('a').remove();
});
As for the look of the cross, SO use a CSS Sprite, so you can do the same by making a png or gif or jpeg of the two states, off(grey) and hover(red) and switch the background-position to red with css eg: .cross:hover { background-position:0px -20px }
You can delete elements making use of remove().
Also, i would recommend you to make use of jQuery events instead of using inline events. (if you take a look at the source code of stackoverflow you will notice there are no inline javascript calls)
In this case you would need to add an event handler to the document object as you want to assign the events to elements which are not loaded in the DOM from the start.
$(document).on('click', '.tag span', function(){
$(this).parent().remove();
});
Living example: http://jsfiddle.net/Wky2Z/7/
Update
I updated the example removing the element from the list of tags too:
http://jsfiddle.net/Wky2Z/8/
Added a data-value for the tag links:
$(".target").append("X</span>'+ "");
And modified the click event:
$(document).on('click', '.tag span', function(){
$(this).parent().remove();
var removeItem = $(this).parent().data('value');
tags = $.grep(tags, function(value) {
return value != removeItem;
});
});
For a full jQuery solution you can remove the inline remove_tag function and use jQuery on function. it works for dynamically created elements too.
Attach an event handler function for one or more events to the
selected elements.
Here you can get the parent element of the deleted element and remove it from the DOM using remove.
To "sync" the array with the current situation you can use grep to delete the item from the array; note the removedItem variable used to get the text only of the parent excluding the children from the text.
Code:
//enter something in textbox and press enter....
var tags = [];
$(document).ready(function () {
$('body').on('click', 'span.cross', function () {
var removedItem = $(this).parent().contents(':not(span)').text();
$(this).parent().remove();
tags = $.grep(tags, function (value) {
return value != removedItem;
});
});
$("#textBox").keypress(function (e) {
if (e.which === 13) {
$(".target").append("X</span>' + "");
tags.push(this.value);
this.value = "";
}
});
});
Demo: http://jsfiddle.net/IrvinDominin/pDFnG/
Here's the updated link: http://jsfiddle.net/Wky2Z/6/
Move remove_tag outside of keypress event handle and pass a this pointer to it for quick solution:
//enter something in textbox and press enter....
var tags = [];
function remove_tag(x) {
$(x).parent('a').remove();
}
$(function () {
$("#textBox").keypress(function (e) {
if (e.which === 13) {
$(".target").append("X</span>' + "");
tags.push(this.value);
this.value = "";
}
});
});
I simply want to have a variable toggle between true and false and have the text on the button clicked to change as well. Here is my Jquery:
$("button").toggle(
function () {
$(this).text("Click to change to paint brush");
var erasing = true;
},
function () {
$(this).text("Click to change to eraser");
var erasing = false;
}
);
This looks 100% sound to me, but in my jsfiddle you will see that it is toggling the existence of the button before I can even click it! Why is this happening and how can I fix it?
This version of toggle has been deprecated (1.8) and removed (1.9). Now you need to handle it in button click itself.
Somthing like this:
var erasing = false;
$("button").click(function () {
erasing = !erasing;
$(this).text(function (_, curText) {
return curText == "Click to change to paint brush" ? "Click to change to eraser" : "Click to change to paint brush" ;
});
console.log(erasing);
});
Fiddle
Plus if you want to preserve the value of the variable just define them out of the click event scope, so that it is more global to be accessed outside.
See
.toggle
.text(func) syntax
Deprecated toggle
Thank you all for explaining how toggle is out of date...so that is all I needed and then I solved my problem with a simple if statement:
var erasing = false;
var i = 0
$("button").click(function () {
if(i%2==0){
$(this).text("Click to change to paint brush");
erasing = true;
}
else{
$(this).text("Click to change to eraser");
erasing = false;
};
i += 1
});
jsfiddle
As PSL said, the toggle you're looking for is gone and lost. if you want a click and hold solution (as your title suggests), you could look at using mouseup and mousedown.
var erasing;
$("button").on({
"mousedown": function () {
$(this).text("Click to change to paint brush");
erasing = true;
},
"mouseup mouseleave": function () {
$(this).text("Click to change to eraser");
erasing = false;
}
});
Demo : http://jsfiddle.net/hungerpain/ymeYv/6/
I'm programming an online editor. To get character inputs correctly I'm using jQuery.onKeyPress event on a textarea element (getting inputs from the body doesn't work, as characters such as backspace activate certain browser shortcuts - also, some characters are only provided correctly this way). That textarea is hidden by positioning it outside the window (otherwise won't work).
Questions are:
Is there a better design for what I'm doing?
How can I guarantee that this element is never defocused, other than setting a timer to focus it constantly?
To make sure the element is always in focus, use this:
var $textarea = $('textarea');
$textarea.on('blur', function () {
setTimeout(function () {
$textarea.focus();
}, 0);
});
A small variant of the answer above:
html:
<input type="text" id="element">
Jquery
$('#element').on('blur', function () {
_this = this;
setTimeout(function () {
_this.focus();
}, 0);
});
Vanilla (Plain Js)
var theElement = document.getElementById("element");
theElement.addEventListener("focusout", function(){
_this = this;
setTimeout(function () {
_this.focus();
}, 0);
});
I'm hacking a gallery plugin where I want to disable the click event for the thumbnail and replace it with a hover event.
This is what I did: http://jsbin.com/enezol/3
$(function() {
var galleries = $('.ad-gallery').adGallery();
$('.ad-thumb-list a').hover(function() {
$(this).click();
});
$('.ad-thumb-list a').click(function() {
return false;
});
});
The plugin doesn't allow me to set event to use. So Instead of changing it from their code, I'll just add a little tweak on top of it.
So I want to disable the click event for the 'thumbnail' and just use 'hover' event instead.
Any got and ideas? I'm also open to other approach as long as it meets my requirement.
Thank You!
Trying to implement Steph Skardal and Nicosunshine suggestion:
var thumbs = $('.ad-thumb-list a'),
oldfunction = thumbs.data("events").click["function () { context.showImage(i); context.slideshow.stop(); return false; }"];
thumbs.unbind("click").hover(oldFunction);
edit: My Solution:
I use return false to restrict it from going to the url but it does not restrict in calling the function. Any alternative ideas?
var galleries = $('.ad-gallery').adGallery();
var thumbs = $('.ad-thumb-list a');
thumbs .hover(
function () {
$(this).click();
},
function () {
}
);
thumbs.click( function () { return false; });
You want to use jQuery's unbind method, to unbind the click event. It will have to be called after the plugin is called. E.g.:
$('.ad-thumb-list a').unbind('click');
You could try to unbind the click method and then bind the original function to the hover.
If you can't get the original function you can get it by seeing what the console returns if you throw:
$('.ad-thumb-list a').data("events").click; //name of the property that has the function
then you grab that function and do:
var thumbs = $('.ad-thumb-list a'),
oldfunction = thumbs.data("events").click["theValueYouGotInTheConsole"];
thumbs.unbind("click")
.hover(oldFunction);
Edit:
Here is an example of what I ment with "theValueYouGotInTheConsole", in the image I'm accessing the click property, and then the "4" is where the function is stored.
If you don't want to hardcode the value you can do:
var dataEvents = thumbs.data("events").click,
oldFunction;
for(var functionEvent in dataEvents) {
oldFunction = dataEvents[functionEvent];
break; //I'm assuming there's only one event
}