Because you're to cool not to fork the release candidate

Posts Tagged: jquery

99 problems but a glitch ain’t one

99 problems but a glitch ain’t one

Text

One of my clients’ site, Gnartifact.com, is undergoing a full overhaul currently and occupies a lot of my free time. I figure it deserves the occasional blog for updates.

Firstly,

Gnartifact is getting a brand new video archiving form. Before, the site grabbed a lot of data from the Vimeo and YouTube APIs from the Rails backend. In this version, all API calls are done client-side using jQuery. This increases performance and accuracy of archiving.

Select default thumbnails is now even easier as you can now upload your own thumbnails, and all past thumbnails are saved to be chosen from at any point. Customization is the name of the game for this version. Paperclip still powers image uploading.

With the addition of many more video attributes, the archive form is broken into tabs. This makes organization and user workflow much simpler, and makes it easy to enable or disable features on the fly.

Major changes is the upgrade to Rails 3.1 from Rails 2.3. Production server will run on Phusion Passenger instead of a Mongrel cluster. Hosting company will be switched to my own reseller account. RVM is implemented now right in development. A local Git server and Capistrano will be used for deployment. The complete custom administrative end has been replaced with the ActiveAdmin gem, which I really recommend you check out. 

As always, NewRelic will be used for server monitoring. 

More updates to come soon

http://www.gnartifact.com
http://code.google.com/apis/youtube/overview.html
http://vimeo.com/api
https://github.com/thoughtbot/paperclip
http://activeadmin.info/
 

My first jQuery plugin — Heftybox

I’m getting started with my first official jQuery plugin, and I’m just turning now looking for input. I want to know what I’m doing wrong or right so far and if everything is being developed in a manner that won’t cause issue down the road. With no further adieu:

$.fn.heftyBox = function(args) {
   
if ($(this).length) {
   
//Set up defaults
   
var a    =  $.extend({
        type  
:  "checkbox",
        width  
:  "auto",
        height
:  ($(this).innerHeight() > 150) ? $(this).innerHeight() : 150
   
}, args);

   
//Gather original attributes, convert DOM, then reassgign attributes
   
var attributes = $(this)[0].attributes;
   
var optionsHTML = $(this).html();
    $
(this).after('<ul id="tmpul">' + optionsHTML + '</ul>');
    $
(this).remove();
   
var ul = $('#tmpul')[0];
   
for (var i = 0; i < attributes.length; i++) {
        $
(ul).attr(attributes[i].name, attributes[i].value);
   
}


   
//Convert options to checkbox or radios
   
var options = $(ul).children('option');
   
var name = $(ul).attr('name');
    $
(ul).removeAttr('name');
   
var f = 0;
    $
.each(options, function(key, option) {
       
var itemAttributes = $(this)[0].attributes;
       
var value = $(this).attr('value');
       
var label = $(this).text();
       
var selected = $(this).attr('selected') ? "checked" : ''
        selected
+= $(this).attr('disabled') ? " disabled" : ''
       
var newLi;
        $
(this).replaceWith(newLi = $('<li ' + selected + '><input type="' + a.type + '" id="option_' + name + '_' + f + '" name="' + name + '" value="' + value + '" ' + selected + '/><label for="option_' + name + '_' + f + '">' + label + '</label></li>') )
       
for (var i = 0; i < itemAttributes.length; i++) {
            $
(newLi).children('input').attr(itemAttributes[i].name, itemAttributes[i].value);
       
}
        f
++;
   
})

   
//Add Filter Box
    $
(ul).before('<input id="' + name + '_filter" class="list_filter" />');
   
var list = $(ul).children('li');
   
var filter = $('#' + name + '_filter');
    filterBox
($(filter), list);

   
//Contain it all
    $
(filter).before('<div class="heftyBox" id="' + name + '_container"></div>');
   
var container = $('#' + name + '_container');
    $
(filter).appendTo($(container));
    $
(ul).appendTo($(container));

   
//Select all box for checkboxes
   
if (a.type == "checkbox") {
        $
(filter).after($('<a href="#">Select All</a>').bind('click', function() {
           
var checkboxes = $(this).next('ul').find('input:not([disabled])');
           
if ($(checkboxes).length > $(checkboxes + ':checked').length) {
                $
(checkboxes).attr('checked', 'checked').closest('li').attr('checked', 'checked');
           
} else {
                $
(checkboxes).removeAttr('checked', 'checked').closest('li').removeAttr('checked');
           
}
           
($(this).text() == "Select All") ? $(this).text("Select None") : $(this).text("Select All")
            $
(this).next('ul').trigger('change')
           
return false;
       
}))
   
}

   
//Write the Data to the DOM
    $
(ul).data({
        heftyBox
: a
   
})

   
//Apply DOM data
    updateheftyBox
($(ul));

   
//Handle Value Change
    $
(this).bind('change', function() {updateheftyBox($(this));})
   
}

   
//scroll to first selected DOM
   
if ($(ul).find('li[checked]:first').length) {
       
var itemTop = $(ul).find('li[checked]:first').offset().top || $(ul).offset().top;
       
var ulTop = $(ul).offset().top;
        $
(ul).scrollTop(itemTop - ulTop);
   
}
}

