Recently needed to apply a keyup event to a series of textfields during MooTools domready event, but only have each field’s event execute when that field has the user’s focus.
/**
* Custom MooTools event, restricting firing of the keyUp event to only when the target element has focus.
*
* Usage:
* some_element.addEvent('focusedKeyUp', function(event) {
* console.debug('A key was pressed while the following element has focus: ' + event.target.get('id'));
* });
*/
Element.Events.focusedKeyUp = {
base: 'keyup',
condition: function(event) {
return event.target == $$(event.target.get('tag') + ':focus')[0];
}
};
(Source: gist.github.com)
Though part of the HTML5 Specification, the activeElement attribute is now supported by all major browsers and offers the ability to determine whether an element currently has the user’s focus very easily.
Previously making the determination for which input element currently had focus was done using multiple event handlers applied to all input elements. (Note: The selector below does not include form inputs not based on the <input> tag such as a <select> list)
var current_focus; // Maintains a reference to the currently-focused input
$(document.body).getElements('input').each(function(f){
$(f).addEvents({
'focus': function(){
current_focus = $(this);
},
'blur': function(){
current_focus = false;
}
});
});
//... and later
if (current_focus == $('element-in-question')) {
// The element in question currently has the user's focus
}
Now that most major browsers support activeElement, the test for an input having focus can be done without any event handlers.
if ($(document.activeElement) == $('element-in-question')) {
// The element in question currently has the user's focus
}
Ideally your application’s code will include the old version as a fallback along with the above solution to accommodate all browsers.
When browsing to an anchor within an page, all browsers (that I know of) scroll the page to the anchored element such that the element is at the very top of the visible browser window. This is a problem when a site design includes a fixed element at the top of the browser window. A little bit of Javascript (via MooTools) can fix this:
var AnchorFix = new Class({
Implements: Options,
options: {
fixed_element: null
},
initialize: function(options){
this.setOptions(options);
this.applyTrigger();
},
/**
* Applies the onhashchange event to the window
* to listen for a new anchor being browsed to by the user
*/
applyTrigger: function(){
var fn = window.onhashchange || $empty;
window.onhashchange = function() {
fn();
this.reScrollWindow();
}.bind(this);
},
/**
* Calculates the proper scroll point for the window based
* on the height of the fixed element at the top of the page,
* allowing the anchored element to be visible under the fixed
* element
*/
reScrollWindow: function(){
var hash = window.location.hash.trim().substring(1);
var element = ($(hash) != null) ? $(hash) : $(document.body).getElement('*[name="' + hash + '"]');
if (element != null) {
var position_y = element.getPosition().y;
var bar_height = $(this.options.fixed_element).getSize().y
window.scrollTo(0, (position_y - bar_height - 5));
}
}
});
// Instantiate a new instance of the class to get started
var fixMyAnchors = new AnchorFix({$('idOfTheFixedElement')});
Not all browsers support the Javascript onhashchange event (read: IE7 and earlier). A bit of the applyTrigger() code above was modified from MooHistory, and with a bit of tweaking if desired, support could be added to the code above for earlier versions of IE (check out their source to see how they handle IE6/7).
arguments is a local object variable available within any function in JavaScript. Arguments can be accessed as shown in foo() below.
function foo(){
console.debug(arguments); // ['a', 'b']
console.debug(arguments[0]); // 'a'
}
foo('a', 'b');
This is convenient for functions that may need to accept an arbitrary number of parameters. But if these arguments need to again be passed on to a 2nd function from within the first, a problem arises:
function foo(){
// ...
bar(arguments);
}
function bar(){
console.debug(arguments[0]); // ['a', 'b']
console.debug(arguments[1]); // undefined
// ...
}
foo('a', 'b');
Notice that arguments[0] in bar() above now contains an array of the arguments passed to foo(), while arguments[1] is undefined. MooTools has an
.attempt function prototype (See the documentation) that fixes this issue.
function foo(){
// ...
bar.attempt(arguments); # Call bar() using MooTools attempt()
}
function bar(){
console.debug(arguments[0]); // 'a'
console.debug(arguments[1]); // 'b'
// ...
}
foo('a', 'b');
Looking at MooTools 1.3b1.1 Source, the arguments are passed to the requested function using apply() (See the documentation).
In MooTools the $() is used in part to ensure the element passed to $() is extended by MooTools. Clientcide points out a great tip with the native Class toElement() function.
Aside from the benefits from the use of this from outside of a class passing an instance variable to $(), I like to use toElement() in combination with $(this) from within my Class objects simply for brevity.
var someClass = new Class({
Implement: [Options],
options: {
domReference: null
},
initialize: function(options){
this.setOptions(options);
// Here, $(this) will reference this.options.domReference :)
$(this).setStyle('background-color', '#F00');
}
toElement: function(){
return this.options.domReference;
}
});
var someInstance = new someClass({
domReference: $('some-dom-element-id')
});
Obviously the example is a little bit ridiculous just to style an element’s background red, but the point is for me it’s much cleaner having the option to write
$(this).setStyle('background-color', '#F00');
than
this.options.domReference.setStyle('background-color', '#F00');
Recently I had to slice converted a site mockup to XHMTL and CSS. Part of the implementation required that the width of the site be what I like to call “static-variable width”.
The width of the site is not dependent on the width of the browser as a fluid layout is, but a slider control is available to the user to grow or shrink the width of the site as they desire.
Due to the need for this flexibility and the heavy image work used for the background of many of the DOM elements, .png files with transparency needed to be used in many places.
Things really looked great, except of course in IE6.
There are many different “solutions” to this problem, all which revolve around the Internet Explorer AlphaImageLoader Filter. After a lot of research and testing of different implementations, I settled on the SuperSleight. I like this technique for a variety of reasons
I found that allinthehead has implemented a jQuery plugin. Since I’m personally more a fan of MooTools, I ported the plugin to MooTools, extending the native Element class.
Element.implement({
superSleight: function(settings) {
var settings = $H(settings);
settings.extend({
imgs: true,
backgrounds: true,
shim: '/_img/png_fix_blank.gif',
apply_positioning: true
});
if (Browser.Engine.trident && Browser.Engine.version < 7 && Browser.Engine.version >= 4) {
$(this).getElements('*').each(function(elem) {
// background pngs
if (settings.backgrounds && elem.getStyle('background-image').match(/\.png/i) !== null) {
var bg = elem.getStyle('background-image');
var src = bg.substring(5, bg.length - 2);
var mode = (elem.getStyle('background-repeat') == 'no-repeat' ? 'crop': 'scale');
var styles = {
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "', sizingMethod='" + mode + "')",
'background-image': 'url(' + settings.shim + ')'
};
elem.setStyles(styles);
}
// image elements
if (settings.imgs && elem.match('img[src$=png]')) {
var elem_size = elem.getSize();
var styles = {
'width': elem_size.x + 'px',
'height': elem_size.y + 'px',
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + elem.getProperty('src') + "', sizingMethod='scale')"
};
elem.setStyles(styles).setProperty('src', settings.shim);
}
// apply position to 'active' elements
if (settings.applyPositioning && ['a', 'input'].contains(elem.get('tag')) && elem.getStyle('position') === '') {
elem.setStyle('position', 'relative');
}
});
}
}
});
.gif file. This .gif file should be a transparent 1x1 px image. This is what the Alpha ImageLoader uses to fix the transparency issues with the .png filestop right CSS background-position property, I found increasing the width of these .png images by putting transparent pixels as padding in the left side of the image itself can correctly force the image into position for IE6 without breaking the layout in good browsers.