Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit d9a689b30f83150d482974476aaf30da157aefc1 @tombenner committed Nov 2, 2011
Showing with 1,109 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +1 −0 Gemfile
  3. +20 −0 MIT-LICENSE
  4. +163 −0 README.md
  5. +21 −0 Rakefile
  6. +17 −0 has_many_autocomplete.gemspec
  7. +100 −0 lib/assets/javascripts/has-many-autocomplete.js
  8. +82 −0 lib/assets/javascripts/jquery-ui.js
  9. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png
  10. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png
  11. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_flat_10_000000_40x100.png
  12. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png
  13. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png
  14. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png
  15. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png
  16. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
  17. BIN lib/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
  18. BIN lib/assets/stylesheets/ui-lightness/images/ui-icons_222222_256x240.png
  19. BIN lib/assets/stylesheets/ui-lightness/images/ui-icons_228ef1_256x240.png
  20. BIN lib/assets/stylesheets/ui-lightness/images/ui-icons_ef8c08_256x240.png
  21. BIN lib/assets/stylesheets/ui-lightness/images/ui-icons_ffd27a_256x240.png
  22. BIN lib/assets/stylesheets/ui-lightness/images/ui-icons_ffffff_256x240.png
  23. +342 −0 lib/assets/stylesheets/ui-lightness/jquery-ui.css
  24. +13 −0 lib/generators/has_many_autocomplete/install_generator.rb
  25. +14 −0 lib/generators/has_many_autocomplete/install_ui_generator.rb
  26. +12 −0 lib/has_many_autocomplete.rb
  27. +96 −0 lib/has_many_autocomplete/autocomplete.rb
  28. +56 −0 lib/has_many_autocomplete/form_helper.rb
  29. +47 −0 lib/has_many_autocomplete/model/active_record.rb
  30. +8 −0 lib/has_many_autocomplete/orm.rb
  31. +47 −0 lib/has_many_autocomplete/orm/active_record.rb
  32. +30 −0 lib/has_many_autocomplete/orm/mongo_mapper.rb
  33. +34 −0 lib/has_many_autocomplete/orm/mongoid.rb
  34. +3 −0 lib/has_many_autocomplete/version.rb
