first commit
This commit is contained in:
296
libraries/jquery.select-to-autocomplete.js
Normal file
296
libraries/jquery.select-to-autocomplete.js
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
Version: 1.0.5
|
||||
|
||||
Documentation: http://baymard.com/labs/country-selector#documentation
|
||||
|
||||
Copyright (C) 2011 by Jamie Appleseed, Baymard Institute (baymard.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
(function($){
|
||||
var settings = {
|
||||
'sort': true,
|
||||
'sort-attr': 'data-priority',
|
||||
'sort-desc': false,
|
||||
'autoselect': false,
|
||||
'alternative-spellings': true,
|
||||
'alternative-spellings-attr': 'data-alternative-spellings',
|
||||
'remove-valueless-options': true,
|
||||
'copy-attributes-to-text-field': true,
|
||||
'autocomplete-plugin': 'jquery_ui',
|
||||
'relevancy-sorting': true,
|
||||
'relevancy-sorting-partial-match-value': 1,
|
||||
'relevancy-sorting-strict-match-value': 5,
|
||||
'relevancy-sorting-booster-attr': 'data-relevancy-booster',
|
||||
handle_invalid_input: function( context ) {
|
||||
|
||||
var check = false;
|
||||
if ( context.$text_field.val() != context.$select_field.find('option:selected:first').text() && context.$text_field.val() != '' )
|
||||
{
|
||||
context.$select_field.children( 'option' ).each( function() {
|
||||
if ( $( this ).attr( 'value' ) == context.$text_field.val() )
|
||||
check = true;
|
||||
})
|
||||
|
||||
if ( !check )
|
||||
{
|
||||
var text = context.$text_field.val();
|
||||
$( '#' + context.$select_field.attr( 'id' ) ).attr( 'disabled', 'disabled' );
|
||||
$( '#' + context.$select_field.attr( 'id' ) + '-value' ).val( text );
|
||||
$( '#' + context.$select_field.attr( 'id' ) + '-value' ).removeAttr( 'disabled' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$( '#' + context.$select_field.attr( 'id' ) ).removeAttr( 'disabled' );
|
||||
$( '#' + context.$select_field.attr( 'id' ) + '-value' ).attr( 'disabled', 'disabled' );
|
||||
}
|
||||
},
|
||||
handle_select_field: function( $select_field ) {
|
||||
return $select_field.hide();
|
||||
},
|
||||
insert_text_field: function( context ) {
|
||||
var $text_field = $( "<input></input>" );
|
||||
if ( settings['copy-attributes-to-text-field'] ) {
|
||||
var attrs = {};
|
||||
var raw_attrs = context.$select_field[0].attributes;
|
||||
for (var i=0; i < raw_attrs.length; i++) {
|
||||
var key = raw_attrs[i].nodeName;
|
||||
var value = raw_attrs[i].nodeValue;
|
||||
if ( key !== 'name' && key !== 'id' && typeof context.$select_field.attr(key) !== 'undefined' ) {
|
||||
attrs[key] = value;
|
||||
}
|
||||
};
|
||||
$text_field.attr( attrs );
|
||||
}
|
||||
$text_field.blur(function() {
|
||||
var valid_values = context.$select_field.find('option').map(function(i, option) { return $(option).text(); });
|
||||
if ( !($text_field.val() in valid_values) && typeof settings['handle_invalid_input'] === 'function' ) {
|
||||
settings['handle_invalid_input'](context);
|
||||
}
|
||||
});
|
||||
// give the input box the ability to select all text on mouse click
|
||||
if ( context.settings['autoselect'] ) {
|
||||
$text_field.click( function() {
|
||||
this.select();
|
||||
});
|
||||
}
|
||||
return $text_field.val( context.$select_field.find('option:selected:first').text() )
|
||||
.insertAfter( context.$select_field );
|
||||
},
|
||||
extract_options: function( $select_field ) {
|
||||
var options = [];
|
||||
var $options = $select_field.find('option');
|
||||
var number_of_options = $options.length;
|
||||
|
||||
// go over each option in the select tag
|
||||
$options.each(function(){
|
||||
var $option = $(this);
|
||||
var option = {
|
||||
'real-value': $option.attr('value'),
|
||||
'label': $option.text()
|
||||
}
|
||||
if ( settings['remove-valueless-options'] && option['real-value'] === '') {
|
||||
// skip options without a value
|
||||
} else {
|
||||
// prepare the 'matches' string which must be filtered on later
|
||||
option['matches'] = option['label'];
|
||||
var alternative_spellings = $option.attr( settings['alternative-spellings-attr'] );
|
||||
if ( alternative_spellings ) {
|
||||
option['matches'] += ' ' + alternative_spellings;
|
||||
}
|
||||
// give each option a weight paramter for sorting
|
||||
if ( settings['sort'] ) {
|
||||
var weight = parseInt( $option.attr( settings['sort-attr'] ), 10 );
|
||||
if ( weight ) {
|
||||
option['weight'] = weight;
|
||||
} else {
|
||||
option['weight'] = number_of_options;
|
||||
}
|
||||
}
|
||||
// add relevancy score
|
||||
if ( settings['relevancy-sorting'] ) {
|
||||
option['relevancy-score'] = 0;
|
||||
option['relevancy-score-booster'] = 1;
|
||||
var boost_by = parseFloat( $option.attr( settings['relevancy-sorting-booster-attr'] ) );
|
||||
if ( boost_by ) {
|
||||
option['relevancy-score-booster'] = boost_by;
|
||||
}
|
||||
}
|
||||
// add option to combined array
|
||||
options.push( option );
|
||||
}
|
||||
});
|
||||
// sort the options based on weight
|
||||
if ( settings['sort'] ) {
|
||||
if ( settings['sort-desc'] ) {
|
||||
options.sort( function( a, b ) { return b['weight'] - a['weight']; } );
|
||||
} else {
|
||||
options.sort( function( a, b ) { return a['weight'] - b['weight']; } );
|
||||
}
|
||||
}
|
||||
|
||||
// return the set of options, each with the following attributes: real-value, label, matches, weight (optional)
|
||||
return options;
|
||||
}
|
||||
};
|
||||
|
||||
var public_methods = {
|
||||
init: function( customizations ) {
|
||||
|
||||
settings = $.extend( settings, customizations );
|
||||
|
||||
return this.each(function(){
|
||||
var $select_field = $(this);
|
||||
|
||||
var context = {
|
||||
'$select_field': $select_field,
|
||||
'options': settings['extract_options']( $select_field ),
|
||||
'settings': settings
|
||||
};
|
||||
|
||||
context['$text_field'] = settings['insert_text_field']( context );
|
||||
|
||||
settings['handle_select_field']( $select_field );
|
||||
|
||||
if ( typeof settings['autocomplete-plugin'] === 'string' ) {
|
||||
adapters[settings['autocomplete-plugin']]( context );
|
||||
} else {
|
||||
settings['autocomplete-plugin']( context );
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var adapters = {
|
||||
jquery_ui: function( context ) {
|
||||
// loose matching of search terms
|
||||
var filter_options = function( term ) {
|
||||
var split_term = term.split(' ');
|
||||
var matchers = [];
|
||||
for (var i=0; i < split_term.length; i++) {
|
||||
if ( split_term[i].length > 0 ) {
|
||||
var matcher = {};
|
||||
matcher['partial'] = new RegExp( $.ui.autocomplete.escapeRegex( split_term[i] ), "i" );
|
||||
if ( context.settings['relevancy-sorting'] ) {
|
||||
matcher['strict'] = new RegExp( "^" + $.ui.autocomplete.escapeRegex( split_term[i] ), "i" );
|
||||
}
|
||||
matchers.push( matcher );
|
||||
}
|
||||
};
|
||||
|
||||
return $.grep( context.options, function( option ) {
|
||||
var partial_matches = 0;
|
||||
if ( context.settings['relevancy-sorting'] ) {
|
||||
var strict_match = false;
|
||||
var split_option_matches = option.matches.split(' ');
|
||||
}
|
||||
for ( var i=0; i < matchers.length; i++ ) {
|
||||
if ( matchers[i]['partial'].test( option.matches ) ) {
|
||||
partial_matches++;
|
||||
}
|
||||
if ( context.settings['relevancy-sorting'] ) {
|
||||
for (var q=0; q < split_option_matches.length; q++) {
|
||||
if ( matchers[i]['strict'].test( split_option_matches[q] ) ) {
|
||||
strict_match = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
if ( context.settings['relevancy-sorting'] ) {
|
||||
var option_score = 0;
|
||||
option_score += partial_matches * context.settings['relevancy-sorting-partial-match-value'];
|
||||
if ( strict_match ) {
|
||||
option_score += context.settings['relevancy-sorting-strict-match-value'];
|
||||
}
|
||||
option_score = option_score * option['relevancy-score-booster'];
|
||||
option['relevancy-score'] = option_score;
|
||||
}
|
||||
return (!term || matchers.length === partial_matches );
|
||||
});
|
||||
}
|
||||
// update the select field value using either selected option or current input in the text field
|
||||
var update_select_value = function( option ) {
|
||||
if ( option ) {
|
||||
if ( context.$select_field.val() !== option['real-value'] ) {
|
||||
context.$select_field.val( option['real-value'] );
|
||||
context.$select_field.change();
|
||||
}
|
||||
} else {
|
||||
var option_name = context.$text_field.val().toLowerCase();
|
||||
var matching_option = { 'real-value': false };
|
||||
for (var i=0; i < context.options.length; i++) {
|
||||
if ( option_name === context.options[i]['label'].toLowerCase() ) {
|
||||
matching_option = context.options[i];
|
||||
break;
|
||||
}
|
||||
};
|
||||
if ( context.$select_field.val() !== matching_option['real-value'] ) {
|
||||
context.$select_field.val( matching_option['real-value'] || '' );
|
||||
context.$select_field.change();
|
||||
}
|
||||
if ( matching_option['real-value'] ) {
|
||||
context.$text_field.val( matching_option['label'] );
|
||||
}
|
||||
if ( typeof context.settings['handle_invalid_input'] === 'function' && context.$select_field.val() === '' ) {
|
||||
context.settings['handle_invalid_input']( context );
|
||||
}
|
||||
}
|
||||
}
|
||||
// jQuery UI autocomplete settings & behavior
|
||||
context.$text_field.autocomplete({
|
||||
'minLength': 0,
|
||||
'delay': 0,
|
||||
'autoFocus': true,
|
||||
source: function( request, response ) {
|
||||
var filtered_options = filter_options( request.term );
|
||||
if ( context.settings['relevancy-sorting'] ) {
|
||||
filtered_options = filtered_options.sort( function( a, b ) { return b['relevancy-score'] - a['relevancy-score']; } );
|
||||
}
|
||||
response( filtered_options );
|
||||
},
|
||||
select: function( event, ui ) {
|
||||
update_select_value( ui.item );
|
||||
},
|
||||
change: function( event, ui ) {
|
||||
update_select_value( ui.item );
|
||||
}
|
||||
});
|
||||
// force refresh value of select field when form is submitted
|
||||
// context.$text_field.parents('form:first').submit(function(){
|
||||
// update_select_value();
|
||||
// });
|
||||
// select current value
|
||||
// update_select_value();
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.selectToAutocomplete = function( method ) {
|
||||
if ( public_methods[method] ) {
|
||||
return public_methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
|
||||
} else if ( typeof method === 'object' || ! method ) {
|
||||
return public_methods.init.apply( this, arguments );
|
||||
} else {
|
||||
$.error( 'Method ' + method + ' does not exist on jQuery.fn.selectToAutocomplete' );
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user