meshcomplete 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|