updateheftyBox
= function(target) {
   
var a = $(target).data().heftyBox;
   
var container = $(target).parent('.heftyBox');
   
var filter = $(target).siblings('.list_filter');
   
var ul = $(target);

   
//Gather created data
    a
.value = [];
    $
(ul).find('input:checked').each(function() {
        a
.value.push($(this).val())
   
})

    $
(container).css({
        width
: a.width,
        height
: a.height,
       
"min-width": $(filter).outerWidth()
   
});
    $
(ul).css({
        height
: a.height - $(filter).outerHeight(),
       
"margin-top": $(filter).outerHeight()
   
})
    $
(ul).val(a.value);
}


filterBox
= function(target, blocks) {
    $
(target).unbind('keyup change');
    $
(target).bind('keyup change', function() {
       
var inText = $(this).val().trim(); //remove trailing whitespace

        $
.each(blocks, function() {
           
var title = $(this).children('label').text(); //the title in the block
           
if (matchAll(title, inText)) {
                $
(this).show();
           
} else {
                $
(this).hide();
           
}
       
})

   
})
}

matchAll
= function(string, args) { //string= string to match, args= search input
   
var die = 0; //return switch
   
var checks = args.split(' '); //break input into array
    $
.each(checks, function() {
       
var myReg = new RegExp(this, 'i'); //search term to regex
       
if (!string.match(myReg)) { //if it doesn't match, kill the function
           
die = 1;
       
}
   
})

   
if (die == 1) {
       
return false;
   
} else {
       
return true;
   
}
}

$
('.heftyBox li:has(input:checkbox)').live('click', function() {
   
($(this).has(':checked').length) ? $(this).attr('checked', 'checked') : $(this).removeAttr('checked')
})

The concepts of thus plugin:

  • The HeftyBox should be dynamic and not affect any attributes or user input that coould be collected by the original Select box
  • The HeftyBox should accept many options to match styling and uniqueness of the application it is being used for
  • The HeftyBox should be able to be modified and customized with calls to the object after it is initiated
  • The HefyBox should be easy to implement, attractive, and functional with defualt setting

Source github/kmacey1249/heftybox

Implemented like so:

Initial HTML

<select name="test" id="test" multiple="multiple" bar="baz">
 
<option value="1">One</option>
 
<option value="2">Two</option>
 
<option value="3" foo="bar">Three</option>
</select>

jQuery Call

$('#test').heftyBox(); //{type: "checkbox"/"radio", width: "auto", height: 150}

Result:

<div class="heftyBox" id="test_container" style="width: auto; height: 178px; min-width: 155px; ">
 
<input id="test_filter" class="list_filter" />
 
<a href="#">Select All</a>
 
<ul id="test" multiple="multiple" bar="baz" style="height: 155px; margin-top: 23px; ">
   
<li>
     
<input type="checkbox" id="option_test_0" name="test" value="1">
     
<label for="option_test_0">One</label>
   
</li>
   
<li>
     
<input type="checkbox" id="option_test_1" name="test" value="2">
     
<label for="option_test_1">Two</label>
   
</li>
   
<li>
     
<input type="checkbox" id="option_test_2" name="test" value="3" foo="bar">
     
<label for="option_test_2">Three</label>
   
</li>          
 
</ul>
</div>
Source: codereview.stackexchange.com

Prevent scrolling from anchor tags