@@ -0,0 +1,3 @@
+.bundle/
+log/*.log
+pkg/
@@ -0,0 +1 @@
+gem "jquery-rails"
@@ -0,0 +1,20 @@
+Copyright 2011 Tom Benner
+
+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.
163 README.md
@@ -0,0 +1,163 @@
+# Has Many Autocomplete
+
+Provides a form helper method that displays a sortable list of associated records from a has_many association and an autocomplete field that can be used to add records to the list.
+
+Has Many Autocomplete has only been tested on Rails 3.1.
+
+## Installation
+
+Include the gem on your Gemfile
+
+ gem 'has-many-autocomplete', :git => 'git://github.com/tombenner/has-many-autocomplete'
+
+Install it
+
+ bundle install
+
+Run the generator
+
+ rails g has_many_autocomplete:install
+
+jQuery UI needs to be included, either through Google's CDN:
+
+ stylesheet_link_tag "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/themes/ui-lightness/jquery-ui.css"
+ javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"
+
+Or by installing the files and including them:
+
+ rails g has_many_autocomplete:install_ui
+
+ stylesheet_link_tag "ui-lightness/jquery-ui"
+ javascript_include_tag "jquery-ui.min"
+
+Finally, include has-many-autocomplete.js in your layout after jQuery and jQuery UI:
+
+ javascript_include_tag "jquery", "jquery-ui", "has-many-autocomplete"
+
+## Usage
+
+### Model
+
+We'll assume you have a Playlist model that has_many Songs through PlaylistsSong, and that you want to add Songs to a Playlist via the autocomplete:
+
+ class Playlist < ActiveRecord::Base
+ has_many :playlists_songs, :dependent => :destroy
+ has_many :songs, :through => :playlists_songs, :order => "playlists_songs.id"
+ end
+
+ class PlaylistsSong < ActiveRecord::Base
+ belongs_to :playlist
+ belongs_to :song
+ end
+
+ # Song has a name:string column, which will be used in the autocomplete lookups
+ class Song < ActiveRecord::Base
+ end
+
+### Controller
+
+To set up the action that the autocomplete uses in your controller, call _autocomplete_ with the model name and the method:
+
+ class PlaylistsController < ApplicationController
+ autocomplete :song, :name
+ end
+
+This will create an _autocomplete_song_name_ action in your controller, which you'll need to add into routes.rb:
+
+ resources :playlists do
+ get :autocomplete_song_name, :on => :collection
+ end
+
+Note: To preserve the order of the songs, you'll need to set `@playlist.songs = []` in the _PlaylistsController#update_ action:
+
+ def update
+ @playlist = Playlist.find(params[:id])
+ @playlist.songs = []
+ respond_to do |format|
+ # etc...
+ end
+ end
+
+### Autocomplete Options
+
+#### :full => true
+
+By default, the search starts from the beginning of the string you're searching for. If you want to do a full search, set the _full_ parameter to true.
+
+ class ProductsController < ApplicationController
+ autocomplete :song, :name, :full => true
+ end
+
+The following terms would match the query 'un':
+
+* Luna
+* Unacceptable
+* Rerun
+
+#### :full => false (default behavior)
+
+Only the following terms mould match the query 'un':
+
+* Unacceptable
+
+#### :extra_data
+
+By default, your search will only return the required columns from the database needed to populate your form, namely id and the column you are searching (name, in the above example).
+
+Passing an array of attributes/column names to this option will fetch and return the specified data.
+
+ class SongsController < ApplicationController
+ autocomplete :song, :name, :extra_data => [:slogan]
+ end
+
+#### :display_value
+
+If you want to display a different version of what you're looking for, you can use the :display_value option.
+
+This options receives a method name as the parameter, and that method will be called on the instance when displaying the results.
+
+ class Song < ActiveRecord::Base
+ def funky_method
+ "#{self.name}.camelize"
+ end
+ end
+
+ class PlaylistsController < ApplicationController
+ autocomplete :song, :name, :display_value => :funky_method
+ end
+
+In the example above, you will search by _name_, but the autocomplete list will display the result of _funky_method_
+
+This wouldn't really make much sense unless you use it with the "id_element" attribute. (See below)
+
+Only the object's id and the column you are searching on will be returned in JSON, so if your display_value method requires another parameter, make sure to fetch it with the :extra_data option
+
+
+#### :scopes
+ Added option to use scopes. Pass scopes in an array.
+ e.g `:scopes => [:scope1, :scope2]`
+
+#### :column_name
+ By default autocomplete uses method name as column name. Now it can be specified using column_name options
+ `:column_name => 'name'`
+
+#### json encoder
+Yajl is used as the default JSON encoder, but you can specify your own:
+
+ class PlaylistsController < ApplicationController
+ autocomplete :song, :name do |items|
+ CustomJSON::Encoder.encode(items)
+ end
+ end
+
+### View
+
+In the form, the following method will display both the autocomplete and the sortable list of songs:
+
+ form_for @playlist do |f|
+ f.has_many_autocomplete :song_ids, autocomplete_song_name_playlists_path, @playlist.songs.collect{|s| [s.name, s.id]}
+ end
+
+# Thanks
+
+A great deal of this code was based on or taken from the excellent [rails3-jquery-autocomplete](https://github.com/crowdint/rails3-jquery-autocomplete), so a hearty thanks goes to [that project's contributors](https://github.com/crowdint/rails3-jquery-autocomplete/contributors).
@@ -0,0 +1,21 @@
+#!/usr/bin/env rake
+begin
+ require 'bundler/setup'
+rescue LoadError
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
+end
+begin
+ require 'rdoc/task'
+rescue LoadError
+ require 'rdoc/rdoc'
+ require 'rake/rdoctask'
+ RDoc::Task = Rake::RDocTask
+end
+
+RDoc::Task.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'HasManyAutocomplete'
+ rdoc.options << '--line-numbers'
+ rdoc.rdoc_files.include('README.rdoc')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
@@ -0,0 +1,17 @@
+$:.push File.expand_path("../lib", __FILE__)
+
+require "has_many_autocomplete/version"
+
+Gem::Specification.new do |s|
+ s.name = "has-many-autocomplete"
+ s.version = HasManyAutocomplete::VERSION
+ s.authors = ["Tom Benner"]
+ s.homepage = "http://github.com/tombenner/has-many-autocomplete"
+ s.summary = "Autocomplete and sortable list for has_many associations"
+ s.description = "Provides a form helper method that displays a sortable list of associated records from a has_many association and an autocomplete field that can be used to add records to the list."
+
+ s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
+ s.test_files = Dir["test/**/*"]
+
+ s.add_dependency "rails", "~> 3.1.0"
+end
@@ -0,0 +1,100 @@
+$(document).ready(function(){
+ $('input.has-many-autocomplete').hasManyAutocomplete();
+});
+
+(function(jQuery)
+{
+ var self = null;
+ jQuery.fn.hasManyAutocomplete = function() {
+ if (!this.hasManyAutocompleter) {
+ this.hasManyAutocompleter = new jQuery.hasManyAutocomplete(this);
+ }
+ };
+
+ jQuery.hasManyAutocomplete = function (e) {
+ _e = e;
+ this.init(_e);
+ };
+
+ jQuery.hasManyAutocomplete.fn = jQuery.hasManyAutocomplete.prototype = {
+ hasManyAutocomplete: '0.0.1'
+ };
+
+ jQuery.hasManyAutocomplete.fn.extend = jQuery.hasManyAutocomplete.extend = jQuery.extend;
+ jQuery.hasManyAutocomplete.fn.extend({
+ init: function(e) {
+
+ e.delimiter = $(e).attr('data-delimiter') || null;
+ e.list_element = $(e).find('~ ul.hma-list');
+ e.select_element = $(e).find('~ select.hma-hidden-select');
+
+ function split( val ) {
+ return val.split( e.delimiter );
+ }
+
+ function extractLast( term ) {
+ return split( term ).pop().replace(/^\s+/,"");
+ }
+
+ function updateHiddenSelect() {
+ var id;
+ ids = [];
+ e.select_element.find('option').remove();
+ e.list_element.find('.hma-remove-link').each(function() {
+ id = $(this).attr('data-id');
+ appendOptionToHiddenSelect( id );
+ });
+ }
+
+ function appendOptionToHiddenSelect( id ) {
+ e.select_element.append('<option value="'+id+'" selected="selected">'+id+'</option>');
+ }
+
+ e.list_element.sortable({
+ stop: function(event, ui) {
+ updateHiddenSelect();
+ }
+ });
+
+ e.list_element.find('.hma-remove-link').live('click', function() {
+ var id = $(this).attr('data-id');
+ $(this).parents('li:first').remove();
+ updateHiddenSelect();
+ return false;
+ });
+
+ $(e).autocomplete({
+ source: function( request, response ) {
+ $.getJSON( $(e).attr('data-autocomplete'), {
+ term: extractLast( request.term )
+ }, function() {
+ $(arguments[0]).each(function(i, el) {
+ var obj = {};
+ obj[el.id] = el;
+ $(e).data(obj);
+ });
+ response.apply(null, arguments);
+ });
+ },
+ search: function() {
+ // custom minLength
+ var term = extractLast( this.value );
+ if ( term.length < 2 ) {
+ return false;
+ }
+ },
+ focus: function() {
+ // prevent value inserted on focus
+ return false;
+ },
+ select: function( event, ui ) {
+ e.list_element.append('<li><a href="#" class="hma-remove-link" data-id="'+ui.item.id+'"><span class="hma-remove-link-text">Remove</a> <span class="hma-item-label">'+ui.item.label+'</span></li>');
+ appendOptionToHiddenSelect( ui.item.id );
+ $(this).val('');
+ $(this).trigger('hasManyAutocomplete.select', ui);
+ return false;
+ }
+ });
+ }
+ });
+})(jQuery);
Oops, something went wrong.

0 comments on commit d9a689b

Please sign in to comment.