function removeDuplicates(arr) {
arr.sort();
var i = arr.length - 1;
while (i > 0) {
if (arr[i] === arr[i - 1]) arr.splice(i, 1);
i--;
}
}
A collection of handy code snippets in the languages that I use on a daily basis.
March 23, 2012
Javascript: Remove duplicate values from an array
I did a Google search for different methods of removing duplicate values from an array, and I found a bunch of crappy algorithms that all returned a new array, rather than paring down the original array. So I wrote this, which wouldn't work on identical complex objects, but works great for primitive data types and objects stored by reference.
Labels:
array,
function,
javascript,
js
March 22, 2012
Javascript: Get the original size of an image
Sometimes you need to know the original dimensions of an image that you've loaded via javascript, or that's already loaded in the DOM. Here's a little class that will take the location of an image, and a callback function that receives the original width and height:
var getImageSizeWithCallback = function( src, callback ) {
var image = new Image();
image.onload = function () {
if( callback ) callback( image.width, image.height );
image.onload = image.onerror = null;
};
image.onerror = function () {
if( callback ) callback( -1, -1 );
image.onload = image.onerror = null;
};
// load it
image.src = src;
};
Usage:
getImageSizeWithCallback( 'images/path/to/img.jpg', function( w, h ) {
console.log( 'image size:', w, h );
});
March 6, 2012
Bookmarklet: Scrape a web page for YouTube videos and generate a playlist
I wrote this little script to capture about 50 YouTube videos from a music blog I was browsing. I figured it would be useful for others, so I turned it into a bookmarklet:
// get html sourceAnd here's the bookmarklet link text:
var src = document.getElementsByTagName('html')[0].innerHTML;
// handle old youtube vids, and https
var vids = src.replace(/\"/g).replace(/http:\/\/www.youtube.com\/v\//gi,'http://www.youtube.com/embed/').replace(/https/gi,'http');
// parse the source for youtube embeds
var vidArr = vids.split('http://www.youtube.com/embed/')
var links = '';
// build string for playlist
var playlist = 'http://www.ytplaylist.com/?pl=';
// build links
if(vidArr.length > 1) {
// keep track of IDs so we don't get duplicates
var videos = [];
for(var i=1; i < vidArr.length; i++) {
// grab 11-character YouTube ID
var ytID = vidArr[i].substr(0,11);
if(videos.indexOf(ytID) == -1) {
// add link to video, and to playlist link
var link = 'http://www.youtube.com/watch?v='+ytID;
links += '<a target="_blank" href="'+link+'">'+link+'</a><br/>';
playlist += ytID+';';
videos.push(ytID);
}
}
playlist = playlist.substr(0,playlist.length-1);
// draw it to the page
var container = document.createElement('div');
container.innerHTML = 'Videos Found:<br/><br/>'+links+'<br/><br/>'+'<a target="_blank" href="'+playlist+'">View as Playlist</a><br/>';
container.style.position='fixed';
container.style.background='#fff';
container.style.border='5px solid black';
container.style.padding='10px';
container.style.top='0';
container.style.right='0';
container.style.zIndex='999';
document.body.appendChild(container);
} else {
alert('No YouTube videos found');
}
javascript:(function(){var%20src%20%3D%20document.getElementsByTagName('html')%5B0%5D.innerHTML%3B%0Avar%20vids%20%3D%20src.replace(%2F%5C%22%2Fg).replace(%2Fhttp%3A%5C%2F%5C%2Fwww.youtube.com%5C%2Fv%5C%2F%2Fgi%2C'http%3A%2F%2Fwww.youtube.com%2Fembed%2F').replace(%2Fhttps%2Fgi%2C'http')%3B%0Avar%20vidArr%20%3D%20vids.split('http%3A%2F%2Fwww.youtube.com%2Fembed%2F')%0Avar%20links%20%3D%20''%3B%20%0Avar%20playlist%20%3D%20'http%3A%2F%2Fwww.ytplaylist.com%2F%3Fpl%3D'%3B%20%0A%2F%2F%20build%20links%0Aif(vidArr.length%20%3E%201)%20%7B%0A%20%20var%20videos%20%3D%20%5B%5D%3B%0A%20%20for(var%20i%3D1%3B%20i%20%3C%20vidArr.length%3B%20i%2B%2B)%20%7B%20%0A%20%20%20%20var%20ytID%20%3D%20vidArr%5Bi%5D.substr(0%2C11)%3B%0A%20%20%20%20if(videos.indexOf(ytID)%20%3D%3D%20-1)%20%7B%0A%20%20%20%20%20%20var%20link%20%3D%20'http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D'%2BytID%3B%0A%20%20%20%20%20%20links%20%2B%3D%20'%3Ca%20target%3D%22_blank%22%20href%3D%22'%2Blink%2B'%22%3E'%2Blink%2B'%3C%2Fa%3E%3Cbr%2F%3E'%3B%0A%20%20%20%20%20%20playlist%20%2B%3D%20ytID%2B'%3B'%3B%0A%20%20%20%20%20%20videos.push(ytID)%3B%0A%20%20%20%20%7D%0A%20%20%7D%0A%20%20playlist%20%3D%20playlist.substr(0%2Cplaylist.length-1)%3B%0A%20%20var%20container%20%3D%20document.createElement('div')%3B%0A%20%20container.innerHTML%20%3D%20'Videos%20Found%3A%3Cbr%2F%3E%3Cbr%2F%3E'%2Blinks%2B'%3Cbr%2F%3E%3Cbr%2F%3E'%2B'%3Ca%20target%3D%22_blank%22%20href%3D%22'%2Bplaylist%2B'%22%3EView%20as%20Playlist%3C%2Fa%3E%3Cbr%2F%3E'%3B%0A%20%20container.style.position%3D'fixed'%3B%0A%20%20container.style.background%3D'%23fff'%3B%0A%20%20container.style.border%3D'5px%20solid%20black'%3B%0A%20%20container.style.padding%3D'10px'%3B%0A%20%20container.style.top%3D'0'%3B%0A%20%20container.style.right%3D'0'%3B%0A%20%20container.style.zIndex%3D'999'%3B%0A%20%20document.body.appendChild(container)%3B%0A%7D%20else%20%7B%0A%20%20alert('No%20YouTube%20videos%20found')%3B%0A%7D}());
Labels:
bookmarklet,
code,
html,
javascript,
js,
link,
scrape,
video,
youtube
February 29, 2012
iPad bug: using CSS transitions on :hover prevents child element from showing
While building a CSS-powered drop-down navigation, I found a little iOS bug that prevented my main nav elements' sub-menus from showing on :hover. Consider the following markup and css, where a rollover on the outer <li> will reveal the inner <ul>.
<header class="admin_nav">
<ul>
<li>
<a href="#" title="Users">
<span class="label">Users</span>
</a>
<ul>
<li>
<a href="#" title="Map">Map</a>
</li>
</ul>
</li>
</ul>
</header>
header.admin_nav ul li ul {
visibility:hidden;
opacity:0;
-webkit-transition: opacity 0.35s linear;
}
header.admin_nav ul li:hover ul {
visibility:visible;
opacity:1;
}
On desktop browsers, this is a nice way to fade in a sub-menu on :hover of the main menu item. But, having the -webkit-transition definition breaks the iPad's handling of this nicely-animated menu. Get rid of the transition, and it works just fine, albeit not quite as slickly.
January 5, 2012
Coffeescript: HTML5 <input> placeholder attribute fallback
You want to use the new HTML5 placeholder attribute on input fields, but you also want to support older browsers. Here's a little Coffeescript class that takes an HTML element in the constructor, and uses jQuery to bind the focus and blur events to swap out text like a modern browser would without the script.
# ## HTML5 placeholder feature fallback class
class PlaceholderFallback
constructor: (el) ->
@el = $(el)
@initialize()
# HTML5 <input> placeholder feature detection
browserHasPlaceholder: =>
"placeholder" of document.createElement("input")
# Reads the placeholder attribute and uses it in a javascript fallback, if needed
initialize: =>
if @browserHasPlaceholder() == false
placeholderText = @el.attr 'placeholder'
@el.removeAttr 'placeholder'
@el.val(placeholderText)
@el.focus (e) ->
if this.value == placeholderText
this.value = ''
@el.blur (e) ->
if this.value == ''
this.value = placeholderText
else
@el = null
# Usage:
placeholderFallback = new PlaceholderFallback( element )
Labels:
blur,
coffeescript,
detection,
event,
fallback,
focus,
input,
javascript,
jquery,
js,
placeholder
Subscribe to:
Posts (Atom)