Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e333a03
* Change event should not be triggered on init. This behavior differs…
Feb 8, 2012
1b61271
* Keyboard selection bugfix
cstickel Feb 9, 2012
5181a20
* removed a lot of bugs related to keyboard selection
cstickel Feb 9, 2012
23d483c
* added esc key to close dropdown
cstickel Feb 9, 2012
af548ea
* dropdownSelection does now work for both click on the li or on the a
cstickel Feb 9, 2012
f7eee0c
* it's now possible to update value of selectbox without closing drop…
cstickel Feb 9, 2012
b3e37db
* added left and right keys as alias for up and down
cstickel Feb 9, 2012
d09eaf7
* set correct selected class, if there are labels with the same content
cstickel Feb 9, 2012
8f74454
* handle scrolling position for long dropdownlists where a scrollbar …
cstickel Feb 9, 2012
0645daa
* added "Page Up" and "Page Down" key functionality
cstickel Feb 9, 2012
47ba436
* trigger change event only when value has changed
cstickel Feb 9, 2012
6734925
* page up and page down keys bug fixed
cstickel Feb 9, 2012
be5cb73
* trim labels before searching for alphanumeric keys matchstring (sol…
cstickel Feb 9, 2012
f0b561f
* fixed page up and page down behavior for closed dropdown
cstickel Feb 9, 2012
8c33fca
* fixed page up, page bug wich closed the dropdown
cstickel Feb 9, 2012
c8573f5
* get rid of the data-id stuff... replaced with references to jquery …
cstickel Feb 10, 2012
fd989a6
* keep focus while scrolling with dropdown scrollbar (else keyboard s…
cstickel Feb 11, 2012
0bdd496
* Bugfix for Issue 10 (dropdown positions with appendTo after resize)…
cstickel Feb 11, 2012
5b8ac2f
* setting for dropdown position update polling
cstickel Feb 11, 2012
d75fb7b
* preventDefault if a dropdown closes (fixes bug if parent element of…
cstickel Feb 15, 2012
4957a7a
* updated jQuery version for unit testing
cstickel Feb 15, 2012
97578c8
* fixed bug with focus keeping behavior (it should now be possible to…
cstickel Feb 15, 2012
9b2ec3e
* fixed Firefox bug, that select by clicking on an option doesn't wor…
cstickel Mar 8, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<input type="submit"/>
</form>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="js/jquery.sparkbox-select.js"></script>
<script src="js/script.js"></script>
</body>
Expand Down
302 changes: 200 additions & 102 deletions js/jquery.sparkbox-select.js
Original file line number Diff line number Diff line change
@@ -1,130 +1,221 @@
(function($) {
var selectboxCounter = 0;


Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no reason to keep selectboxCounter, since data-id isn't in use anymore

$.fn.sbCustomSelect = function(options) {
var iOS = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)) || (navigator.userAgent.match(/iPad/i)),
android = (navigator.userAgent.match(/Android/i)),
UP = 38, DOWN = 40, SPACE = 32, RETURN = 13, TAB = 9,
LEFT = 37, UP = 38, RIGHT = 39, DOWN = 40, SPACE = 32, RETURN = 13, TAB = 9, ESC = 27, PGUP = 33, PGDOWN = 34,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added the missing keys which are also supported by native select boxes

matchString = '',
visibleDropdowns = $(),
settings = $.extend({
appendTo: false
appendTo: false,
pollPosition: false //Polling frequency in microsecounds (500-1000 should be enough), default false disableds polling. Use this option only if your selects position may change while dropdown is opened.
}, options);

var scrollToSelected = function($dropdown, recover) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This functionality was completely missing. A dropdown with a scrollbar, has to keep the selected element in the visible area.

var $selected = $dropdown.find('li.selected');
if(!$selected.length) return true;

//recover scroll position (after fadeOut)
if($dropdown.data('sb-saved-scrollTo') && recover) $dropdown.scrollTop($dropdown.data('sb-saved-scrollTo'));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hidden elements lose their scroll position. So if the dropdown fades in the last known position has to be recovered.


//we can't just use $selected.position().top, if the sb-dropdown is positioned static -.-
var scrollTop = $dropdown.scrollTop(),
offset = ($selected.offset().top+scrollTop-$dropdown.offset().top);

if(offset < scrollTop) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selected element is above the visible area.

$dropdown.scrollTop(offset);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reduce Scrolltop to the offset of the Element. => Element is the first element shown in the visible area.

} else if($dropdown.innerHeight()+scrollTop < offset+$selected.outerHeight()) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selected element is below visible area.

var scrollTo = offset+$selected.outerHeight()-$dropdown.innerHeight();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increase scrolltop that it's exactly the last one shown in the visible area.

$dropdown.scrollTop(scrollTo);
}
$dropdown.data('sb-saved-scrollTo', $dropdown.scrollTop());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save the new position, to be recovered, if we've to fade in the dropdown later.

}

var fixDropdownPositions = function(element) {
if (settings.appendTo) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing to do if appendTo isn't used.

var $elements = $(element).is('.sb-dropdown') ? $(element) : visibleDropdowns;

$elements.each(function() {
var $sbCustom = $(this).data('sb-custom'),
offset = $sbCustom.offset();

$(this).css({
'top': offset.top,
'left': offset.left,
'width': $sbCustom.width() * 0.8
});
});
}
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to the end of the file, where all events get bound.


// Sync custom display with original select box and set selected class and the correct <li>
var updateSelect = function() {
var $this = $(this),
$dropdown = $('.sb-dropdown[data-id=' + $this.parent().data('id') + ']'),
$sbSelect = $this.siblings('.sb-select');

if (this.selectedIndex != -1) {
$sbSelect.val(this[this.selectedIndex].innerHTML);

$dropdown.children().removeClass('selected')
.filter(':contains(' + this[this.selectedIndex].innerHTML + ')').addClass('selected');
var updateSelect = function(select) {
var $select = this === window ? $(select) : $(this),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it possible to call the function directly (with the select as parameter), without triggering an event.
The first sync starts before the events get bound via delegate at the end.

$dropdown = $select.parent().data('sb-dropdown'),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get the correct dropdown directly via reference saved in data. (much faster, than searching via selectorengine)

$sbSelect = $select.siblings('.sb-select');

if ($select.prop("selectedIndex") != -1) {
$sbSelect.val($select.children().eq($select.prop("selectedIndex")).html());

if($dropdown) {
$dropdown.children('.selected').removeClass('selected');
$dropdown.children().eq($select.prop("selectedIndex")).addClass('selected');
scrollToSelected($dropdown);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move new selected element to visible area, if needed.

}
}
};

// Update original select box, hide <ul>, and fire change event to keep everything in sync
var dropdownSelection = function(e) {
var $target = $(e.target),
id = $target.closest('ul').attr('data-id'),
$option = $('.sb-custom[data-id=' + id + ']').find('option').filter('[value="' + $target.parent().data('value') + '"]');

var dropdownSelection = function(e, preventClose) {
e.preventDefault();

setFocus.call($(this).data('sb-custom'));
var $target = $(e.target).parent('li').andSelf().filter('li');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for both, if the li or containing a is clicked. A lot of bugs in keyboard navigation had as reason, that the click event was triggered for the li but the function only worked for the a element.

if(!$target.length) return true;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do anything if not a list element was clicked. (e.g. the padding or border of the dropdown)


var $option = $target.data('sb-option');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get option directly through jquery object reference saved in data. Much faster than selectorengine and does also work correct if two options share the same value.


$option[0].selected = true;
$target.closest('ul').fadeOut('fast');
$option.parent().trigger('change');
if(!preventClose) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes we want to update the value without closing the dropdown. That way it's possible to navigate with page up/down, arrow up/down or alphanumeric keys in the dropdown.

hideDropdown({});
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a function to close dropdowns, to reduce redundancy. => dry

if($option.parent().data('lastVal') != $option.parent().val()) $option.parent().data('lastVal', $option.parent().val()).trigger('change');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only trigger change event, if the value really changed. If the value has changed, we've to save the new value, to for checking the next time against it.
This is in the "preventClose" condition because select other options while dropdown doesn't gets closed shouldn't trigger a "change"-event (just like native select boxes).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed old unused source.

} else updateSelect($option.parent());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the native select in sync, even if change event isn't triggered.

};

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up and down keys shouldn't open the dropdown. But return should.

// Create the <ul> that will be used to change the selection on a non iOS/Android browser
var createDropdown = function($select, i) {
var createDropdown = function($select) {
var $options = $select.children(),
$dropdown = $('<ul data-id="' + i + '" class="sb-dropdown"/>');
$dropdown = $('<ul class="sb-dropdown"/>').data('sb-custom', $select.parent());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save object reference instead of data-id for faster and more simple access.


$options.each(function() {
$this = $(this);
$dropdown.append('<li data-value="' + $this.val() + '"><a href=".">' + $this.text() + '</a></li>');
$('<li><a href=".">' + $this.text() + '</a></li>').data('sb-option', $this).appendTo($dropdown);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save the reference, to find the matching option.

});
$dropdown.bind('click', dropdownSelection);

return $dropdown;
};

// Clear keystroke matching string and show dropdown
var viewList = function(e) {
var $this = $(this),
id = $this.data('id');

var $dropdown = $(this).parent().data('sb-dropdown') || $(this);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is bound to dropdown focus and sb-select input. If it's triggered on the input we've to find the dropdown.


//if it's already the active dropdown don't do anything
if($dropdown.is('.active')) return false;

clearKeyStrokes();

$('.sb-dropdown').filter('[data-id!=' + id + ']').fadeOut('fast');
$('.sb-dropdown').filter('[data-id=' + id + ']').fadeIn('fast');

hideDropdown({target: $dropdown});
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a function to close dropdowns, to reduce redundancy. => dry

fixDropdownPositions($dropdown);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get sure the dropdown has the correct position before showing it.

visibleDropdowns = visibleDropdowns.add($dropdown);
$dropdown.addClass('active').stop().fadeTo('fast', 1);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The active class tells us, if it's actually in use, or just visible and currently fading out.
Stop active animations to prevent the stacking of animations if dropdown is toggled very fast. Feels more responsive.
FadeTo instead of FadeIn, to force fading to opacity 1, else it will fade to the value the element had before fading out, which isn't 1 if a fadeIn was got stopped before.


scrollToSelected($dropdown, true);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recover the scroll position the dropdown had, before it faded out. If it's opened the first time, bring the preselected element in visible area, if it isn't already.


e.preventDefault();
};

// Hide the custom dropdown
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the functionality of this function directly to the place where it's needed. It's called just there anyways. So it's still dry.

var hideDropdown = function(e) {
if (!$(e.target).closest('.sb-custom').length) {
$('.sb-dropdown').fadeOut('fast');
}
var $matches = $(e.target).closest('.sb-dropdown, .sb-custom'),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if target is a descendant of sb-custom or sb-dropdown. sb-dropdown isn't an descendant of sb-custom if appendTo setting is set.

$prevent = $matches.data('sb-dropdown') || $matches,
$toHide = $('.sb-dropdown.active').not($prevent);

if($toHide.length && e.preventDefault) e.preventDefault();
$toHide.removeClass('active').stop().fadeOut('fast', function() {
visibleDropdowns = visibleDropdowns.not($(this));
});
};


var setFocus = function() {
$(this).children('input.sb-select').focus();
};

// Manage keypress to replicate browser functionality
var selectKeypress = function(e) {
var $this = $(this),
$current = $('.sb-dropdown[data-id=' + $this.data('id') + ']').find('.selected');


// if ($('.sb-dropdown[data-id=' + $this.data('id') + ']').find('.selected') || $('.sb-dropdown[data-id=' + $this.data('id') + ']');
// $this.siblings('ul').find('.selected');

if ((e.keyCode == UP || e.keyCode == DOWN || e.keyCode == SPACE) && $current.is(':hidden')) {
$current.focus();
return;
$current = $this.parent().data('sb-dropdown').find('.selected');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faster access through object reference.


//select in dropdown if it's open... else directly change select value to target element
function softSelect(el) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Softselect selects new value without triggering change event, if the dropdown is opened.

if($current.is(':hidden')) $(el).trigger('click');
else $(el).addClass('selected').trigger('click', true);
}

if (e.keyCode == UP && $current.prev().length) {
e.preventDefault();
$current.removeClass('selected');
$current.prev().addClass('selected');
} else if (e.keyCode == DOWN && $current.next().length) {

if (e.keyCode >= 48 && e.keyCode <= 90) {
matchString += String.fromCharCode(e.keyCode);

var matches = [],
matchFirstChar = false;

if(!matchString.replace(new RegExp(matchString[0],"g"), '').length) matchFirstChar = true;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the whole match string contains only the same character one or multiple times, we just jump to the next element, starting with that char.


$current.siblings('li').andSelf().children('a').each(function() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check all options.

if ($.trim(this.innerHTML.toUpperCase()).indexOf(matchFirstChar ? matchString[0] : matchString) === 0) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've to trim it. Maybe someone splits the option tag on multiple lines, or something like that.
Find the next element that starts with the whole matchstring if the string contains different chars, else find the next element starting with that char.

matches.push(this);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Events are now all delegated and bound at the end.

}
});
if (matches.length) {
if(matchFirstChar) {
softSelect($(matches[($(matches).index($current.find('a'))+1)%matches.length]).parent());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a matchstring containing just a single char one or multiple times, we've to select the next match relative to the current selected. If the current is the last match we start from top.
Since we use softselect, the change event is triggered, if the dropdown is closed and it isn't if dropdown is open.

}
else softSelect($(matches[0]).parent());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we've multiple different chars in match string we just select the first match. Of course softselect again.

}
} else clearKeyStrokes();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clear stroke string, if a non alpha numeric key is pressed.


if ((e.keyCode == RETURN || e.keyCode == SPACE) && $current.is(':hidden')) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return should open the dropdown.

$current.focus();
e.preventDefault();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prevent default, else the formular gets submitted if the return key is pressed.

$current.removeClass('selected');
$current.next().addClass('selected');
}

if (e.keyCode == RETURN || e.keyCode == SPACE) {
$current.trigger('click');
return;
}

if (e.keyCode >= 48 && e.keyCode <= 90) {
matchString += String.fromCharCode(e.keyCode);
checkforMatch(e);

function nextPage(elements) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calculation how far we've to scroll with page up/down keys.

var hideAfter = false;
if($current.is(':hidden')) {
$current.parent().show();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've to show the dropdown if it's closed to get the correct dimensions. Since it's closed again immediately the user won't see it.

hideAfter = true;
}
var targetDistance = $current.parent().innerHeight()-($current.outerHeight()*2),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to scroll one page. The last shown element should be the first shown on the next page and the other way around.

distance = 0,
$target = $(elements).last();

elements.each(function() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've to check height of each relevant element till we reached the target distance, since they may differ. For example multiple line options or padding set by css selectors like :nth-child(odd).

if(distance < targetDistance) distance += $(this).outerHeight();
else {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change event shouldn't be triggered on init.

$target = $(this);
return false;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As soon as we've reached the target distance we can break out of the loop.

}
});
if(hideAfter) $current.parent().hide();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If dropdown was hidden, hide it again. Else keep it open.

softSelect($target);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Softselect, since page up and pagedown work with opened and closed dropdown.

}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.live also does just event delegation. So we can use delegate on the document to keep a consistent style of binding events. With current jQuery versions this should be changed to .on. I hadn't updated the jQuery version for compatibility reasons, so far.


if (e.keyCode == TAB && $current.is(':visible')) {
e.preventDefault();

switch (e.keyCode) {
case UP:
case LEFT:
e.preventDefault();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've to prevent default independent of actually finding a next element. Else the browser scrolls if we're already at the first element.

if($current.prev().length) softSelect($current.prev());
break;
case RIGHT:
case DOWN:
e.preventDefault();
if($current.next().length) softSelect($current.next());
break;
case PGUP:
e.preventDefault();
nextPage($current.prevAll());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For page up we calculate the distance on the elements before.

break;
case PGDOWN:
e.preventDefault();
nextPage($current.nextAll());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For page down we calculate the distance on the elements after.

break;
}

if ((e.keyCode == TAB && $current.is(':visible')) || e.keyCode == RETURN || e.keyCode == SPACE || e.keyCode == ESC) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dropdown can be closed by return, space, esc and tab close.
Don't prevent default for tab if the dropdown is closed, since we still want to be able to switch to the next element by tab.

$current.trigger('click');
hideDropdown(e);
e.preventDefault();
return;
}
};

// Check keys pressed to see if there is a text match with one of the options
var checkforMatch = function(e) {

var re = '/' + matchString + '.*/';

$(e.target).siblings('ul').find('a').each(function() {
if (this.innerHTML.toUpperCase().indexOf(matchString) === 0) {
$(this).trigger('click');
return;
}
});
};

// Clear the string used for matching keystrokes to select options
var clearKeyStrokes = function() {
matchString = '';
Expand All @@ -145,12 +236,13 @@
* After all of the setup is complete, trigger the change event on the original select box to update the .sb-select input
*/
this.each(function() {
var $self = $(this);
var $self = $(this),
$sbCustom = $('<div class="sb-custom"/>');

$self.attr('tabindex', -1)
.wrap('<div data-id="' + selectboxCounter + '" class="sb-custom"/>')
.after('<input data-id="' + selectboxCounter + '" type="text" class="sb-select" readonly="readonly" />')
.bind('change', updateSelect);
.after($sbCustom)
.appendTo($sbCustom)
.after('<input type="text" class="sb-select" readonly="readonly" />');


if (iOS || android) {
Expand All @@ -163,33 +255,39 @@
'z-index': 1000
});
} else {
$self.next().bind('click', viewList);

$sbCustom.data('sb-dropdown', createDropdown($self));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link dropdown object reference to the custom select, to be able to access fast the correct dropdown.


if (!settings.appendTo) {
$self.after(createDropdown($self, selectboxCounter));
$sbCustom.append($sbCustom.data('sb-dropdown'));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually append the object, we've created before by createDropdown.

} else {
var offset = $self.parent().offset();

$(settings.appendTo).append(createDropdown($self, selectboxCounter).css({
'top': offset.top,
'left': offset.left,
'width': $self.parent().width() * 0.8
}));
$(settings.appendTo).append($sbCustom.data('sb-dropdown'));
if(typeof(settings.pollPosition) === 'number') {
var callback = function() {
fixDropdownPositions();
window.setTimeout(callback, settings.pollPosition);
};
callback();
}
}

$self.data('lastVal', $self.val());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save the current value for the "has it actually changed"-check.

}

$self.trigger('change');
selectboxCounter++;
updateSelect($self);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sync the custom select value with the value of the native select. Events aren't bound, so far, so we call the function directly, instead of triggering an event.

});

// Hide dropdown when click is outside of the input or dropdown
$(document).bind('click', hideDropdown);

$('.sb-custom').find('.sb-select').live('keydown', selectKeypress);
$('.sb-custom').bind('blur', clearKeyStrokes);
$(document).delegate('.sb-dropdown', 'focus', viewList);

$(document).bind('mousedown', hideDropdown)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bind all events in one place in a consistent style. Using delegation instead of binding the event directly to the dropdown, select, etc improves also the performance. Especially for pages with a lot of dropdowns. For example a long list, where each element has it's own dropdown.

.delegate('.sb-custom', 'blur', clearKeyStrokes)
.delegate('.sb-custom', 'click', setFocus)
.delegate('.sb-custom select', 'change', updateSelect)
.delegate('.sb-select', 'keydown', selectKeypress)
.delegate('.sb-select', 'click', viewList)
.delegate('.sb-dropdown', 'focus', viewList)
.delegate('.sb-dropdown', 'click', dropdownSelection);
$(window).bind('resize', fixDropdownPositions);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update positions of the visible dropdowns if the window gets resized.


return this;
};
})(jQuery);
2 changes: 1 addition & 1 deletion test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

<script src="../js/modernizr-1.7.min.js"></script>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="../js/jquery.sparkbox-select.js"></script>

<!-- test runner files -->
Expand Down
Loading