quorum 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +35 -28
- data/HISTORY.md +4 -0
- data/app/assets/javascripts/quorum/application.js +1 -0
- data/app/assets/javascripts/quorum/jobs.js +5 -345
- data/app/assets/javascripts/quorum/quorum.js +275 -0
- data/app/assets/javascripts/quorum/template_settings.js +8 -0
- data/app/assets/javascripts/quorum/utilities.js +12 -0
- data/app/assets/stylesheets/quorum/application.css +0 -4
- data/app/assets/stylesheets/quorum/autohint.css +4 -0
- data/app/controllers/quorum/jobs_controller.rb +9 -9
- data/app/views/quorum/jobs/form/_blastn_form.html.erb +62 -62
- data/app/views/quorum/jobs/form/_blastp_form.html.erb +62 -62
- data/app/views/quorum/jobs/form/_blastx_form.html.erb +62 -62
- data/app/views/quorum/jobs/form/_tblastn_form.html.erb +62 -62
- data/app/views/quorum/jobs/show.html.erb +1 -1
- data/app/views/quorum/jobs/templates/_blast_detailed_report_template.html.erb +22 -22
- data/app/views/quorum/jobs/templates/_blast_template.html.erb +29 -29
- data/app/views/shared/_error_messages.html.erb +8 -8
- data/lib/quorum/version.rb +1 -1
- data/lib/tasks/jasmine.rake +8 -0
- data/quorum.gemspec +1 -0
- data/spec/data/seqs_not_fa.txt +16 -16
- data/spec/javascripts/fixtures/formatted_sequence.html +6 -0
- data/spec/javascripts/fixtures/quorum_search_form.html +461 -0
- data/spec/javascripts/fixtures/quorum_tabs.html +10 -0
- data/spec/javascripts/helpers/jasmine-jquery.js +288 -0
- data/spec/javascripts/jobs_spec.js +99 -0
- data/spec/javascripts/jquery/jquery-ui.min.js +791 -0
- data/spec/javascripts/jquery/jquery.min.js +4 -0
- data/spec/javascripts/jquery/jquery_ujs.js +373 -0
- data/spec/javascripts/quorum_spec.js +106 -0
- data/spec/javascripts/string_spec.js +18 -0
- data/spec/javascripts/support/jasmine.yml +84 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +33 -0
- data/spec/requests/jobs_spec.rb +34 -33
- data/vendor/assets/javascripts/jquery.autohint.js +87 -0
- metadata +62 -26
@@ -0,0 +1,106 @@
|
|
1
|
+
//
|
2
|
+
// Test the methods not covered in RSpec request specs.
|
3
|
+
//
|
4
|
+
|
5
|
+
describe("QUORUM", function() {
|
6
|
+
|
7
|
+
//
|
8
|
+
// Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
|
9
|
+
//
|
10
|
+
// Blastn should increment qseq's title by 1 and hseq's title by 1.
|
11
|
+
//
|
12
|
+
it("formats blastn sequence report for Blast detailed report", function() {
|
13
|
+
var report = QUORUM.formatSequenceReport(
|
14
|
+
"ACGT", "|| |", "ACCT", 6, 9, 2, 8, "blastn"
|
15
|
+
);
|
16
|
+
expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=7>C</a><a rel='quorum-tipsy' title=8>G</a><a rel='quorum-tipsy' title=9>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
|
17
|
+
});
|
18
|
+
|
19
|
+
//
|
20
|
+
// Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
|
21
|
+
//
|
22
|
+
// Blastx should increment qseq's title by 3 and hseq's title by 1.
|
23
|
+
//
|
24
|
+
it("formats blastx sequence report for Blast detailed report", function() {
|
25
|
+
var report = QUORUM.formatSequenceReport(
|
26
|
+
"ACGT", "|| |", "ACCT", 6, 9, 2, 8, "blastx"
|
27
|
+
);
|
28
|
+
expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=9>C</a><a rel='quorum-tipsy' title=12>G</a><a rel='quorum-tipsy' title=15>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
|
29
|
+
});
|
30
|
+
|
31
|
+
//
|
32
|
+
// Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
|
33
|
+
//
|
34
|
+
// Tblastn should increment qseq's title by 1 and hseq's title by 3.
|
35
|
+
//
|
36
|
+
it("formats tblastn sequence report for Blast detailed report", function() {
|
37
|
+
var report = QUORUM.formatSequenceReport(
|
38
|
+
"ELVIS", "ELVIS", "ELVIS", 10, 14, 121, 136, "tblastn"
|
39
|
+
);
|
40
|
+
expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=124>L</a><a rel='quorum-tipsy' title=127>V</a><a rel='quorum-tipsy' title=130>I</a><a rel='quorum-tipsy' title=133>S</a>\n\n</pre></span>");
|
41
|
+
});
|
42
|
+
|
43
|
+
//
|
44
|
+
// Spec covers QUORUM.formatSequenceReport & QUORUM.addBaseTitleIndex.
|
45
|
+
//
|
46
|
+
// Blastp should increment qseq's title by 1 and hseq's title by 1.
|
47
|
+
//
|
48
|
+
it("formats blastx sequence report for Blast detailed report", function() {
|
49
|
+
var report = QUORUM.formatSequenceReport(
|
50
|
+
"ELVIS", "ELVIS", "ELVIS", 10, 14, 121, 125, "blastp"
|
51
|
+
);
|
52
|
+
expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=122>L</a><a rel='quorum-tipsy' title=123>V</a><a rel='quorum-tipsy' title=124>I</a><a rel='quorum-tipsy' title=125>S</a>\n\n</pre></span>");
|
53
|
+
});
|
54
|
+
|
55
|
+
it("should display title via jquery.tipsy on mouse over hide on mouse out", function() {
|
56
|
+
loadFixtures('formatted_sequence.html');
|
57
|
+
$('a[rel=quorum-tipsy]').tipsy({ gravity: 's' });
|
58
|
+
|
59
|
+
$('a[rel=quorum-tipsy]').trigger('mouseover');
|
60
|
+
expect($('.tipsy')).toBeVisible();
|
61
|
+
|
62
|
+
$('a[rel=quorum-tipsy]').trigger('mouseout');
|
63
|
+
expect($('.tipsy')).not.toBeVisible();
|
64
|
+
});
|
65
|
+
|
66
|
+
it("prints hit strand as forward / forward for + / + intergers", function() {
|
67
|
+
expect(QUORUM.formatStrand(1, 1)).toEqual("forward / forward");
|
68
|
+
});
|
69
|
+
|
70
|
+
it("prints hit strand as forward / reverse for + / - integers", function() {
|
71
|
+
expect(QUORUM.formatStrand(1, -1)).toEqual("forward / reverse");
|
72
|
+
});
|
73
|
+
|
74
|
+
it("prints hit strand as reverse / forward for - / + integers", function() {
|
75
|
+
expect(QUORUM.formatStrand(-1, 1)).toEqual("reverse / forward");
|
76
|
+
});
|
77
|
+
|
78
|
+
it("prints hit strand as reverse / reverse for - / - integers", function() {
|
79
|
+
expect(QUORUM.formatStrand(-1, -1)).toEqual("reverse / reverse");
|
80
|
+
});
|
81
|
+
|
82
|
+
//
|
83
|
+
// Only print links to HSPs whers data id != focus.
|
84
|
+
//
|
85
|
+
it("prints HSP links", function() {
|
86
|
+
var focus = 1;
|
87
|
+
var group = "1,2";
|
88
|
+
var data = [
|
89
|
+
{"id":1,"hsp_group":"1,2","hsp_num":1},
|
90
|
+
{"id":2,"hsp_group":"1,2","hsp_num":2}
|
91
|
+
];
|
92
|
+
var hsps = QUORUM.displayHspLinks(focus, group, data);
|
93
|
+
expect(hsps).toEqual("Related <a onclick=\"(QUORUM.openWindow('http://www.ncbi.nlm.nih.gov/books/NBK62051/def-item/blast_glossary.HSP','HSP', 800, 300))\">HSPs</a>: 1 <a onclick='(QUORUM.autoScroll(2, true))'>2</a> ");
|
94
|
+
});
|
95
|
+
|
96
|
+
it("opens url in a new window", function() {
|
97
|
+
spyOn(window, 'open');
|
98
|
+
var url = "http://google.com";
|
99
|
+
var name = "Google";
|
100
|
+
var width = 300;
|
101
|
+
var height = 300;
|
102
|
+
QUORUM.openWindow(url, name, width, height);
|
103
|
+
expect(window.open).toHaveBeenCalledWith(url, name, "width=" + width + ",height=" + height + ",scrollbars=yes");
|
104
|
+
});
|
105
|
+
|
106
|
+
});
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe("String", function() {
|
2
|
+
|
3
|
+
it("truncates a string to length n", function() {
|
4
|
+
var str = "this is a long string.";
|
5
|
+
expect(str.trunc(5)).toEqual("this...");
|
6
|
+
});
|
7
|
+
|
8
|
+
it("truncates a string to length n", function() {
|
9
|
+
var str = "this is a long string.";
|
10
|
+
expect(str.trunc(15)).toEqual("this is a long...");
|
11
|
+
});
|
12
|
+
|
13
|
+
it("doesn't truncate string when length is less than n", function() {
|
14
|
+
var str = "this is a long string.";
|
15
|
+
expect(str.trunc(50)).toEqual(str);
|
16
|
+
});
|
17
|
+
|
18
|
+
});
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# src_files
|
2
|
+
#
|
3
|
+
# Return an array of filepaths relative to src_dir to include before jasmine specs.
|
4
|
+
# Default: []
|
5
|
+
#
|
6
|
+
# EXAMPLE:
|
7
|
+
#
|
8
|
+
# src_files:
|
9
|
+
# - lib/source1.js
|
10
|
+
# - lib/source2.js
|
11
|
+
# - dist/**/*.js
|
12
|
+
#
|
13
|
+
src_files:
|
14
|
+
- spec/javascripts/jquery/jquery.min.js
|
15
|
+
- spec/javascripts/jquery/jquery-ui.min.js
|
16
|
+
- spec/javascripts/jquery/jquery_ujs.js
|
17
|
+
- vendor/assets/javascripts/underscore-min.js
|
18
|
+
- app/assets/javascripts/quorum/jobs.js
|
19
|
+
- app/assets/javascripts/quorum/quorum.js
|
20
|
+
- app/assets/javascripts/quorum/utilities.js
|
21
|
+
- app/assets/javascripts/quorum/template_settings.js
|
22
|
+
- vendor/assets/javascripts/jquery.autohint.js
|
23
|
+
- vendor/assets/javascripts/jquery.tipsy.js
|
24
|
+
|
25
|
+
# stylesheets
|
26
|
+
#
|
27
|
+
# Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
|
28
|
+
# Default: []
|
29
|
+
#
|
30
|
+
# EXAMPLE:
|
31
|
+
#
|
32
|
+
# stylesheets:
|
33
|
+
# - css/style.css
|
34
|
+
# - stylesheets/*.css
|
35
|
+
#
|
36
|
+
stylesheets:
|
37
|
+
|
38
|
+
# helpers
|
39
|
+
#
|
40
|
+
# Return an array of filepaths relative to spec_dir to include before jasmine specs.
|
41
|
+
# Default: ["helpers/**/*.js"]
|
42
|
+
#
|
43
|
+
# EXAMPLE:
|
44
|
+
#
|
45
|
+
# helpers:
|
46
|
+
# - helpers/**/*.js
|
47
|
+
#
|
48
|
+
helpers:
|
49
|
+
- helpers/**/*.js
|
50
|
+
|
51
|
+
# spec_files
|
52
|
+
#
|
53
|
+
# Return an array of filepaths relative to spec_dir to include.
|
54
|
+
# Default: ["**/*[sS]pec.js"]
|
55
|
+
#
|
56
|
+
# EXAMPLE:
|
57
|
+
#
|
58
|
+
# spec_files:
|
59
|
+
# - **/*[sS]pec.js
|
60
|
+
#
|
61
|
+
spec_files:
|
62
|
+
- '**/*[sS]pec.js'
|
63
|
+
|
64
|
+
# src_dir
|
65
|
+
#
|
66
|
+
# Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
|
67
|
+
# Default: project root
|
68
|
+
#
|
69
|
+
# EXAMPLE:
|
70
|
+
#
|
71
|
+
# src_dir: public
|
72
|
+
#
|
73
|
+
src_dir:
|
74
|
+
|
75
|
+
# spec_dir
|
76
|
+
#
|
77
|
+
# Spec directory path. Your spec_files must be returned relative to this path.
|
78
|
+
# Default: spec/javascripts
|
79
|
+
#
|
80
|
+
# EXAMPLE:
|
81
|
+
#
|
82
|
+
# spec_dir: spec/javascripts
|
83
|
+
#
|
84
|
+
spec_dir: spec/javascripts
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Jasmine
|
2
|
+
class Config
|
3
|
+
|
4
|
+
# Add your overrides or custom config code here
|
5
|
+
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# Note - this is necessary for rspec2, which has removed the backtrace
|
11
|
+
module Jasmine
|
12
|
+
class SpecBuilder
|
13
|
+
def declare_spec(parent, spec)
|
14
|
+
me = self
|
15
|
+
example_name = spec["name"]
|
16
|
+
@spec_ids << spec["id"]
|
17
|
+
backtrace = @example_locations[parent.description + " " + example_name]
|
18
|
+
parent.it example_name, {} do
|
19
|
+
me.report_spec(spec["id"])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
$:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require File.expand_path("../../../dummy/config/environment", __FILE__)
|
5
|
+
require 'jasmine'
|
6
|
+
jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
|
7
|
+
require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
|
8
|
+
if Jasmine::Dependencies.rspec2?
|
9
|
+
require 'rspec'
|
10
|
+
else
|
11
|
+
require 'spec'
|
12
|
+
end
|
13
|
+
|
14
|
+
jasmine_config = Jasmine::Config.new
|
15
|
+
spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
|
16
|
+
|
17
|
+
should_stop = false
|
18
|
+
|
19
|
+
if Jasmine::Dependencies.rspec2?
|
20
|
+
RSpec.configuration.after(:suite) do
|
21
|
+
spec_builder.stop if should_stop
|
22
|
+
end
|
23
|
+
else
|
24
|
+
Spec::Runner.configure do |config|
|
25
|
+
config.after(:suite) do
|
26
|
+
spec_builder.stop if should_stop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
spec_builder.start
|
32
|
+
should_stop = true
|
33
|
+
spec_builder.declare_suites
|
data/spec/requests/jobs_spec.rb
CHANGED
@@ -17,7 +17,7 @@ describe "Jobs" do
|
|
17
17
|
click_button "Submit"
|
18
18
|
|
19
19
|
page.should have_content("Please enter your sequence(s) in Plain Text " <<
|
20
|
-
|
20
|
+
"as FASTA.")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -30,7 +30,7 @@ describe "Jobs" do
|
|
30
30
|
attach_file "job_sequence_file", word_file
|
31
31
|
click_button "Submit"
|
32
32
|
page.should have_content("Please enter your sequence(s) in Plain Text " <<
|
33
|
-
|
33
|
+
"as FASTA.")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -43,7 +43,7 @@ describe "Jobs" do
|
|
43
43
|
attach_file "job_sequence_file", file
|
44
44
|
click_button "Submit"
|
45
45
|
page.should have_content("Please enter your sequence(s) in Plain Text " <<
|
46
|
-
|
46
|
+
"as FASTA.")
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -56,71 +56,72 @@ describe "Jobs" do
|
|
56
56
|
ResqueSpec.inline = true
|
57
57
|
end
|
58
58
|
describe "submit sequences in attached file" do
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
it "check algorithms, fill in values, view results and download hit sequence" do
|
60
|
+
visit new_job_path
|
61
|
+
current_path.should eq(new_job_path)
|
62
|
+
|
63
|
+
nucl_seqs = File.expand_path("../../data/nucl_prot_seqs.txt", __FILE__)
|
64
|
+
attach_file "job_sequence_file", nucl_seqs
|
65
|
+
|
66
66
|
# Blastn
|
67
|
-
|
68
|
-
|
67
|
+
check "job_blastn_job_attributes_queue"
|
68
|
+
select "tmp", :from => "job_blastn_job_attributes_blast_dbs"
|
69
69
|
check "job_blastn_job_attributes_filter"
|
70
70
|
fill_in "job_blastn_job_attributes_expectation", :with => "5e-20"
|
71
71
|
fill_in "job_blastn_job_attributes_min_bit_score", :with => "0"
|
72
72
|
fill_in "job_blastn_job_attributes_max_score", :with => "25"
|
73
73
|
select "Yes", :from => "job_blastn_job_attributes_gapped_alignments"
|
74
74
|
select "11, 2", :from => "job_blastn_job_attributes_gap_opening_extension"
|
75
|
-
|
75
|
+
|
76
76
|
# Blastx
|
77
|
-
|
78
|
-
|
77
|
+
check "job_blastx_job_attributes_queue"
|
78
|
+
select "tmp", :from => "job_blastx_job_attributes_blast_dbs"
|
79
79
|
check "job_blastx_job_attributes_filter"
|
80
80
|
fill_in "job_blastx_job_attributes_expectation", :with => "5e-20"
|
81
81
|
fill_in "job_blastx_job_attributes_min_bit_score", :with => "0"
|
82
82
|
fill_in "job_blastx_job_attributes_max_score", :with => "25"
|
83
83
|
select "Yes", :from => "job_blastx_job_attributes_gapped_alignments"
|
84
84
|
select "10, 2", :from => "job_blastx_job_attributes_gap_opening_extension"
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
|
86
|
+
# Tblastn
|
87
|
+
check "job_tblastn_job_attributes_queue"
|
88
|
+
select "tmp", :from => "job_tblastn_job_attributes_blast_dbs"
|
89
89
|
check "job_tblastn_job_attributes_filter"
|
90
90
|
fill_in "job_tblastn_job_attributes_expectation", :with => "5e-20"
|
91
91
|
fill_in "job_tblastn_job_attributes_min_bit_score", :with => "0"
|
92
92
|
fill_in "job_tblastn_job_attributes_max_score", :with => "25"
|
93
93
|
select "Yes", :from => "job_tblastn_job_attributes_gapped_alignments"
|
94
94
|
select "9, 2", :from => "job_tblastn_job_attributes_gap_opening_extension"
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
|
96
|
+
# Blastp
|
97
|
+
check "job_blastp_job_attributes_queue"
|
98
|
+
select "tmp", :from => "job_blastp_job_attributes_blast_dbs"
|
99
99
|
check "job_blastp_job_attributes_filter"
|
100
100
|
fill_in "job_blastp_job_attributes_expectation", :with => "5e-20"
|
101
101
|
fill_in "job_blastp_job_attributes_min_bit_score", :with => "0"
|
102
102
|
fill_in "job_blastp_job_attributes_max_score", :with => "25"
|
103
103
|
select "Yes", :from => "job_blastp_job_attributes_gapped_alignments"
|
104
104
|
select "13, 1", :from => "job_blastp_job_attributes_gap_opening_extension"
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
105
|
+
|
106
|
+
click_button "Submit"
|
107
|
+
|
108
|
+
page.should have_content("Search Results")
|
109
|
+
|
110
110
|
click_link "Blastx"
|
111
|
-
|
111
|
+
page.should have_content("Your search returned 0 hits.")
|
112
112
|
|
113
113
|
click_link "Tblastn"
|
114
|
-
|
114
|
+
page.should have_content("Your search returned 0 hits.")
|
115
115
|
|
116
116
|
## Interact with the Blast results. ##
|
117
117
|
click_link "Blastn"
|
118
118
|
|
119
119
|
# Render modal box.
|
120
|
-
|
120
|
+
find("#blastn-results").find("td a").click
|
121
121
|
page.should have_content("Quorum Report Details")
|
122
122
|
page.should have_content("qseq")
|
123
123
|
page.should have_content("hseq")
|
124
|
+
|
124
125
|
# Download sequence
|
125
126
|
find("p.small a#download_sequence_1").click
|
126
127
|
page.should have_content("Fetching sequence...")
|
@@ -129,11 +130,11 @@ describe "Jobs" do
|
|
129
130
|
click_link "Blastp"
|
130
131
|
|
131
132
|
# Render modal box.
|
132
|
-
|
133
|
+
find("#blastp-results").find("td a").click
|
133
134
|
page.should have_content("Quorum Report Details")
|
134
135
|
page.should have_content("qseq")
|
135
136
|
page.should have_content("hseq")
|
136
|
-
|
137
|
+
end
|
137
138
|
end
|
138
139
|
after(:all) do
|
139
140
|
Capybara.use_default_driver
|
@@ -0,0 +1,87 @@
|
|
1
|
+
//
|
2
|
+
// jQuery autoHint
|
3
|
+
//
|
4
|
+
// v0.2.0
|
5
|
+
// Ken Seal hunzinker@gmail.com
|
6
|
+
// License: MIT
|
7
|
+
|
8
|
+
(function($) {
|
9
|
+
|
10
|
+
var methods = {
|
11
|
+
|
12
|
+
init: function() {
|
13
|
+
return this.each(function() {
|
14
|
+
var $this = $(this);
|
15
|
+
$this.autoHint('addHints');
|
16
|
+
$this.autoHint('focusHint');
|
17
|
+
$this.autoHint('blurHint');
|
18
|
+
});
|
19
|
+
},
|
20
|
+
|
21
|
+
// Add hints to the form elements.
|
22
|
+
addHints: function() {
|
23
|
+
return this.each(function() {
|
24
|
+
var $this = $(this);
|
25
|
+
if ($this.attr('title') === '') {
|
26
|
+
return;
|
27
|
+
}
|
28
|
+
|
29
|
+
if ($this.val() === '') {
|
30
|
+
$this.val($this.attr('title'));
|
31
|
+
|
32
|
+
if (!$this.hasClass('auto-hint')) {
|
33
|
+
$this.addClass('auto-hint');
|
34
|
+
}
|
35
|
+
} else {
|
36
|
+
$this.removeClass('auto-hint');
|
37
|
+
}
|
38
|
+
});
|
39
|
+
},
|
40
|
+
|
41
|
+
// Remove hint and class on focus.
|
42
|
+
focusHint: function() {
|
43
|
+
return this.focus(function() {
|
44
|
+
var $this = $(this);
|
45
|
+
if ($this.val() === $this.attr('title')) {
|
46
|
+
$this.val('');
|
47
|
+
$this.removeClass('auto-hint');
|
48
|
+
}
|
49
|
+
});
|
50
|
+
},
|
51
|
+
|
52
|
+
// Retain value or add hint.
|
53
|
+
blurHint: function() {
|
54
|
+
return this.blur(function() {
|
55
|
+
var $this = $(this);
|
56
|
+
if ($this.val() === '' && $this.attr('title') !== '') {
|
57
|
+
$this.val($this.attr('title'));
|
58
|
+
$this.addClass('auto-hint');
|
59
|
+
}
|
60
|
+
});
|
61
|
+
},
|
62
|
+
|
63
|
+
// Remove hints.
|
64
|
+
removeHints: function() {
|
65
|
+
return this.each(function() {
|
66
|
+
var $this = $(this);
|
67
|
+
if ($this.val() === $this.attr('title')) {
|
68
|
+
$this.val('');
|
69
|
+
}
|
70
|
+
});
|
71
|
+
}
|
72
|
+
|
73
|
+
};
|
74
|
+
|
75
|
+
$.fn.autoHint = function(method) {
|
76
|
+
|
77
|
+
if (methods[method]) {
|
78
|
+
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
79
|
+
} else if (typeof method === 'object' || !method) {
|
80
|
+
return methods.init.apply(this, arguments);
|
81
|
+
} else {
|
82
|
+
$.error('Method ' + method + ' does not exist for jQuery autoHint.');
|
83
|
+
}
|
84
|
+
|
85
|
+
};
|
86
|
+
|
87
|
+
})(jQuery);
|