I’m making a simple navigation with jQuery that loads content panes by showing or hiding them on the page. I am using anchor tags to determine which pane to show. I also use a “ready” function to show the#hash element when the page is loaded. Pretty basic:

$(document).ready(function() {
  $
('#video_form_content > div').hide();
 
var showTab = window.location.hash || "#basic-info";
  $
(showTab).show();
}

$
('#video_form_tabs li').on('click', function() {
    $
('#video_form_content > div').hide();
   
var target = $(this).children('a').attr('href');
    $
(target).show();
})

What’s happening, though, is that when the elements are clicked, the page jumps to the top of the targetdiv. I don’t want this jump, but I do want to keep the default functionality of the anchor tag in the sense that I want the hash added to the URL so that refreshing would reopen the same tab.

Here’s what I’ve tried

  • Adding $(window).scrollTop(0) to the click event. I thought it might, but this event fires before the actual navigation of the anchor element, so it’s immediately undone.
  • Adding $(window).scrollTop(0) to $(document).ready() However, this listener is not fired when clicking an anchor for the same page.
  • Adding window.location.hash = target or window.location.href = target to the click event. However, this still causes the resubmission of the page, and it still “jumps”.
  • Adding return false to the function. This prevents adding the hash to the URL, which is highly preferred.

This is really baffling me, and any help would be much appreciated.

Source: stackoverflow.com

Regular Expression to Match and Highlight With a Lot of Variance

I’ve taken a few swings at this, but I’ll post my issue and my most recent successful code.

If you’re familiar with Sublime Text, this will make sense much more quickly. If not, I’ll do my best to explain, but I definitely recommend the program as a side note.

The goal is to match titles given a search string and highlight the match. The catch is that the match can be in any order, and doesn’t have to signify the beginning of the string, and that strings are separated by spaces in the original input

Example:

String to Match: "Hello World"

Does it match?
"hello" -> Yes!
"h w" -> Yes!
"el orl" -> Yes!
"World Hello" -> Yes!
"Hello Foo" -> No!

So the input is very forgiving. I have it to the point where I can match the text and determine whether or not to show the result. I’m just stuck at getting highlighting to work. I may be taking the wrong approach, but here is what I have:

$('#sdfilter').live('keyup change', function() {
   
var inText = $(this).val().trim(); //remove trailing whitespace
   
var blocks = $('.listing'); //blocks to loop through

    $
.each(blocks, function() {
       
var title = $(this).children('.title').text(); //the title in the block
       
if (matchAll(title, inText)) {
            $
(this).show();
       
} else {
            $
(this).hide();
       
}
   
})

})

matchAll
= function(string, args) {
   
var die = 0; //return switch
   
var checks = args.split(' '); //break input into array
    $
.each(checks, function() {
       
var myReg = new RegExp(this, 'i'); //search term to regex
       
if (!string.match(myReg)) { //if it doesn't match, kill the function
           
die = 1;
       
}
   
})

   
if (die == 1) {
       
return false;
   
} else {
       
return true;
   
}
}

I’ve tried doing a replace withing the $.each(checks, function() {...}) loop to add <span>tags, but then the input string matches the span tags themselves as it loops around.

I’ve found solutions that are very close, but not quite as dynamic as I’m hoping for. So my official question is: Am I moving in the right direction? And if so, what am I missing here?

Source: stackoverflow.com

jQuery API .data(key, value)

This saved my life today, so I figured it was worth giving credit to.

Source: api.jquery.com

Select where parent does not contain DOM in any generation

I can’t figure this one out, and I may be making it harder than it is.

I need to select all DOMS with class ‘B’, whose parent, ‘A’, does not contain class ‘C’ in any generation, and ‘C’ is NOT a sibling of ‘B’

Example:

We would not select B if

A => ({B}, {D => ({C})})

Because B’s parent, A, also contains D, and D contains C.

However, we would select B if

A => ({B}, {D => ({})})

Because B’s parent, A, does contain D, but C is nowhere in this particular tree under A.

I’ve tried:

$('.B').not($(this).parent('.A').find('.C'))

But the not statement here actually selects the ‘C’, and excludes C itself from the array of B. I also triedhas instead of find, but that not only selects the parent A for exclusion, but I believe has only scans through one generation.

Any help or guidance would be appreciated.

Source: stackoverflow.com

Group JSON resultset by multiple attributes

Given a JSON resultset such as the following:

[ {fooID: 1, fooLabel: "one", barID: 20 barLabel: "twenty"},
 
{fooID: 1, fooLabel: "one", barID: 30 barLabel: "thirty"},
 
{fooID: 1, fooLabel: "one", barID: 40 barLabel: "forty"},
 
{fooID: 2, fooLabel: "two", barID: 500 barLabel: "fivehundred"},
 
{fooID: 2, fooLabel: "two", barID: 600 barLabel: "sixhundred"} ]

How could I iterate through this in groups?

Example

<legend>1 - one</legend>
 
<div>20 - twenty</div>
 
<div>30 - thirty</div>
 
<div>40 - forty</div>

<legend>2 - two</legend>
 
<div>500 - fivehundred</div>
 
<div>600 - sixhundred</div>

Also, it would be preferable that the solution can support more dimensions, even maybe with some minor adjustments, as it’s looking like I’ll have to use this a few times for several applications. And it shouldn’t be an issue, but it may also be good to take into consideration that the results will not always be in order by group such as in the example I provided. It may be ordered 1, 2, 2, 1, 2… etc.

Source: stackoverflow.com

Text

I came across a question today on stackoverflow.com, and thought I had a relatively clever answer.

The Question:

Say that I have a table with id “unique” and that i have executed

$('.8').hide();
$
('.3').hide();

Now I only want to show the row with 1 visible collumn and hide the rest, I.E I want to hide all rows except the first one (Still having the second and third collumn hidden), how can I check if a table row have more than 1 visible collumn?

<table id="unique">
<tr class = "opponent4 opponent3 opponent5">
<td class="1">1</td>
<td class="3">3</td>
<td class="8">8</td>
</tr>
<tr class = "opponent7 opponent3 opponent9">
<td class="1">1</td>
<td class="1">1</td>
<td class="8">8</td>
</tr>
<tr class = "opponent1 opponent3 opponent4">
<td class="1">1</td>
<td class="2">2</td>
<td class="8">8</td>
</tr>
The Answer: 
$.each($('unique tr'), function() { //Loop through rows
 
if ($(this).children('td:visible').length > 1) { //If this row has more than one visible column
    $
(this).hide(); //hide this row
 
}
}

UPDATE

If this is a critical part of your program, I’d save something like this to a function.

$.fn.multipleColumnRows = function() {
 
var result = [];
  $
.each($(this).children('tr'), function() {
     
if ($(this).children('td:visible').length > 1) {
        result
.push($(this));
     
}
   
}
   
return result;
}

$
('#unique').multipleColumnRows.hide();


The initial answer was given in 3 or 4 different versions, (though not well documented, I must add ;-)). So, I decided to take it a step further. A problem such as this implied that this may be an important aspect to the functionality of the project. Hiding specific rows based on content tells me he wants to lead the user through a certain interface path. Therefor, he may or may not use this functionality across several tables or other applications. So, I generalized the method I originally posted and pulled it out to a function, making it re-usable. Sure, you can call it going overboard for the upvote, but I tried to look deeper into the question to provide something that will aid the user further and maybe even get him looking into making functions of his own.

Ok, I did it for the upvote.

Source: stackoverflow.com

jQuery selector not working the way I'm expecting

Consider the following simple HTML:

<div id="navcontainer">
       
<a href="#"><img alt="" src="Img1.jpg" /></a>
       
<a href="#"><img alt="" src="Img2.jpg" /></a>
       
<a href="#"><img alt="" src="Img3.jpg" /></a>
       
<a href="#"><img alt="" src="Img4.jpg" /></a>
       
<a href="#"><img alt="" src="Img5.jpg" /></a>
</div>

And for the sake of argument, let’s say it’s a very small portion of a large page with many DIV’s and A’s.

What I want to do is hide the tags and the images inside them. If I do this, it works:

$('a').hide();

But like I said, there are a lot of links on the page, so I want to be very specific. Essentially, I want ONLY the links that are inside a <div> with the class of “navcontainer”. So from what I’m seeing on the web, it should be one of the following two formats. The second one looks perfect to me. But neither is working for me.

$('div.navcontainer a').hide();
$
('div.navcontainer > a').hide();

I must be missing something stupid. Can anyone please clue me in?

Source: stackoverflow.com