meshcomplete 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.rdoc +10 -0
- data/Rakefile +2 -0
- data/app/controllers/meshcomplete_controller.rb +6 -0
- data/app/models/subject.rb +3 -0
- data/app/models/synonym.rb +8 -0
- data/config/routes.rb +4 -0
- data/lib/generators/meshcomplete/USAGE +8 -0
- data/lib/generators/meshcomplete/meshcomplete_generator.rb +32 -0
- data/lib/generators/meshcomplete/templates/create_subjects.rb +12 -0
- data/lib/generators/meshcomplete/templates/create_synonyms.rb +14 -0
- data/lib/generators/meshcomplete/templates/meshcomplete.css +85 -0
- data/lib/generators/meshcomplete/templates/meshcomplete.js +89 -0
- data/lib/meshcomplete.rb +3 -0
- data/lib/meshcomplete/action_view_extension.rb +10 -0
- data/lib/meshcomplete/engine.rb +19 -0
- data/lib/meshcomplete/version.rb +3 -0
- data/lib/tasks/meshcomplete.rake +3 -0
- data/meshcomplete.gemspec +22 -0
- metadata +86 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
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,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,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,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("×").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
|
+
});
|
data/lib/meshcomplete.rb
ADDED
@@ -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\">×</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,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
|
+
|