meshcomplete 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in meshcomplete.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,10 @@
1
+ = Meshcomplete
2
+
3
+ # add "gem 'meshcomplete'" to Gemfile
4
+ $ bundle install
5
+ $ rails g meshcomplete # creates migration file, Subject & Synonym model, JavaScript & CSS files
6
+ $ rake db:migrate
7
+ $ rake meshcomplete:load_data
8
+
9
+ # add to config/routes.rb
10
+ match 'meshcomplete-update' => 'genes#top' # change to appropriate controller & method
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,6 @@
1
+ class MeshcompleteController < ApplicationController
2
+ def search
3
+ items = Synonym.search(params[:term])
4
+ render :json => items
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class Subject < ActiveRecord::Base
2
+ has_many :synonyms
3
+ end
@@ -0,0 +1,8 @@
1
+ class Synonym < ActiveRecord::Base
2
+ belongs_to :subject
3
+
4
+ def self.search(starts_with, limit = 10)
5
+ mesh = where(["term LIKE ?", "#{starts_with}%"]).limit(limit).order("term asc").includes(:subject).group_by(&:subject)
6
+ mesh.keys.compact.sort_by(&:term).map {|m| {"id" => m.id, "label" => m.term, "value" => m.term, "entries" => mesh[m].reject {|e| m.term == e.term}.map{|e| e.term}.sort}}
7
+ end
8
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Rails.application.routes.draw do
2
+ mount_at = Meshcomplete::Engine.config.mount_at
3
+ match mount_at + "meshcomplete" => "meshcomplete/meshcomplete#search"
4
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Creates auto-complete search box for MeSH.
3
+
4
+ Example:
5
+ rails generate meshcomplete Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,32 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class MeshcompleteGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ def self.next_migration_number(dirname)
10
+ if ActiveRecord::Base.timestamped_migrations
11
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
12
+ else
13
+ "%.3d" % (current_migration_number(dirname) + 1)
14
+ end
15
+ end
16
+
17
+ def create_subjects_migration_file
18
+ migration_template 'create_subjects.rb', 'db/migrate/create_subjects.rb'
19
+ end
20
+
21
+ def create_synonyms_migration_file
22
+ migration_template 'create_synonyms.rb', 'db/migrate/create_synonyms.rb'
23
+ end
24
+
25
+ def copy_stylesheets
26
+ copy_file 'meshcomplete.css', 'public/stylesheets/meshcomplete.css'
27
+ end
28
+
29
+ def copy_javascripts
30
+ copy_file 'meshcomplete.js', 'public/javascripts/meshcomplete.js'
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ class CreateSubjects < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :subjects do |t|
4
+ t.string :term
5
+ end
6
+ add_index :subjects, :term
7
+ end
8
+
9
+ def self.down
10
+ drop_table :subjects
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ class CreateSynonyms < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :synonyms do |t|
4
+ t.integer :subject_id
5
+ t.string :term
6
+ end
7
+ add_index :synonyms, :subject_id
8
+ add_index :synonyms, :term
9
+ end
10
+
11
+ def self.down
12
+ drop_table :synonyms
13
+ end
14
+ end
@@ -0,0 +1,85 @@
1
+ #meshcomplete-box {
2
+ width: 90%;
3
+ margin: 1em;
4
+ padding: 0.25em 0.25em 0 0.25em;
5
+ border:1px solid #aaa;
6
+ background-color:#fff;
7
+ cursor:text;
8
+ display: block;
9
+ }
10
+ #meshcomplete {
11
+ margin: 0 0 0.25em 0;
12
+ padding: 0;
13
+ border: none;
14
+ display: inline-block;
15
+ font-size: 1em;
16
+ cursor:text;
17
+ }
18
+ #meshcomplete:focus {
19
+ outline-width: 0;
20
+ }
21
+ #meshcomplete-box .selected {
22
+ display:inline-block;
23
+ margin: 0 0.25em 0.25em 0;
24
+ padding: 0 0.25em;
25
+ background-color: #eee;
26
+ border: 1px solid #999;
27
+ -moz-border-radius: 4px;
28
+ -webkit-border-radius: 4px;
29
+ border-radius: 4px;
30
+ color:#333;
31
+ font-size: 1em;
32
+ }
33
+ #meshcomplete-box .operator {
34
+ display:inline-block;
35
+ margin: 0 0.4em 0 0;
36
+ padding: 0 0.25em;
37
+ background-color: #eee;
38
+ border: 1px solid #999;
39
+ -moz-border-radius: 4px;
40
+ -webkit-border-radius: 4px;
41
+ border-radius: 4px;
42
+ color:#999;
43
+ font-size: 0.75em;
44
+ text-align: center;
45
+ cursor: pointer;
46
+ width: 2.5em;
47
+ }
48
+ #meshcomplete-box .operator:hover {
49
+ color: #333;
50
+ }
51
+ #meshcomplete-box .remove {
52
+ display: inline-block;
53
+ margin: 0 0 0 0.25em;
54
+ padding: 0;
55
+ color: #999;
56
+ text-decoration: none;
57
+ font-weight: bold;
58
+ }
59
+ #meshcomplete-box .remove:hover {
60
+ background-color: #eee;
61
+ color: #333;
62
+ }
63
+ #meshcomplete-clear {
64
+ float: right;
65
+ cursor: pointer;
66
+ font-weight: bold;
67
+ color: #999;
68
+ }
69
+ #meshcomplete-clear:hover {
70
+ color: #333;
71
+ }
72
+ .ui-autocomplete {
73
+ width: 20em;
74
+ }
75
+ .ui-menu-item .entry_term {
76
+ font-size: 0.75em;
77
+ color: #999;
78
+ }
79
+ .ui-menu-item .matched {
80
+ font-weight: bold;
81
+ }
82
+ .ui-autocomplete li {
83
+ list-style: none;
84
+ text-align: left;
85
+ }
@@ -0,0 +1,89 @@
1
+ $(function() {
2
+ $("#meshcomplete").attr("value","").attr("size", 5);
3
+ $("#meshcomplete-box").click(function(){
4
+ $("#meshcomplete").focus();
5
+ });
6
+ $("#meshcomplete-box .remove").live("click", function(){
7
+ var removed_id = $(this).parent().attr("data-meshcomplete-id");
8
+ var selected_ids = $("#meshcomplete-selected-ids").attr("value");
9
+ selected_ids = selected_ids.replace(new RegExp("," + removed_id), "");
10
+ $("#meshcomplete-selected-ids").attr("value", selected_ids);
11
+ $(this).parent().remove();
12
+ if ($("#meshcomplete-box .operator").length >= $("#meshcomplete-box .selected").length) {
13
+ $("#meshcomplete-box .operator").last().remove();
14
+ }
15
+ if ($("#meshcomplete-box .selected").length > 0) {
16
+ $.get("/meshcomplete-update", { ids: selected_ids },
17
+ function(data) {
18
+ $("#meshcomplete-update").html(data);
19
+ }
20
+ );
21
+ } else {
22
+ $("#meshcomplete-update").html("");
23
+ }
24
+ });
25
+ $("#meshcomplete-clear").live("click", function(){
26
+ $("#meshcomplete-box .selected").each(function(index) { $(this).remove() });
27
+ $("#meshcomplete-box .operator").each(function(index) { $(this).remove() });
28
+ $("#meshcomplete-selected-ids").attr("value", "");
29
+ $("#meshcomplete").attr("value", "");
30
+ $("#meshcomplete-update").html("");
31
+ });
32
+ $("#meshcomplete").bind('keyup keydown blur update', function(){
33
+ if($("#meshcomplete").attr("size") < $("#meshcomplete").val().length){
34
+ size = $("#meshcomplete").val().length + 5;
35
+ $("#meshcomplete").attr("size",size);
36
+ }
37
+ });
38
+ $("#meshcomplete").autocomplete({
39
+ source: "/meshcomplete",
40
+ select: function(e, ui) {
41
+ var selected = ui.item.value,
42
+ span = $("<span>").addClass("selected").text(selected).attr("data-meshcomplete-id", ui.item.id);
43
+ if ($("#meshcomplete-box .selected").length > 0) {
44
+ var operator = $("<span>").addClass("operator").attr({
45
+ }).html("AND").toggle(
46
+ function () {
47
+ $(this).html("OR");
48
+ },
49
+ function () {
50
+ $(this).html("NOT");
51
+ },
52
+ function () {
53
+ $(this).html("AND");
54
+ }
55
+ );
56
+ operator.insertBefore("#meshcomplete");
57
+ }
58
+ var a = $("<a>").addClass("remove").attr({
59
+ href: "javascript: return false;",
60
+ title: "Remove " + selected
61
+ }).html("&times;").appendTo(span);
62
+ span.insertBefore("#meshcomplete");
63
+ $("#meshcomplete").attr("value","").attr("size", 5);
64
+ var selected_ids = $("#meshcomplete-selected-ids").attr("value").split(",");
65
+ selected_ids.push( ui.item.id );
66
+ $("#meshcomplete-selected-ids").attr("value", selected_ids.join(","));
67
+ $("#meshcomplete-update").html('<img src="/images/loading.gif"> Loading ...').slideDown("slow");
68
+ $.get("/meshcomplete-update", { ids: selected_ids.join(",") },
69
+ function(data) {
70
+ $("#meshcomplete-update").html(data).slideDown("slow");
71
+ }
72
+ );
73
+ return false;
74
+ },
75
+ focus: function() {
76
+ return false;
77
+ }
78
+ })
79
+ .data( "autocomplete" )._renderItem = function( ul, item ) {
80
+ var re_label = new RegExp("^" + this.term, "i");
81
+ var re_entries = new RegExp("(^|\| )" + this.term, "gi");
82
+ var label = item.label.replace(re_label, "<span class='matched'>$&" + "</span>");
83
+ var entries = item.entries.join(" | ").replace(re_entries, "<span class='matched'>" + "$&" + "</span>");
84
+ return $( "<li></li>" )
85
+ .data( "item.autocomplete", item )
86
+ .append("<a>" + label + "<div class='entry_term'>" + entries + "</div>" + "</a>")
87
+ .appendTo( ul );
88
+ };
89
+ });
@@ -0,0 +1,3 @@
1
+ module Meshcomplete
2
+ require "meshcomplete/engine" if defined?(Rails)
3
+ end
@@ -0,0 +1,10 @@
1
+ module Meshcomplete
2
+ module ActionViewExtension
3
+ extend ActiveSupport::Concern
4
+ module InstanceMethods
5
+ def meshcomplete(ids)
6
+ "<div id=\"meshcomplete-box\"><input id=\"meshcomplete\" /><span id=\"meshcomplete-clear\" title=\"Clear search\">&times;</span><input type=\"hidden\" id=\"meshcomplete-selected-ids\" value=\"#{ids}\"/></div><div id=\"meshcomplete-update\"></div>".html_safe
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ require "meshcomplete"
2
+ require "rails"
3
+ require "meshcomplete/action_view_extension"
4
+
5
+ module Meshcomplete
6
+ class Engine < Rails::Engine
7
+ config.mount_at = '/'
8
+
9
+ initializer "check config" do |app|
10
+ config.mount_at += '/' unless config.mount_at.last == '/'
11
+ end
12
+
13
+ initializer 'meshcomplete' do |app|
14
+ ActiveSupport.on_load(:action_view) do
15
+ ActionView::Base.send :include, Meshcomplete::ActionViewExtension
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Meshcomplete
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ require 'open-uri'
2
+ namespace :meshcomplete do
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "meshcomplete/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "meshcomplete"
7
+ s.version = Meshcomplete::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Joon Lee"]
10
+ s.email = ["seouri@gmail.com"]
11
+ s.homepage = "https://github.com/seouri/meshcomplete"
12
+ s.summary = %q{Meshcomplete is a Ruby on Rails engine for MeSH autocomplete search box built with jQuery UI.}
13
+ s.description = %q{}
14
+
15
+ s.rubyforge_project = "meshcomplete"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ s.add_dependency('jquery-rails', '>= 0.2.7');
22
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meshcomplete
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Joon Lee
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-16 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: jquery-rails
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.2.7
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description: ""
28
+ email:
29
+ - seouri@gmail.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - README.rdoc
40
+ - Rakefile
41
+ - app/controllers/meshcomplete_controller.rb
42
+ - app/models/subject.rb
43
+ - app/models/synonym.rb
44
+ - config/routes.rb
45
+ - lib/generators/meshcomplete/USAGE
46
+ - lib/generators/meshcomplete/meshcomplete_generator.rb
47
+ - lib/generators/meshcomplete/templates/create_subjects.rb
48
+ - lib/generators/meshcomplete/templates/create_synonyms.rb
49
+ - lib/generators/meshcomplete/templates/meshcomplete.css
50
+ - lib/generators/meshcomplete/templates/meshcomplete.js
51
+ - lib/meshcomplete.rb
52
+ - lib/meshcomplete/action_view_extension.rb
53
+ - lib/meshcomplete/engine.rb
54
+ - lib/meshcomplete/version.rb
55
+ - lib/tasks/meshcomplete.rake
56
+ - meshcomplete.gemspec
57
+ has_rdoc: true
58
+ homepage: https://github.com/seouri/meshcomplete
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project: meshcomplete
81
+ rubygems_version: 1.6.2
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Meshcomplete is a Ruby on Rails engine for MeSH autocomplete search box built with jQuery UI.
85
+ test_files: []
86
+