/* * Unobtrusive autocomplete * * To use it, you just have to include the HTML attribute autocomplete * with the autocomplete URL as the value * * Example: * * * Optionally, you can use a jQuery selector to specify a field that can * be updated with the element id whenever you find a matching value * * Example: * */ (function(jQuery) { var self = null; jQuery.fn.railsAutocomplete = function() { var handler = function() { if (!this.railsAutoCompleter) { this.railsAutoCompleter = new jQuery.railsAutocomplete(this); } }; if (jQuery.fn.on !== undefined) { return jQuery(document).on('focus',this.selector,handler); } else { return this.live('focus',handler); } }; jQuery.railsAutocomplete = function (e) { var _e = e; this.init(_e); }; jQuery.railsAutocomplete.options = { showNoMatches: true, noMatchesLabel: 'no existing match' } jQuery.railsAutocomplete.fn = jQuery.railsAutocomplete.prototype = { railsAutocomplete: '0.0.1' }; jQuery.railsAutocomplete.fn.extend = jQuery.railsAutocomplete.extend = jQuery.extend; jQuery.railsAutocomplete.fn.extend({ init: function(e) { e.delimiter = jQuery(e).attr('data-delimiter') || null; e.min_length = jQuery(e).attr('min-length') || 2; e.append_to = jQuery(e).attr('data-append-to') || null; e.autoFocus = jQuery(e).attr('data-auto-focus') || false; function split( val ) { return val.split( e.delimiter ); } function extractLast( term ) { return split( term ).pop().replace(/^\s+/,""); } jQuery(e).autocomplete({ appendTo: e.append_to, autoFocus: e.autoFocus, delay: jQuery(e).attr('delay') || 0, source: function( request, response ) { var firedFrom = this.element[0]; var params = {term: extractLast( request.term )}; if (jQuery(e).attr('data-autocomplete-fields')) { jQuery.each(jQuery.parseJSON(jQuery(e).attr('data-autocomplete-fields')), function(field, selector) { params[field] = jQuery(selector).val(); }); } jQuery.getJSON( jQuery(e).attr('data-autocomplete'), params, function() { var options = {}; jQuery.extend(options, jQuery.railsAutocomplete.options); jQuery.each(options, function(key, value) { if(options.hasOwnProperty(key)) { var attrVal = jQuery(e).attr('data-' + key); options[key] = attrVal ? attrVal : value; } }); if(arguments[0].length == 0 && jQuery.inArray(options.showNoMatches, [true, 'true'])) { arguments[0] = []; arguments[0][0] = { id: "", label: options.noMatchesLabel }; } jQuery(arguments[0]).each(function(i, el) { var obj = {}; obj[el.id] = el; jQuery(e).data(obj); }); response.apply(null, arguments); jQuery(firedFrom).trigger('railsAutocomplete.source', arguments); }); }, change: function( event, ui ) { if(!jQuery(this).is('[data-id-element]') || jQuery(jQuery(this).attr('data-id-element')).val() === "") { return; } jQuery(jQuery(this).attr('data-id-element')).val(ui.item ? ui.item.id : "").trigger('change'); if (jQuery(this).attr('data-update-elements')) { var update_elements = jQuery.parseJSON(jQuery(this).attr("data-update-elements")); var data = ui.item ? jQuery(this).data(ui.item.id.toString()) : {}; if(update_elements && jQuery(update_elements['id']).val() === "") { return; } for (var key in update_elements) { var element = jQuery(update_elements[key]); if (element.is(':checkbox')) { if (data[key] != null) { element.prop('checked', data[key]); } } else { element.val(ui.item ? data[key] : "").trigger('change'); } } } }, search: function() { // custom minLength var term = extractLast( this.value ); if ( term.length < e.min_length ) { return false; } }, focus: function() { // prevent value inserted on focus return false; }, select: function( event, ui ) { // first ensure value is a string ui.item.value = ui.item.value.toString(); if(ui.item.value.toLowerCase().indexOf('no match') != -1 || ui.item.value.toLowerCase().indexOf('too many results') != -1){ jQuery(this).trigger('railsAutocomplete.noMatch', ui); return false; } var terms = split( this.value ); // remove the current input terms.pop(); // add the selected item terms.push( ui.item.value ); // add placeholder to get the comma-and-space at the end if (e.delimiter != null) { terms.push( "" ); this.value = terms.join( e.delimiter ); } else { this.value = terms.join(""); if (jQuery(this).attr('data-id-element')) { jQuery(jQuery(this).attr('data-id-element')).val(ui.item.id).trigger('change'); } if (jQuery(this).attr('data-update-elements')) { var data = ui.item; var new_record = ui.item.value.indexOf('Create New') != -1 ? true : false; var update_elements = jQuery.parseJSON(jQuery(this).attr("data-update-elements")); for (var key in update_elements) { if(jQuery(update_elements[key]).attr("type") === "checkbox"){ if(data[key] === true || data[key] === 1) { jQuery(update_elements[key]).attr("checked","checked"); } else { jQuery(update_elements[key]).removeAttr("checked"); } } else{ if((new_record && data[key] && data[key].indexOf('Create New') == -1) || !new_record){ jQuery(update_elements[key]).val(data[key]).trigger('change'); }else{ jQuery(update_elements[key]).val('').trigger('change'); } } } } } var remember_string = this.value; jQuery(this).bind('keyup.clearId', function(){ if(jQuery.trim(jQuery(this).val()) != jQuery.trim(remember_string)){ jQuery(jQuery(this).attr('data-id-element')).val("").trigger('change'); jQuery(this).unbind('keyup.clearId'); } }); jQuery(e).trigger('railsAutocomplete.select', ui); return false; } }); } }); jQuery(document).ready(function(){ jQuery('input[data-autocomplete]').railsAutocomplete(); }); })(jQuery);