michael_hintbuble 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,171 @@
1
+ module Coroutine #:nodoc:
2
+ module MichaelHintbuble #:nodoc:
3
+ module Helpers #:nodoc:
4
+
5
+ # This method returns a javascript tag containing the hint bubble initialization logic. The first argument
6
+ # to this method is <tt>target_id</tt>, the id of the html element to which the hint bubble is anchored.
7
+ # The target_id is required and should be unique (duh). Further options may be provided; those that
8
+ # are specific to the hint bubble are:
9
+ #
10
+ # * <tt>:class</tt> - the css style to assign to the outermost div container (defaults to "michael_hintbuble_bubble")
11
+ # * <tt>:style</tt> - additional css style assignments for outermost div container (defaults to "")
12
+ # * <tt>:position</tt> - css-style value that specifies the hint bubble's relative position, e.g., top, bottom, right, or left (defaults to right)
13
+ # * <tt>:event_names</tt> - an array of strings specifying the events that should trigger the display of the hint bubble
14
+ # * <tt>:before_show</tt> - a Javascript function that will be invoked before the hint bubble is shown
15
+ # * <tt>:after_show</tt> - a Javascript function that will be invoked after the hint bubble has been shown
16
+ # * <tt>:before_hide</tt> - a Javascript function that will be invoked before the hint bubble is hidden
17
+ # * <tt>:after_hide</tt> - a Javascript function that will be invoked after the hint bubble has been hidden
18
+ # * <tt>&block</tt> - HTML markup that will be automatically converted to render's inline option
19
+ #
20
+ # All remaining options are the same as the options available to ActionController::Base#render. Please
21
+ # see the documentation for ActionController::Base#render for further details.
22
+ #
23
+ # ==== Events
24
+ #
25
+ # The library manages repositioning the hint bubble in response to window resizing and scrolling events automatically.
26
+ # You do not need to specify <tt>resize</tt> or <tt>scroll</tt> in the optional event names array.
27
+ #
28
+ # The library defaults to trapping mouse gestures, but it is capable of trapping focus events in addition
29
+ # to or in place of mouse events. When specifying events, you need only reference the positive action: the
30
+ # library can infer the corresponding action to toggle off the tooltip.
31
+ #
32
+ # Valid entries for the events array are any combination of the following options:
33
+ #
34
+ # * <tt>"focus"</tt>
35
+ # * <tt>"mouseover"</tt>
36
+ #
37
+ #
38
+ # ==== Example
39
+ #
40
+ # # Generates:
41
+ # #
42
+ # # <script type="text/javascript">
43
+ # # //<![CDATA[
44
+ # # MichaelHintbuble.Bubble.instances["foo_target_id"] = new MichaelHintbuble.Bubble("What up, foo?", { "event_names": ["mouseover"], "position": "top center" });
45
+ # # //]]>
46
+ # # </script>
47
+ # <%= render_bubble :foo_target_id, :content => "What up, foo?", :position => "top center" %>
48
+ #
49
+ # In this case, a simple hint bubble is produced with the specified text content. The bubble responds to mouseover/mouseout
50
+ # events and centers itself above the target element when shown.
51
+ #
52
+ #
53
+ # ==== Example
54
+ #
55
+ # # Generates:
56
+ # #
57
+ # # <script type="text/javascript">
58
+ # # //<![CDATA[
59
+ # # MichaelHintbuble.Bubble.instances["bar_target_id"] = new MichaelHintbuble.Bubble("<ul><li>Item 1</li><li>Item 2</li></ul>", { "event_names": ["focus"], "position": "center left" });
60
+ # # //]]>
61
+ # # </script>
62
+ # <%= render_bubble :bar_target_id, :event_names => ["focus"], :position => "center left" %>
63
+ # <ul>
64
+ # <li>Item 1</li>
65
+ # <li>Item 2</li>
66
+ # </ul>
67
+ # <% end %>
68
+ #
69
+ # In this case, a slightly more complex hint bubble is produced with the specified markup. The bubble responds to focus/blur
70
+ # events and positions itself to the left of the target.
71
+ #
72
+ def render_bubble(target_id, options = {}, &block)
73
+ options[:inline] = capture(&block) if block_given?
74
+ render_options = extract_bubble_render_options(options, &block)
75
+ javascript_options = bubble_options_to_js(extract_bubble_javascript_options(options))
76
+
77
+ content = escape_javascript(render(options))
78
+
79
+ raise "You gotta specify a target id to register a hint bubble, baby." unless target_id
80
+ raise "You gotta provide content to register a hint bubble, baby." unless content
81
+
82
+ javascript_tag "Event.observe(window, 'load', function() { MichaelHintbuble.Bubble.instances['#{target_id}'] = new MichaelHintbuble.Bubble('#{target_id}', '#{content}', #{javascript_options}) });"
83
+ end
84
+
85
+
86
+ # This method returns a Javascript string that will show the bubble attached to the supplied
87
+ # target id.
88
+ #
89
+ def show_bubble(target_id)
90
+ "MichaelHintbuble.Bubble.show('#{target_id}');"
91
+ end
92
+
93
+
94
+ # This method returns a Javascript string that will hide the bubble attached to the supplied
95
+ # target id.
96
+ #
97
+ def hide_bubble(target_id)
98
+ "MichaelHintbuble.Bubble.hide('#{target_id}');"
99
+ end
100
+
101
+
102
+
103
+ private
104
+
105
+ # This method returns an array of javascript option keys supported by the accompanying
106
+ # javascript library.
107
+ #
108
+ def bubble_javascript_option_keys
109
+ [:class, :style, :position, :event_names, :before_show, :after_show, :before_hide, :after_hide]
110
+ end
111
+
112
+
113
+ # This method converts ruby hashes using underscore notation to js strings using camelcase
114
+ # notation, which is more common in javascript.
115
+ #
116
+ def bubble_options_to_js(options={})
117
+ js_kv_pairs = []
118
+ sorted_keys = options.keys.map { |k| k.to_s }.sort.map { |s| s.to_sym }
119
+
120
+ sorted_keys.each do |key|
121
+ js_key = key.to_s.camelcase(:lower)
122
+ js_value = "null"
123
+
124
+ unless options[key].empty?
125
+ case key
126
+ when :before_show, :after_show, :before_hide, :after_hide
127
+ js_value = "#{options[key]}"
128
+ when :event_names
129
+ js_value = "['" + options[key].join("','") + "']"
130
+ else
131
+ js_value = "'#{options[key]}'"
132
+ end
133
+ end
134
+
135
+ js_kv_pairs << "#{js_key}:#{js_value}"
136
+ end
137
+
138
+ "{#{js_kv_pairs.join(',')}}"
139
+ end
140
+
141
+
142
+ # This method returns a hash with javascript options. It also inspects the supplied options
143
+ # and adds defaults as necessary.
144
+ #
145
+ def extract_bubble_javascript_options(options)
146
+ js_options = options.reject { |k,v| !bubble_javascript_option_keys.include?(k) }
147
+
148
+ js_options[:class] = "michael_hintbuble_bubble" if js_options[:class].blank?
149
+ js_options[:position] = "right" if js_options[:position].blank?
150
+ js_options[:event_names] = [] if js_options[:event_names].blank?
151
+
152
+ js_options[:class] = js_options[:class].to_s
153
+ js_options[:event_names] = js_options[:event_names].uniq.map { |en| en.to_s }
154
+ js_options[:event_names] << "mouseover" if js_options[:event_names].empty?
155
+ js_options[:event_names] << "resize" unless js_options[:event_names].include?("resize")
156
+ js_options[:event_names] << "scroll" unless js_options[:event_names].include?("scroll")
157
+
158
+ js_options
159
+ end
160
+
161
+
162
+ # This method returns a hash with rendering options. It also inspects the supplied options
163
+ # and adds defaults as necessary.
164
+ #
165
+ def extract_bubble_render_options(options)
166
+ options.reject { |k,v| bubble_javascript_option_keys.include?(k) }
167
+ end
168
+
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,10 @@
1
+ # external gems
2
+ require "action_pack"
3
+
4
+
5
+ # helpers
6
+ require File.dirname(__FILE__) + "/michael_hintbuble/helpers"
7
+
8
+
9
+ # add action view extensions
10
+ ActionView::Base.module_eval { include Coroutine::MichaelHintbuble::Helpers }
@@ -0,0 +1,67 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{michael_hintbuble}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Coroutine", "Tim Lowrimore", "John Dugan"]
12
+ s.date = %q{2010-10-10}
13
+ s.description = %q{Michael HintBuble allows you to generate hint bubbles and tooltips in Rails applications using the same syntax used for rendering templates.}
14
+ s.email = %q{gems@coroutine.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ ".specification",
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "generators/michael_hintbuble/michael_hintbuble_generator.rb",
26
+ "generators/michael_hintbuble/templates/michael_hintbuble.css",
27
+ "generators/michael_hintbuble/templates/michael_hintbuble.js",
28
+ "generators/michael_hintbuble/templates/michael_hintbuble_pointer.png",
29
+ "init.rb",
30
+ "lib/generators/michael_hintbuble/michael_hintbuble_generator.rb",
31
+ "lib/generators/michael_hintbuble/templates/michael_hintbuble.css",
32
+ "lib/generators/michael_hintbuble/templates/michael_hintbuble.js",
33
+ "lib/generators/michael_hintbuble/templates/michael_hintbuble_pointer.png",
34
+ "lib/michael_hintbuble.rb",
35
+ "lib/michael_hintbuble/helpers.rb",
36
+ "michael_hintbuble.gemspec",
37
+ "rails/init.rb",
38
+ "test/michael_hintbuble/helpers_test.rb",
39
+ "test/test_helper.rb"
40
+ ]
41
+ s.homepage = %q{http://github.com/coroutine/michael_hintbuble}
42
+ s.rdoc_options = ["--charset=UTF-8"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.3.7}
45
+ s.summary = %q{Dead simple, beautiful hint bubbles for Rails.}
46
+ s.test_files = [
47
+ "test/michael_hintbuble/helpers_test.rb",
48
+ "test/test_helper.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<actionpack>, [">= 2.3.4"])
57
+ s.add_development_dependency(%q<activesupport>, [">= 2.3.4"])
58
+ else
59
+ s.add_dependency(%q<actionpack>, [">= 2.3.4"])
60
+ s.add_dependency(%q<activesupport>, [">= 2.3.4"])
61
+ end
62
+ else
63
+ s.add_dependency(%q<actionpack>, [">= 2.3.4"])
64
+ s.add_dependency(%q<activesupport>, [">= 2.3.4"])
65
+ end
66
+ end
67
+
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "michael_hintbuble"
@@ -0,0 +1,156 @@
1
+ #---------------------------------------------------------
2
+ # Requirements
3
+ #---------------------------------------------------------
4
+
5
+ # all generic stuff required by test helper
6
+ require "test/test_helper"
7
+
8
+
9
+
10
+ #---------------------------------------------------------
11
+ # Class Definitions
12
+ #---------------------------------------------------------
13
+
14
+ class TestView < ActionView::Base
15
+ end
16
+
17
+
18
+
19
+ #---------------------------------------------------------
20
+ # Tests
21
+ #---------------------------------------------------------
22
+
23
+ class MichaelHintbubleHelpersTest < ActionView::TestCase
24
+
25
+ def setup
26
+ @view = TestView.new
27
+ end
28
+
29
+
30
+ def test_composition
31
+ assert @view.respond_to?(:render_bubble, false)
32
+ assert @view.respond_to?(:show_bubble, false)
33
+ assert @view.respond_to?(:hide_bubble, false)
34
+ assert @view.respond_to?(:bubble_javascript_option_keys, true)
35
+ assert @view.respond_to?(:bubble_options_to_js, true)
36
+ assert @view.respond_to?(:extract_bubble_javascript_options, true)
37
+ assert @view.respond_to?(:extract_bubble_render_options, true)
38
+ end
39
+
40
+
41
+ #---------------------------------------------------------
42
+ # Public methods
43
+ #---------------------------------------------------------
44
+
45
+ def test_render_bubble_with_simple_options
46
+ text = "Who wants to play volleyball on a court with a four-foot net?"
47
+ default_options = "{class:'michael_hintbuble_bubble',eventNames:['mouseover','resize','scroll'],position:'right'}"
48
+
49
+ expected = "<script type=\"text/javascript\">\n" \
50
+ "//<![CDATA[\n" \
51
+ "Event.observe(window, 'load', function() { MichaelHintbuble.Bubble.instances['come_fly_with_me'] = new MichaelHintbuble.Bubble('come_fly_with_me', '#{text}', #{default_options}) });\n" \
52
+ "//]]>\n" \
53
+ "</script>"
54
+ actual = @view.render_bubble(:come_fly_with_me, :text => text)
55
+
56
+ assert_equal expected, actual
57
+ end
58
+
59
+
60
+ def test_show_bubble
61
+ expected = "MichaelHintbuble.Bubble.show('come_fly_with_me');"
62
+ actual = @view.show_bubble(:come_fly_with_me)
63
+
64
+ assert_equal expected, actual
65
+ end
66
+
67
+
68
+ def test_hide_dialog
69
+ expected = "MichaelHintbuble.Bubble.hide('come_fly_with_me');"
70
+ actual = @view.hide_bubble(:come_fly_with_me)
71
+
72
+ assert_equal expected, actual
73
+ end
74
+
75
+
76
+
77
+ #---------------------------------------------------------
78
+ # Public methods
79
+ #---------------------------------------------------------
80
+
81
+ def test_bubble_javascript_option_keys
82
+ expected = [:class, :style, :position, :event_names, :before_show, :after_show, :before_hide, :after_hide]
83
+ actual = @view.send(:bubble_javascript_option_keys)
84
+
85
+ assert_equal expected, actual
86
+ end
87
+
88
+
89
+ def test_bubble_options_to_js
90
+ options = {
91
+ :class => "error_container",
92
+ :position => "top",
93
+ :event_names => ["mouseover","resize","scroll"],
94
+ :before_show => "function{ alert('hello, world!'); }",
95
+ :after_show => "function{ alert('goodbye, world!'); }"
96
+ }
97
+
98
+ expected = "{" +
99
+ "afterShow:function{ alert('goodbye, world!'); }" + "," +
100
+ "beforeShow:function{ alert('hello, world!'); }" + "," +
101
+ "class:'error_container'" + "," +
102
+ "eventNames:['mouseover','resize','scroll']" + "," +
103
+ "position:'top'" +
104
+ "}"
105
+ actual = @view.send(:bubble_options_to_js, options)
106
+
107
+ assert_equal expected, actual
108
+ end
109
+
110
+
111
+ def test_extract_bubble_javascript_options
112
+ options = { :class => "my_class", :event_names => ["focus", "resize", "scroll"], :position => "right", :text => "Text" }
113
+ js_options = @view.send(:extract_bubble_javascript_options, options)
114
+
115
+ assert_equal true, js_options.has_key?(:class)
116
+ assert_equal true, js_options.has_key?(:event_names)
117
+ assert_equal true, js_options.has_key?(:position)
118
+ assert_equal false, js_options.has_key?(:text)
119
+
120
+ assert_equal "my_class", js_options[:class]
121
+ assert_equal ["focus", "resize", "scroll"], js_options[:event_names]
122
+ assert_equal "right", js_options[:position]
123
+ end
124
+ def test_extract_bubble_javascript_options_for_default_class
125
+ options = { :event_names => ["focus", "resize", "scroll"], :position => "top right", :text => "Text" }
126
+ js_options = @view.send(:extract_bubble_javascript_options, options)
127
+
128
+ assert_equal "michael_hintbuble_bubble", js_options[:class]
129
+ end
130
+ def test_extract_bubble_javascript_options_for_default_event_names
131
+ options = { :class => "my_class", :position => "top right", :text => "Text" }
132
+ js_options = @view.send(:extract_bubble_javascript_options, options)
133
+
134
+ assert_equal ["mouseover", "resize", "scroll"], js_options[:event_names]
135
+ end
136
+ def test_extract_bubble_javascript_options_for_default_position
137
+ options = { :class => "my_class", :event_names => ["focus", "resize", "scroll"], :text => "Text" }
138
+ js_options = @view.send(:extract_bubble_javascript_options, options)
139
+
140
+ assert_equal "right", js_options[:position]
141
+ end
142
+
143
+
144
+ def test_extract_bubble_render_options
145
+ options = { :class => :my_class, :event_names => [:focus, :resize, :scroll], :position => "top right", :text => "Text" }
146
+ render_options = @view.send(:extract_bubble_render_options, options)
147
+
148
+ assert_equal false, render_options.has_key?(:class)
149
+ assert_equal false, render_options.has_key?(:event_names)
150
+ assert_equal false, render_options.has_key?(:position)
151
+ assert_equal true, render_options.has_key?(:text)
152
+
153
+ assert_equal "Text", render_options[:text]
154
+ end
155
+
156
+ end
@@ -0,0 +1,16 @@
1
+ #----------------------------------------------------------
2
+ # Requirements
3
+ #----------------------------------------------------------
4
+
5
+ # rails stuff
6
+ require "rubygems"
7
+ require "active_support"
8
+ require "active_support/test_case"
9
+ require "action_controller"
10
+ require "action_controller/test_case"
11
+ require "action_view"
12
+ require "action_view/test_case"
13
+ require "test/unit"
14
+
15
+ # the plugin itself
16
+ require "#{File.dirname(__FILE__)}/../init"
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: michael_hintbuble
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Coroutine
14
+ - Tim Lowrimore
15
+ - John Dugan
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2010-10-10 00:00:00 -05:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: actionpack
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 11
32
+ segments:
33
+ - 2
34
+ - 3
35
+ - 4
36
+ version: 2.3.4
37
+ type: :runtime
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: activesupport
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 11
48
+ segments:
49
+ - 2
50
+ - 3
51
+ - 4
52
+ version: 2.3.4
53
+ type: :development
54
+ version_requirements: *id002
55
+ description: Michael HintBuble allows you to generate hint bubbles and tooltips in Rails applications using the same syntax used for rendering templates.
56
+ email: gems@coroutine.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - README.rdoc
63
+ files:
64
+ - .gitignore
65
+ - .specification
66
+ - MIT-LICENSE
67
+ - README.rdoc
68
+ - Rakefile
69
+ - VERSION
70
+ - generators/michael_hintbuble/michael_hintbuble_generator.rb
71
+ - generators/michael_hintbuble/templates/michael_hintbuble.css
72
+ - generators/michael_hintbuble/templates/michael_hintbuble.js
73
+ - generators/michael_hintbuble/templates/michael_hintbuble_pointer.png
74
+ - init.rb
75
+ - lib/generators/michael_hintbuble/michael_hintbuble_generator.rb
76
+ - lib/generators/michael_hintbuble/templates/michael_hintbuble.css
77
+ - lib/generators/michael_hintbuble/templates/michael_hintbuble.js
78
+ - lib/generators/michael_hintbuble/templates/michael_hintbuble_pointer.png
79
+ - lib/michael_hintbuble.rb
80
+ - lib/michael_hintbuble/helpers.rb
81
+ - michael_hintbuble.gemspec
82
+ - rails/init.rb
83
+ - test/michael_hintbuble/helpers_test.rb
84
+ - test/test_helper.rb
85
+ has_rdoc: true
86
+ homepage: http://github.com/coroutine/michael_hintbuble
87
+ licenses: []
88
+
89
+ post_install_message:
90
+ rdoc_options:
91
+ - --charset=UTF-8
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ requirements: []
113
+
114
+ rubyforge_project:
115
+ rubygems_version: 1.3.7
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Dead simple, beautiful hint bubbles for Rails.
119
+ test_files:
120
+ - test/michael_hintbuble/helpers_test.rb
121
+ - test/test_helper.rb