-
Notifications
You must be signed in to change notification settings - Fork 25
Keyboard selection behavior and bugfixes. #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e333a03
1b61271
5181a20
23d483c
af548ea
f7eee0c
b3e37db
d09eaf7
8f74454
0645daa
47ba436
6734925
be5cb73
f0b561f
8c33fca
c8573f5
fd989a6
0bdd496
5b8ac2f
d75fb7b
4957a7a
97578c8
9b2ec3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,130 +1,221 @@ | ||
| (function($) { | ||
| var selectboxCounter = 0; | ||
|
|
||
|
|
||
| $.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, | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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')); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Selected element is above the visible area. |
||
| $dropdown.scrollTop(offset); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| }); | ||
| }); | ||
| } | ||
| } | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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), | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| $dropdown = $select.parent().data('sb-dropdown'), | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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({}); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed old unused source. |
||
| } else updateSelect($option.parent()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| }; | ||
|
|
||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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}); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a function to close dropdowns, to reduce redundancy. => dry |
||
| fixDropdownPositions($dropdown); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
|
||
| scrollToSelected($dropdown, true); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'), | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| matches.push(this); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| } | ||
| else softSelect($(matches[0]).parent()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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')) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return should open the dropdown. |
||
| $current.focus(); | ||
| e.preventDefault(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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), | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change event shouldn't be triggered on init. |
||
| $target = $(this); | ||
| return false; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Softselect, since page up and pagedown work with opened and closed dropdown. |
||
| } | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The dropdown can be closed by return, space, esc and tab close. |
||
| $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 = ''; | ||
|
|
@@ -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) { | ||
|
|
@@ -163,33 +255,39 @@ | |
| 'z-index': 1000 | ||
| }); | ||
| } else { | ||
| $self.next().bind('click', viewList); | ||
|
|
||
| $sbCustom.data('sb-dropdown', createDropdown($self)); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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')); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
There was a problem hiding this comment.
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