├── .gitignore ├── CHANGELOG ├── Documentation.txt ├── LICENSE ├── README ├── Rakefile ├── generators ├── navigation │ ├── USAGE │ ├── navigation_generator.rb │ └── templates │ │ └── navigation.html.erb └── tabnav │ ├── USAGE │ ├── tabnav_generator.rb │ └── templates │ └── tabnav.html.erb ├── images ├── tooltip_arrow.gif └── tooltip_image.gif ├── init.rb ├── install.rb ├── javascripts └── tooltip.js ├── lib ├── widgets.rb └── widgets │ ├── code.css.erb │ ├── code_helper.rb │ ├── core.rb │ ├── css_template.rb │ ├── disableable.rb │ ├── highlightable.rb │ ├── navigation.css.erb │ ├── navigation.rb │ ├── navigation_helper.rb │ ├── navigation_item.rb │ ├── progressbar.css.erb │ ├── progressbar_helper.rb │ ├── showhide.css.erb │ ├── showhide_helper.rb │ ├── spiffy_corners │ ├── spiffy5.html.erb │ ├── spiffy_corners.css.erb │ └── spiffy_corners_helper.rb │ ├── tab.rb │ ├── table.css.erb │ ├── table_helper.rb │ ├── tabnav.css.erb │ ├── tabnav.rb │ ├── tabnav_helper.rb │ ├── tooltip.css.erb │ ├── tooltip_helper.rb │ └── utils_helper.rb ├── tasks └── widgets_tasks.rake ├── test ├── disableable_test.rb ├── highlightable_test.rb ├── navigation_helper_test.rb ├── showhide_helper_test.rb ├── spiffy_corners │ ├── simple.html │ └── spiffy_corners_test.rb ├── tab_test.rb ├── table_helper_test.rb ├── tabnav_helper_test.rb ├── tabnav_test.rb ├── test_helper.rb └── tooltip_helper_test.rb └── uninstall.rb /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject/ 2 | 3 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | nov 01, 2007 2 | ADD: Added disableable support to Tabnav, thanks to Nick Plante 3 | ADD: Added partial rendering for Tooltips 4 | ADD: started tracking changes in this CHANGELOG -------------------------------------------------------------------------------- /Documentation.txt: -------------------------------------------------------------------------------- 1 | - - Tableizer - - 2 | <% tableize :customers, @customers, 3 | :header => 'Listing Customers', 4 | :generate_css => 'true' do |customer| %> 5 | 6 |

<%= customer.name %>

7 |

8 | Code: <%= customer.code %> 9 | Place order: <%= customer.order %> 10 | <%= link_to 'show', .... %> 11 | <%= link_to 'Edit', .... %> 12 | <%= link_to 'Destroy', .... %> 13 |

14 | <% end %> 15 | 16 | - - ShowHide - - 17 | 18 | usage in view, array usage 19 | 20 | <% for user in @users %> 21 | <%=h user.login %> 22 | <%= show_detail_for user %> 23 | 24 | <% detail_for user do %> 25 | details .... 26 | <%=h user.email %> 27 | more details.... 28 | <%= hide_detail_for user %> 29 | <% end %> 30 | <% end %> 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2009 Paolo Dona and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Rails Widgets 2 | ======= 3 | 4 | Rails Widgets is a collection of UI Widgets for RubyOnRails (in form of ActionView helpers). 5 | You can add tabbed navigations, progressbars, rounded boxes etc in a snap. 6 | All the widgets generate and inline their own CSS. Once your page is up and running you can extract and customize them as you wish. 7 | 8 | Source code: 9 | git://github.com/paolodona/rails-widgets.git 10 | 11 | Documentation: 12 | http://github.com/paolodona/rails-widgets/wikis 13 | 14 | Discussion Groups: 15 | http://groups.google.com/group/railswidgets 16 | http://groups.google.com/group/rails-widgets-dev 17 | 18 | Issue Tracking: 19 | http://rails-widgets.lighthouseapp.com 20 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | require 'rake/rdoctask' 4 | 5 | desc 'Default: run unit tests.' 6 | task :default => :test 7 | 8 | desc 'Test the widgets plugin.' 9 | Rake::TestTask.new(:test) do |t| 10 | t.libs << 'lib' 11 | t.pattern = 'test/**/*_test.rb' 12 | t.verbose = true 13 | end 14 | 15 | desc 'Generate documentation for the widgets plugin.' 16 | Rake::RDocTask.new(:rdoc) do |rdoc| 17 | rdoc.rdoc_dir = 'rdoc' 18 | rdoc.title = 'Widgets' 19 | rdoc.options << '--line-numbers' << '--inline-source' 20 | rdoc.rdoc_files.include('README') 21 | rdoc.rdoc_files.include('lib/**/*.rb') 22 | end 23 | -------------------------------------------------------------------------------- /generators/navigation/USAGE: -------------------------------------------------------------------------------- 1 | The navigation generator creates a sample navigation partial. 2 | 3 | invoke with: ./script/generate navigation 4 | es: ./script/generate navigation main 5 | 6 | Usage: 7 | Customize your generated partial (es: views/widgets/_main_navigation.html.erb) 8 | then insert in your .html.erb pages one of this snippet: 9 | 10 | <%= navigation :main %> 11 | -------------------------------------------------------------------------------- /generators/navigation/navigation_generator.rb: -------------------------------------------------------------------------------- 1 | class NavigationGenerator < Rails::Generator::Base 2 | attr_accessor :name 3 | 4 | def initialize(*runtime_args) 5 | super(*runtime_args) 6 | if args[0].nil? 7 | puts banner 8 | else 9 | @name = args[0].underscore 10 | end 11 | end 12 | 13 | def manifest 14 | record do |m| 15 | if @name 16 | m.directory File.join('app/views/widgets') 17 | m.template 'navigation.html.erb', File.join('app/views/widgets', "_#{@name}_navigation.html.erb") 18 | end 19 | end 20 | end 21 | 22 | protected 23 | 24 | def banner 25 | IO.read File.expand_path(File.join(File.dirname(__FILE__), 'USAGE')) 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /generators/navigation/templates/navigation.html.erb: -------------------------------------------------------------------------------- 1 | <%% 2 | # this partial renders a navigation bar, you can call it in your views with: 3 | # <%% navigation :<%=name%> % > 4 | # 5 | # you can pass render_navigation a few options: 6 | # :generate_css => true|false #=> generates a default inline css for the tabnav, defaults to false 7 | # :html => aHash #=> sets html options for the tabnav's div (es :html => {:class=> 'myCssClass', :id=>'myCssId'}) 8 | # 9 | render_navigation :<%=name%>, :generate_css => true do 10 | add_item do |i| 11 | i.named 'welcome to the rails-widgets' 12 | i.disable! 13 | end 14 | 15 | add_item do |i| 16 | # i.html = {:id => 'logout_link'} 17 | i.named 'github' 18 | i.links_to "http://github.com/paolodona/rails-widgets" 19 | end 20 | 21 | add_item do |i| 22 | i.named 'wiki' 23 | i.titled 'contribute to the wiki!' 24 | i.links_to "http://github.com/paolodona/rails-widgets/wiki" 25 | end 26 | 27 | # you can pass add_item a block to just like the tabnav! 28 | # 29 | # add_item do |i| 30 | # i.html = {:id => 'logout_link'} 31 | # i.named 'logout', 32 | # i.links_to :action => 'logout' 33 | # end 34 | # 35 | end 36 | %> 37 | -------------------------------------------------------------------------------- /generators/tabnav/USAGE: -------------------------------------------------------------------------------- 1 | The tabnav generator creates a sample Tabnav partial. 2 | 3 | invoke with: ./script/generate tabnav 4 | es: ./script/generate tabnav main 5 | 6 | Usage: 7 | Customize your generated partial (es: views/widgets/_main_tabnav.html.erb) 8 | then insert in your .html.erb pages one of these snippets: 9 | 10 | <% tabnav :main do %> 11 | your html here 12 | <% end %> 13 | 14 | <%= tabnav :main %> 15 | -------------------------------------------------------------------------------- /generators/tabnav/tabnav_generator.rb: -------------------------------------------------------------------------------- 1 | class TabnavGenerator < Rails::Generator::Base 2 | attr_accessor :name 3 | 4 | def initialize(*runtime_args) 5 | super(*runtime_args) 6 | if args[0].nil? 7 | puts banner 8 | else 9 | @name = args[0].underscore 10 | end 11 | end 12 | 13 | def manifest 14 | record do |m| 15 | if @name 16 | m.directory File.join('app/views/widgets') 17 | m.template 'tabnav.html.erb', File.join('app/views/widgets', "_#{@name}_tabnav.html.erb") 18 | end 19 | end 20 | end 21 | 22 | protected 23 | 24 | def banner 25 | IO.read File.expand_path(File.join(File.dirname(__FILE__), 'USAGE')) 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /generators/tabnav/templates/tabnav.html.erb: -------------------------------------------------------------------------------- 1 | <%='<'+'%'%> 2 | # this partial renders a tabnav, you can call it in your views with: 3 | # <%='<'+'%='%> tabnav :<%=name%> % > (just the tabnav) 4 | # or, if you want a boxed tabnav: 5 | # <%% tabnav :<%=name%> do % > 6 | # your html here 7 | # <%% end % > 8 | # (remove the space between % and >, we don't want to mess up your brand new tabnav :-)) 9 | # 10 | # you can pass render_tabnav a few options: 11 | # :generate_css => true|false #=> generates a default inline css for the tabnav, defaults to false 12 | # :html => aHash #=> sets html options for the tabnav's div (es :html => {:class=> 'myCssClass', :id=>'myCssId'}) 13 | # 14 | render_tabnav :<%=name%>, 15 | :generate_css => true do 16 | 17 | # this generates a tab for every controller in your app 18 | # you'll probably want to delete this and 19 | # add tabs one by one as shown below 20 | controller_names.each do |name| 21 | add_tab do |t| 22 | t.named name.camelize 23 | t.titled "Go to #{name.camelize}" 24 | t.links_to :controller => name 25 | end 26 | end 27 | 28 | #add_tab do |t| 29 | # t.named 'Home' 30 | # t.titled 'Home Page' 31 | # t.links_to :controller => 'welcome' 32 | #end 33 | # 34 | # you can use restful routes with: 35 | # 36 | #add_tab do |t| 37 | # t.named 'Users' 38 | # t.links_to hash_for_users_path 39 | #end 40 | # 41 | #add_tab do |t| 42 | # t.named 'Customers' 43 | # t.links_to :controller => 'customers' 44 | #end 45 | # 46 | # # A tab can be initialized with a Hash like this: 47 | # 48 | # add_tab :name => 'welcome', :link => {:controller=>'welcome'} 49 | # 50 | # # You can have a dynamic name or link 51 | # # (this partial is evaluated in the page context, so it sees every helper or instance variable) 52 | # 53 | # add_tab do |t| 54 | # t.named "#{current_user} details" 55 | # t.links_to :controller => 'users', :action => 'show', :id => current_user.id 56 | # end 57 | # 58 | # # You can have an image inside 59 | # 60 | # add_tab do |t| 61 | # t.named image_tag('test') 62 | # t.links_to :controller => 'users', :action => 'show', :id => current_user.id 63 | # end 64 | end 65 | <%='%'+'>'%> -------------------------------------------------------------------------------- /images/tooltip_arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolodona/rails-widgets/710a2eff9c57d7c80743663d7b7981c063bf608a/images/tooltip_arrow.gif -------------------------------------------------------------------------------- /images/tooltip_image.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolodona/rails-widgets/710a2eff9c57d7c80743663d7b7981c063bf608a/images/tooltip_image.gif -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | # Include hook code here 2 | require 'widgets' -------------------------------------------------------------------------------- /install.rb: -------------------------------------------------------------------------------- 1 | def copy(file_name, from_dir, to_dir) 2 | FileUtils.mkdir to_dir unless File.exist?(File.expand_path(to_dir)) 3 | from = File.expand_path(File.join(from_dir,file_name)) 4 | to = File.expand_path(File.join(to_dir, file_name)) 5 | FileUtils.cp from, to, :verbose => true unless File.exist?(to) 6 | end 7 | 8 | def copy_image(file_name) 9 | plugin_images = File.join(File.dirname(__FILE__), 'images') 10 | app_images = File.join(RAILS_ROOT, 'public/images/widgets') 11 | copy file_name, plugin_images, app_images 12 | end 13 | 14 | def copy_javascript(file_name) 15 | plugin_javascripts = File.join(File.dirname(__FILE__), 'javascripts') 16 | app_javascripts = File.join(RAILS_ROOT, 'public/javascripts/widgets') 17 | copy file_name, plugin_javascripts, app_javascripts 18 | end 19 | 20 | # copy static assets 21 | begin 22 | copy_image 'tooltip_arrow.gif' 23 | copy_image 'tooltip_image.gif' 24 | copy_javascript 'tooltip.js' 25 | rescue Exception => e 26 | puts "There are problems copying widgets assets to you app: #{e.message}" 27 | end -------------------------------------------------------------------------------- /javascripts/tooltip.js: -------------------------------------------------------------------------------- 1 | // tooltip widget 2 | function toggleTooltip(event, element) { 3 | var __x = Event.pointerX(event); 4 | var __y = Event.pointerY(event); 5 | //alert(__x+","+__y); 6 | element.style.top = __y + 5; 7 | element.style.left = __x - 40; 8 | element.toggle(); 9 | } -------------------------------------------------------------------------------- /lib/widgets.rb: -------------------------------------------------------------------------------- 1 | # Widgets 2 | require 'widgets/core' 3 | require 'widgets/css_template' 4 | require 'widgets/highlightable' 5 | require 'widgets/disableable' 6 | 7 | ##### Navigation ##### 8 | require 'widgets/navigation_item' 9 | require 'widgets/navigation' 10 | require 'widgets/navigation_helper' 11 | ActionController::Base.helper Widgets::NavigationHelper 12 | 13 | ##### Tabnav ##### 14 | require 'widgets/tab' 15 | require 'widgets/tabnav' 16 | require 'widgets/tabnav_helper' 17 | ActionController::Base.helper Widgets::TabnavHelper 18 | 19 | ##### Table ##### 20 | require 'widgets/table_helper' 21 | ActionController::Base.helper Widgets::TableHelper 22 | 23 | ##### Code ##### 24 | # not enabled by default because it depends on the Syntax gem 25 | # require 'widgets/code_helper' 26 | # ActionController::Base.helper Widgets::CodeHelper 27 | 28 | ##### ShowHide ##### 29 | require 'widgets/showhide_helper' 30 | ActionController::Base.helper Widgets::ShowhideHelper 31 | 32 | ##### Tooltip ##### 33 | require 'widgets/tooltip_helper' 34 | ActionController::Base.helper Widgets::TooltipHelper 35 | 36 | ##### Progressbar ##### 37 | require 'widgets/progressbar_helper' 38 | ActionController::Base.helper Widgets::ProgressbarHelper 39 | 40 | ##### Spiffy Corners ##### 41 | require 'widgets/spiffy_corners/spiffy_corners_helper' 42 | ActionController::Base.helper Widgets::SpiffyCorners::SpiffyCornersHelper 43 | 44 | ##### UtilsHelper ##### 45 | require 'widgets/utils_helper' 46 | ActionController::Base.helper Widgets::UtilsHelper 47 | 48 | -------------------------------------------------------------------------------- /lib/widgets/code.css.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/widgets/code_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module CodeHelper 3 | # es: <%= code 'models/post.rb' %> 4 | def code file_path, opts = {} 5 | html = '' 6 | if (opts.has_key?[:generate_css] && opts[:generate_css] != false) || opts[:generate_css] == true 7 | css_template = ERB.new IO.read(File.expand_path(File.dirname(__FILE__) + '/code.css.erb')) 8 | html << css_template.result(binding) 9 | end 10 | 11 | code = File.read(File.expand_path(File.join(RAILS_ROOT, "app/#{file_path}"))) 12 | convertor = ::Syntax::Convertors::HTML.for_syntax "ruby" 13 | html << convertor.convert(code) 14 | html 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/widgets/core.rb: -------------------------------------------------------------------------------- 1 | module ActionView 2 | module Helpers 3 | module AssetTagHelper 4 | 5 | # We redefine javascript_include_tag in order to auto-magically include 6 | # the widgets javascripts. If you hame more than one javascript_include_tag 7 | # call, the widgets javascripts gets included only once. 8 | def javascript_include_tag_with_widgets(*sources) 9 | unless @__widgets_has_already_included_its_js 10 | options = sources.last.is_a?(Hash) ? sources.pop : {} # remove options 11 | sources << 'widgets/tooltip' 12 | sources << options # add previously removed option 13 | @__widgets_has_already_included_its_js = true 14 | end 15 | javascript_include_tag_without_widgets(*sources) 16 | end 17 | alias_method_chain :javascript_include_tag, :widgets 18 | end 19 | end 20 | end -------------------------------------------------------------------------------- /lib/widgets/css_template.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | # Utility module for widgets that need to create a default CSS 3 | # you have to include it inside a Widget to add css_generation capability 4 | module CssTemplate 5 | 6 | def render_css(name) 7 | @_widgets_css_templates ||= {} 8 | return @_widgets_css_templates[name] if @_widgets_css_templates[name] # return the cached copy if possible 9 | # if not cached read and evaluate the template 10 | css_template_filename = "#{name}.css.erb" 11 | css_template = ERB.new IO.read(File.join(File.dirname(__FILE__), css_template_filename)) 12 | @_widgets_css_templates[name] = css_template.result(binding) 13 | end 14 | 15 | # WD-rpw 02-22-2009 changed name to not conflict with ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/base.rb's render_template method 16 | def rw_render_template(name, _binding = nil) 17 | _template_filename = "#{name}.html.erb" 18 | _template = ERB.new IO.read(File.join(File.dirname(__FILE__), _template_filename)) 19 | _template.result(binding) 20 | end 21 | 22 | # should the helper generate a css for this widget? 23 | def generate_css? 24 | @generate_css ? true : false 25 | end 26 | 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/widgets/disableable.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module Disableable 3 | def self.included(base) 4 | # base.extend(ClassMethods) 5 | base.class_eval do 6 | include InstanceMethods 7 | attr_writer :disabled_condition 8 | end 9 | end 10 | 11 | module InstanceMethods 12 | def disabled_condition 13 | @disabled_condition ||= proc { false } 14 | @disabled_condition 15 | end 16 | 17 | # a disable rule should always be a Proc object 18 | def disabled_if rule 19 | raise "you must pass a proc to disabled_if" unless rule.kind_of?(Proc) 20 | self.disabled_condition = rule if rule.kind_of?(Proc) 21 | end 22 | 23 | # force the tab as disabled 24 | def disable! 25 | self.disabled_condition = proc {true} 26 | end 27 | 28 | # Proc evaluates to true/false 29 | def disabled? 30 | self.disabled_condition.call 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/widgets/highlightable.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module Highlightable 3 | def self.included(base) 4 | # base.extend(ClassMethods) 5 | base.class_eval do 6 | include InstanceMethods 7 | attr_writer :highlights 8 | end 9 | end 10 | 11 | module InstanceMethods 12 | def highlights 13 | @highlights ||= [] 14 | @highlights 15 | end 16 | 17 | # a rule can be: 18 | # * a parameter hash eg: {:controller => 'main', :action => 'welcome'} 19 | # * a string containing an URL eg: 'http://blog.seesaw.it' 20 | def highlights_on rule 21 | highlights << rule 22 | end 23 | 24 | # force the tab as highlighted 25 | def highlight! 26 | highlights_on proc { true } 27 | end 28 | 29 | # takes in input a Hash (usually params) 30 | # or a string/Proc that evaluates to true/false 31 | # it does ignore some params like 'only_path' etc.. 32 | # we have to do this in orderr to support restful routes 33 | def highlighted? options={} 34 | option = clean_unwanted_keys(options) 35 | #puts "### '#{name}'.highlighted? #{options.inspect}" 36 | result = false 37 | 38 | highlights.each do |highlight| # for every highlight(proc or hash) 39 | highlighted = true 40 | if highlight.kind_of? String # do not highlight @TODO: should we evaluate the request URI for this? 41 | highlighted &= false 42 | elsif highlight.kind_of? Proc # evaluate the proc 43 | h = highlight.call 44 | if (h.is_a?(TrueClass) || h.is_a?(FalseClass)) 45 | highlighted &= h 46 | else 47 | raise 'proc highlighting rules must evaluate to TrueClass or FalseClass' 48 | end 49 | elsif highlight.kind_of? Hash # evaluate the hash 50 | h = clean_unwanted_keys(highlight) 51 | h.each_key do |key| # for each key 52 | # remove first slash from :controller key otherwise highlighted? could fail with urls such as {:controller => "/base" 53 | h_key = h[key].to_param.dup 54 | h_key.gsub!(/^\//,"") if key == :controller 55 | highlighted &= h_key==options[key].to_s 56 | end 57 | else # highlighting rule not supported 58 | raise 'highlighting rules should be String, Proc or Hash' 59 | end 60 | result |= highlighted 61 | end 62 | return result 63 | end 64 | 65 | private 66 | 67 | # removes unwanted keys from a Hash 68 | # and returns a new hash 69 | def clean_unwanted_keys(hash) 70 | ignored_keys = [:only_path, :use_route] 71 | hash.dup.delete_if{|key,value| ignored_keys.include?(key)} 72 | end 73 | 74 | def check_hash(param, param_name) 75 | raise "param '#{param_name}' should be a Hash but is #{param.inspect}" unless param.kind_of?(Hash) 76 | param 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/widgets/navigation.css.erb: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /lib/widgets/navigation.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | class Navigation 3 | attr_accessor :name, :items, :html, :separator 4 | include CssTemplate 5 | 6 | def initialize(name, opts={}) 7 | @name = name 8 | @items = [] 9 | @generate_css = opts[:generate_css] || false 10 | @html = opts[:html] || {} # setup default html options 11 | @html[:id] ||= "#{@name}_navigation" 12 | @html[:class] ||= @html[:id] 13 | @separator = opts[:separator] ||= ' |' 14 | end 15 | 16 | def add_item opts={} 17 | @items ||= [] 18 | @items << NavigationItem.new(opts) 19 | end 20 | 21 | end 22 | end -------------------------------------------------------------------------------- /lib/widgets/navigation_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module NavigationHelper 3 | 4 | def navigation name, opts={} 5 | partial_template = opts[:partial] || "widgets/#{name}_navigation" 6 | html = capture { render :partial => partial_template } 7 | return html 8 | end 9 | 10 | def render_navigation(name=:main, opts={}, &proc) 11 | raise ArgumentError, "Missing name parameter in render_navigation call" unless name 12 | raise ArgumentError, "Missing block in render_navigation call" unless block_given? 13 | @_navigation = Navigation.new(name, opts) 14 | instance_eval(&proc) 15 | concat @_navigation.render_css('navigation') if @_navigation.generate_css? 16 | concat tag('div',@_navigation.html ,true) 17 | render_navigation_items 18 | concat '' 19 | nil 20 | end 21 | 22 | def add_item opts = {}, &block 23 | raise 'Cannot call add_item outside of a render_navigation block' unless @_navigation 24 | @_navigation.items << NavigationItem.new(opts,&block) 25 | nil 26 | end 27 | 28 | private 29 | 30 | def render_navigation_items 31 | return if @_navigation.items.empty? 32 | 33 | concat "
    \n" 34 | @_navigation.items.each_with_index do |item,index| 35 | if item.disabled? 36 | item.html[:class] = 'disabled' 37 | elsif item.highlighted?(params) 38 | item.html[:class] = 'active' 39 | end 40 | 41 | concat '
  • ' 42 | if item.disabled? 43 | concat content_tag('span', item.name, item.html) 44 | else 45 | if !item.function.blank? 46 | concat link_to_function(item.name, item.function, item.html) 47 | else 48 | concat link_to(item.name, item.link, item.html) 49 | end 50 | end 51 | concat @_navigation.separator unless index == @_navigation.items.size - 1 52 | concat "
  • \n" 53 | end 54 | concat '
' 55 | end 56 | end 57 | end 58 | 59 | -------------------------------------------------------------------------------- /lib/widgets/navigation_item.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | class NavigationItem 3 | include Highlightable 4 | include Disableable 5 | 6 | attr_accessor :name, :link, :html, :function 7 | 8 | def initialize(opts={}) 9 | @name = opts[:name] 10 | @link = opts[:link] || {} 11 | @html = opts[:html] || {} 12 | @function = opts[:function] || {} 13 | @html[:title] = opts[:title] 14 | @html[:target] = opts[:target] 15 | 16 | yield(self) if block_given? 17 | 18 | self.highlights << @link if link? # it does highlight on itself 19 | raise ArgumentError, 'you must provide a name' unless @name 20 | end 21 | 22 | # more idiomatic ways to set tab properties 23 | def links_to(l); @link = l; end 24 | def function_to(f); @function = f; end 25 | def named(n); @name = n; end 26 | def titled(t); @html[:title] = t; end 27 | def new_window(n); html[:target] = n ? '_blank' : nil; end 28 | 29 | def link? 30 | @link && !@link.empty? 31 | end 32 | 33 | end 34 | end -------------------------------------------------------------------------------- /lib/widgets/progressbar.css.erb: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /lib/widgets/progressbar_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module ProgressbarHelper 3 | include CssTemplate 4 | 5 | # show a progressbar 6 | # 7 | # eg: <%= progressbar 35, :generate_css => true %> 8 | # or <%= progressbar [35,78,15] %> 9 | # 10 | # options 11 | # === 12 | # :generate_css defaults to false 13 | # :adjust defaults to false 14 | def progressbar values, options={} 15 | raise ArgumentError, "Missing value(s) parameter in progressbar call" unless values 16 | raise ArgumentError, "The value parameter has to be a Numeric o Array" unless values.kind_of?(Array) or values.kind_of?(Numeric) 17 | if values.kind_of? Numeric # single value 18 | total = 100 19 | values = [values] 20 | else # Array of values 21 | total = values.sum 22 | end 23 | 24 | html = "" 25 | html << render_css('progressbar') if options[:generate_css] == true 26 | html << '
' 27 | values.dup.each_with_index do |value, index| 28 | if total == 0 29 | percentage = 0 30 | else 31 | percentage = options[:adjust] ? (value * 100 / total) : value 32 | end 33 | css_class = "progressbar_color_#{index.modulo(10)}" 34 | html << "
" 35 | end 36 | html << "
" 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/widgets/showhide.css.erb: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /lib/widgets/showhide_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module ShowhideHelper 3 | include CssTemplate 4 | 5 | def show_box_for record, opts={} 6 | name = opts[:name] || 'details' 7 | link_name = opts[:link_name] || 'show details' 8 | detail_box_id = opts[:detail_box_id] || dom_detail_id(record,name) 9 | hide_link_id = opts[:hide_link_id] || dom_hide_id(record,name) 10 | 11 | html = opts[:html] || {} # setup default html options 12 | html[:id] ||= dom_show_id(record,name) 13 | html[:class] ||= "#{name}_show_link" 14 | 15 | link_to_function link_name, nil, html do |page| 16 | page[detail_box_id].show 17 | page[html[:id]].hide 18 | page[hide_link_id].show 19 | end 20 | end 21 | 22 | def hide_box_for record, opts={} 23 | name = opts[:name] || 'details' 24 | link_name = opts[:link_name] || 'hide details' 25 | detail_box_id = opts[:detail_box_id] || dom_detail_id(record,name) 26 | show_link_id = opts[:show_link_id] || dom_show_id(record,name) 27 | 28 | html = opts[:html] || {} # setup default html options 29 | html[:id] ||= dom_hide_id(record,name) 30 | html[:class] ||= "#{name}_hide_link" 31 | html[:style] ||= "" 32 | html[:style] += "display:none;" 33 | 34 | link_to_function link_name, nil, html do |page| 35 | page[detail_box_id].hide 36 | page[show_link_id].show 37 | page[html[:id]].hide 38 | end 39 | end 40 | 41 | def detail_box_for record, opts={}, &block 42 | raise ArgumentError, 'Missing block in showhide.detail_box_for call' unless block_given? 43 | name = opts[:name] || 'details' 44 | @generate_css = opts[:generate_css] || false 45 | 46 | html = opts[:html] || {} # setup default html options 47 | html[:id] ||= dom_detail_id(record,name) 48 | html[:class] ||= "#{name}_for_#{normalize_class_name(record)}" 49 | html[:style] = 'display:none;' 50 | @css_class = html[:class] 51 | concat(render_css('showhide')) if generate_css? 52 | # Taken from ActionView::Helpers::RecordTagHelper 53 | concat content_tag(:div, capture(&block), html) 54 | nil 55 | end 56 | 57 | private 58 | 59 | def dom_detail_id record, name 60 | normalize_dom_id(record, name.to_s) 61 | end 62 | 63 | def dom_show_id record, name 64 | normalize_dom_id(record, "show_#{name}") 65 | end 66 | 67 | def dom_hide_id record, name 68 | normalize_dom_id(record, "hide_#{name}") 69 | end 70 | 71 | def normalize_dom_id object, prefix 72 | if object.kind_of?(ActiveRecord::Base) 73 | dom_id(object, "#{prefix}_for#{object.id ? '' : '_new'}") 74 | else 75 | [ prefix, 'for', normalize_class_name(object) ].compact * '_' 76 | end 77 | end 78 | 79 | def normalize_class_name object 80 | if object.kind_of?(ActiveRecord::Base) 81 | ActionController::RecordIdentifier.singular_class_name(object) 82 | else 83 | object.to_s 84 | end 85 | end 86 | 87 | # content_tag_for creates an HTML element with id and class parameters 88 | # that relate to the specified Active Record object. 89 | # 90 | # Taken from ActionView::Helpers::RecordTagHelper 91 | def content_box_for(tag_name, *args, &block) 92 | concat content_tag(tag_name, capture(&block), args) 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /lib/widgets/spiffy_corners/spiffy5.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
<%= @_spiffy_corners_content %>
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /lib/widgets/spiffy_corners/spiffy_corners.css.erb: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /lib/widgets/spiffy_corners/spiffy_corners_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module SpiffyCorners 3 | module SpiffyCornersHelper 4 | 5 | protected 6 | 7 | include CssTemplate 8 | def spiffy_corners opts={}, &block 9 | raise "you must pass spiffy_corners a block!" unless block_given? 10 | html = [] 11 | html << render_css('spiffy_corners/spiffy_corners') if opts[:generate_css] == true 12 | @_spiffy_corners_content = capture(&block) 13 | html << rw_render_template('spiffy_corners/spiffy5', binding) 14 | 15 | concat html.join 16 | return nil 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/widgets/tab.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | class Tab 3 | include Highlightable 4 | include Disableable 5 | attr_accessor :link, :remote_link, :name, :html 6 | 7 | def initialize(opts={}) 8 | @name = opts[:name] 9 | @link = opts[:link] || {} 10 | @remote_link = opts[:remote_link] || nil 11 | 12 | # wrap highlights into an array if only one hash has been passed 13 | opts[:highlights] = [opts[:highlights]] if opts[:highlights].kind_of?(Hash) 14 | self.highlights = opts[:highlights] || [] 15 | self.disabled_if opts[:disabled_if] || proc { false } 16 | @html = opts[:html] || {} 17 | @html[:title] = opts[:title] 18 | 19 | yield(self) if block_given? 20 | 21 | self.highlights << @link if link? # it does highlight on itself 22 | raise ArgumentError, 'you must provide a name' unless @name 23 | end 24 | 25 | # title is a shortcut to html[:title] 26 | def title; @html[:title]; end 27 | def title=(new_title); @html[:title]=new_title; end 28 | 29 | # more idiomatic ways to set tab properties 30 | def links_to(l); @link = l; end 31 | def links_to_remote(rl); 32 | @remote_link = rl; 33 | #remote links MUST have a dom_id 34 | #if not given I'll generate a random one 35 | @html[:id] ||= "tab_#{rand(99999)}" 36 | end 37 | def named(n); @name = n; end 38 | def titled(t); @html[:title] = t; end 39 | 40 | def link? 41 | @link && !@link.empty? 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/widgets/table.css.erb: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /lib/widgets/table_helper.rb: -------------------------------------------------------------------------------- 1 | 2 | module Widgets 3 | 4 | module TableHelper 5 | include CssTemplate 6 | 7 | # Returns an HTML table with +:collection+ disposed in rows. Add 8 | # HTML attributes by passing an attributes hash to +html+. 9 | # The content of each item is rendered using the given block. 10 | # 11 | # +:collection+ array of items 12 | # +:cols+ number of columns (default 3) 13 | # +:html+ table html attributes (+:class+, +:id+) 14 | # +:name+ name of table (dafault +:main+) 15 | # 16 | # <% tableize @users, :name => 'credential', :html => {:class => 'people'}, :cols => 2 do |user| -%> 17 | # login: <%= user.name %> 18 | # <% end -%> 19 | # 20 | # # => 21 | # 22 | #
login: scooby 
23 | # 24 | def tableize(collection = nil, opts = {}, &block) 25 | table = Tableizer.new(collection, opts, self, &block) 26 | table.render 27 | end 28 | 29 | class Tableizer 30 | 31 | def initialize(collection, opts, template, &block) 32 | parse_args(collection, opts, template, &block) 33 | 34 | raise ArgumentError, 'Missing collection parameter in tableize call' unless @collection 35 | raise ArgumentError, 'Missing block in tableize call' unless block_given? 36 | raise ArgumentError, 'Tableize columns must be two or more' unless columns >= 2 37 | 38 | @buffer = '' 39 | end 40 | 41 | def render 42 | generate_css 43 | generate_html 44 | flush_to_template 45 | return nil # avoid duplication if called with <%= %> 46 | end 47 | 48 | protected 49 | 50 | def parse_args(collection, opts, template, &block) 51 | @collection = collection 52 | @collection ||= opts[:collection] 53 | 54 | @opts = opts 55 | 56 | name = opts[:name] || :main 57 | @html = opts[:html] || {} 58 | @html[:id] ||= name.to_s.underscore << '_table' 59 | @html[:class] ||= @html[:id] 60 | 61 | @template = template 62 | @block = block 63 | end 64 | 65 | def generate_css 66 | @buffer << render_css('table') if generate_css? 67 | end 68 | 69 | def generate_html 70 | opening_table_tags 71 | table_rows 72 | closing_table_tags 73 | end 74 | 75 | def flush_to_template 76 | concat(@buffer) 77 | end 78 | 79 | def opening_table_tags 80 | @buffer << tag('table', {:id => table_id, :class => table_class}, true) 81 | @buffer << tag('tbody', nil, true) 82 | end 83 | 84 | def closing_table_tags 85 | @buffer << '' << '' 86 | end 87 | 88 | def table_rows 89 | @index = 0 90 | @size = @collection.size 91 | 92 | opening_tr_tag 93 | header_tag 94 | fill_table_cells 95 | closing_tr_tag 96 | end 97 | 98 | def opening_tr_tag 99 | @buffer << tag('tr', nil, true) 100 | end 101 | 102 | def closing_tr_tag 103 | @buffer << '' 104 | end 105 | 106 | def header_tag 107 | if header 108 | @buffer << content_tag('th', header) 109 | allow_for_extra_item 110 | end 111 | end 112 | 113 | def allow_for_extra_item 114 | @index += 1 115 | @size += 1 116 | end 117 | 118 | def fill_table_cells 119 | @collection.each do |item| 120 | @index += 1 121 | generate_cell(item) 122 | wrap_to_new_row_if_required 123 | end 124 | pad_last_row 125 | end 126 | 127 | def empty_cell 128 | content_tag('td', ' ', :class => 'blank') 129 | end 130 | 131 | def generate_cell(item) 132 | @buffer << content_tag('td', capture(item, &@block)) 133 | end 134 | 135 | def wrap_to_new_row_if_required 136 | if wrap_to_new_row? 137 | closing_tr_tag 138 | opening_tr_tag 139 | skip_header_column 140 | end 141 | end 142 | 143 | def wrap_to_new_row? 144 | end_of_current_line? and !final_element? 145 | end 146 | 147 | def end_of_current_line? 148 | @index.remainder(columns) == 0 149 | end 150 | 151 | def final_element? 152 | @index == @size 153 | end 154 | 155 | def skip_header_column 156 | if skip_header_column? 157 | @buffer << empty_cell 158 | allow_for_extra_item 159 | end 160 | end 161 | 162 | def skip_header_column? 163 | @opts[:skip_header_column] == true 164 | end 165 | 166 | def pad_last_row 167 | remainder = @size.remainder(columns) 168 | cells_to_pad = columns - remainder 169 | 170 | unless remainder == 0 171 | cells_to_pad.times do 172 | @buffer << empty_cell 173 | end 174 | end 175 | end 176 | 177 | def generate_css? 178 | @opts[:generate_css] || false 179 | end 180 | 181 | def columns 182 | @opts[:cols] || 3 183 | end 184 | 185 | def header 186 | @opts[:header] 187 | end 188 | 189 | def table_id 190 | @html[:id] 191 | end 192 | 193 | def table_class 194 | @html[:class] 195 | end 196 | 197 | def method_missing(*args, &block) 198 | @template.send(*args, &block) 199 | end 200 | end 201 | 202 | end 203 | 204 | end 205 | -------------------------------------------------------------------------------- /lib/widgets/tabnav.css.erb: -------------------------------------------------------------------------------- 1 | 61 | -------------------------------------------------------------------------------- /lib/widgets/tabnav.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | class Tabnav 3 | include CssTemplate 4 | attr_accessor :tabs, :html, :name 5 | 6 | def initialize(name, opts={}) 7 | @name = name || :main 8 | @tabs = [] 9 | @generate_css = opts[:generate_css] || false 10 | @html = opts[:html] || {} # setup default html options 11 | @html[:id] ||= name.to_s.underscore << '_tabnav' 12 | @html[:class] ||= @html[:id] 13 | end 14 | 15 | # should the helper generate a css for this tabnav? 16 | def generate_css? 17 | @generate_css ? true : false 18 | end 19 | 20 | # sort your tabs alphabetically 21 | def sort! 22 | @tabs.sort! { |x,y| x.name <=> y.name } 23 | end 24 | 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/widgets/tabnav_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module TabnavHelper 3 | protected 4 | 5 | # main method 6 | 7 | # show a tabnav defined by a partial 8 | # 9 | # eg: <% tabnav :main do %> 10 | # ...html... 11 | # <% end %> 12 | # 13 | # or <%= tabnav :main %> 14 | # 15 | # options 16 | # === 17 | # :partial: defaults to widgets/_tabnav 18 | def tabnav name, opts={}, &block 19 | partial_template = opts[:partial] || "widgets/#{name}_tabnav" 20 | html = capture { render :partial => partial_template } 21 | if block_given? 22 | options = {:id => @_tabnav.html[:id] + '_content', :class => @_tabnav.html[:class] + '_content'} 23 | html << tag('div', options, true) 24 | html << capture(&block) 25 | html << '' 26 | concat html 27 | nil # avoid duplication if called with <%= %> 28 | else 29 | return html 30 | end 31 | end 32 | 33 | # tabnav building methods 34 | # they are used inside the widgets/*_tabnav.rhtml partials 35 | # (you can also call them in your views if you want) 36 | 37 | # renders the tabnav 38 | def render_tabnav(name, opts={}, &proc) 39 | raise ArgumentError, "Missing name parameter in tabnav call" unless name 40 | raise ArgumentError, "Missing block in tabnav call" unless block_given? 41 | @_tabnav = Tabnav.new(name, opts) 42 | 43 | instance_eval(&proc) 44 | concat @_tabnav.render_css('tabnav') if @_tabnav.generate_css? 45 | concat tag('div',@_tabnav.html ,true) 46 | @_tabnav.sort! if opts[:sort] == true 47 | render_tabnav_tabs 48 | concat "\n" 49 | nil 50 | end 51 | 52 | def add_tab options = {}, &block 53 | raise 'Cannot call add_tab outside of a render_tabnav block' unless @_tabnav 54 | @_tabnav.tabs << Tab.new(options, &block) 55 | nil 56 | end 57 | 58 | # inspects controller names 59 | def controller_names 60 | files = Dir.entries(File.join(RAILS_ROOT, 'app/controllers')) 61 | controllers = files.select {|x| x.match '_controller.rb'} 62 | return controllers.map {|x| x.sub '_controller.rb', ''}.sort 63 | end 64 | 65 | private 66 | 67 | # renders the tabnav's tabs 68 | def render_tabnav_tabs 69 | return if @_tabnav.tabs.empty? 70 | 71 | concat tag('ul', {} , true) 72 | 73 | @_tabnav.tabs.each do |tab| 74 | li_options = {} 75 | li_options[:id] = "#{tab.html[:id]}_container" if tab.html[:id] 76 | 77 | tab_html = tab.html.dup 78 | tab_html[:class] ||= '' 79 | if tab.disabled? 80 | tab_html[:class] << ' disabled' 81 | elsif tab.highlighted?(params) 82 | tab_html[:class] << ' active' 83 | end 84 | li_options[:class] = tab_html[:class] 85 | 86 | concat tag('li', li_options, true) 87 | if tab.disabled? || (tab.link.empty? && tab.remote_link.nil?) 88 | concat content_tag('span', tab.name, tab_html) 89 | elsif !tab.link.empty? 90 | concat link_to(tab.name, tab.link, tab_html) 91 | elsif tab.remote_link 92 | success = "document.getElementsByClassName('active', $('" + @_tabnav.html[:id]+ "')).each(function(item){item.removeClassName('active');});" 93 | success += "$('#{tab.html[:id]}').addClassName('active');" 94 | # success += "alert(this);" 95 | 96 | remote_opts = {:update => @_tabnav.html[:id] + '_content', 97 | # :success => success, 98 | :method => :get, 99 | :loading => loading_function + success, 100 | :loaded => "$('#{@_tabnav.html[:id]}_content').setStyle({height: 'auto'});" 101 | } 102 | concat link_to_remote(tab.name, remote_opts.merge(tab.remote_link), tab_html) 103 | else 104 | raise "WHAT THE HELL?" 105 | end 106 | concat "\n" 107 | end 108 | concat '' 109 | end 110 | 111 | # generate javascript function to use 112 | # while loading remote tabs 113 | # NB: EXPERIMENTAL 114 | def loading_function 115 | # show customized partial and adjust content height 116 | # todo: find out why I need a 38px offset :-| 117 | begin 118 | inner_html = capture {render :partial => 'shared/tabnav_loading' } 119 | rescue 120 | inner_html = "Loading..." 121 | end 122 | return <<-JAVASCRIPT 123 | var element = $('#{@_tabnav.html[:id]}_content'); 124 | var h = element.getHeight() - 38; 125 | element.innerHTML='#{escape_javascript(inner_html)}'; 126 | element.setStyle({height: ''+h+'px'}); 127 | //element.morph('height:'+h+'px'); 128 | JAVASCRIPT 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/widgets/tooltip.css.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/widgets/tooltip_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module TooltipHelper 3 | include CssTemplate 4 | 5 | def tooltip(name=nil, opts={}, &proc) 6 | if name.kind_of?(Hash) # called like this: <%= tooltip :name => 'aaa', :partial => 'mytooltip' %> 7 | opts = name 8 | name = opts[:name] 9 | end 10 | 11 | opts[:id] ||= rand(1000) 12 | name ||= image_tag('widgets/tooltip_image.gif', :border => 0) 13 | 14 | result = '' 15 | result << tooltip_css 16 | result << tooltip_link(opts[:id],name) 17 | result << javascript_tag(tooltip_link_function(opts[:id])) 18 | result << render_tooltip(name, tooltip_content(opts,&proc), opts) 19 | 20 | if block_given? 21 | concat result 22 | return nil 23 | else 24 | return result 25 | end 26 | end 27 | 28 | def tooltip_css 29 | unless @_tooltip_css_done 30 | @_tooltip_css_done = true 31 | return render_css('tooltip') 32 | else 33 | '' 34 | end 35 | end 36 | 37 | def tooltip_content(opts={}, &proc) 38 | return render(:partial => opts[:partial]) if opts[:partial] 39 | return capture(&proc) 40 | end 41 | 42 | def tooltip_link(id, name) 43 | link_to name, 'javascript:void(0)', :id => "tooltip_link_#{id}" 44 | end 45 | 46 | def tooltip_link_function(id) 47 | "$('tooltip_link_#{id}').observe('click', function(event){toggleTooltip(event, $('tooltip_#{id}'))});" 48 | end 49 | 50 | def close_tooltip_link(id, message = 'close') 51 | message ||= 'close' # if nil is passed I'll force it 52 | link_to_function message, "$('tooltip_#{id}').hide()" 53 | end 54 | 55 | def render_tooltip(name, content, opts) 56 | html = tag('div', {:id => "tooltip_#{opts[:id]}", :class=>'tooltip', :style => 'display:none'}, true) 57 | html << tag('div', {:id => "tooltip_content_#{opts[:id]}", :class=>'tooltip_content'},true) 58 | html << content 59 | html << '' + close_tooltip_link(opts[:id], opts[:close_message]) + '' 60 | html << '' 61 | html 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/widgets/utils_helper.rb: -------------------------------------------------------------------------------- 1 | module Widgets 2 | module UtilsHelper 3 | def nocr(string) 4 | return string.gsub("\n", '') 5 | end 6 | 7 | # converts blank spaces into no breaking spaces 8 | # use it like <%=nbsp ...%> 9 | def nbsp(string) 10 | string.to_s.gsub " ", " " 11 | end 12 | 13 | # generates random text to fill up not-yet-implemented interfaces 14 | def lorem(n=nil) 15 | words = %w{Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.} 16 | if n 17 | while (n > words.size) do words = words + words; end 18 | words = words[0..n] 19 | end 20 | return words.join(' ') 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /tasks/widgets_tasks.rake: -------------------------------------------------------------------------------- 1 | def copy(file_name, from_dir, to_dir) 2 | FileUtils.mkdir to_dir unless File.exist?(File.expand_path(to_dir)) 3 | from = File.expand_path(File.join(from_dir,file_name)) 4 | to = File.expand_path(File.join(to_dir, file_name)) 5 | puts " creating: #{to}" 6 | FileUtils.cp from, to unless File.exist?(to) 7 | end 8 | 9 | def copy_image(file_name) 10 | plugin_images = File.join(File.dirname(__FILE__), '..', 'images') 11 | app_images = File.join(RAILS_ROOT, 'public/images/widgets') 12 | copy file_name, plugin_images, app_images 13 | end 14 | 15 | def copy_javascript(file_name) 16 | plugin_javascripts = File.join(File.dirname(__FILE__), '..', 'javascripts') 17 | app_javascripts = File.join(RAILS_ROOT, 'public/javascripts/widgets') 18 | copy file_name, plugin_javascripts, app_javascripts 19 | end 20 | 21 | desc "Copies the widgets assets (images and javascripts) to the public folder" 22 | namespace :widgets do 23 | task :setup do 24 | copy_image 'tooltip_arrow.gif' 25 | copy_image 'tooltip_image.gif' 26 | copy_javascript 'tooltip.js' 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /test/disableable_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class MyDisablingObject 4 | include Widgets::Disableable 5 | end 6 | 7 | class DisableableTest < Test::Unit::TestCase 8 | 9 | EXPECTED_INSTANCE_METHODS = %w{disabled_condition disabled_condition= disabled? disabled_if} 10 | 11 | def setup 12 | @obj = MyDisablingObject.new 13 | end 14 | 15 | def test_included_methods 16 | EXPECTED_INSTANCE_METHODS.each do |method| 17 | assert @obj.respond_to?(method), "A disableable object should respond to '#{method}'" 18 | end 19 | end 20 | 21 | def test_accessor 22 | assert @obj.disabled_condition.kind_of?(Proc) 23 | end 24 | 25 | def test_disabled_if 26 | disabled_proc = proc { 1 == 1 } 27 | @obj.disabled_condition = disabled_proc 28 | assert @obj.disabled_condition.kind_of?(Proc) 29 | end 30 | 31 | def test_disabled? 32 | @obj.disabled_if proc { 1 == 1 } 33 | assert @obj.disabled?, 'should be disabled' 34 | end 35 | 36 | def test_default_disabled? 37 | assert !@obj.disabled?, 'should not be disabled' 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/highlightable_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class MyHighlightingObject 4 | include Widgets::Highlightable 5 | end 6 | 7 | class HighlightableTest < Test::Unit::TestCase 8 | 9 | EXPECTED_INSTANCE_METHODS = %w{highlights highlights= highlighted? highlights_on} 10 | 11 | def setup 12 | @obj = MyHighlightingObject.new 13 | end 14 | 15 | def test_included_methods 16 | EXPECTED_INSTANCE_METHODS.each do |method| 17 | assert @obj.respond_to?(method), "An Highlightable object should respond to '#{method}'" 18 | end 19 | end 20 | 21 | def test_accessor 22 | assert_equal [], @obj.highlights, 'should return an empty array' 23 | end 24 | 25 | def test_highlights_on 26 | @obj.highlights=[ {:action => 'my_action'}, {:action => 'my_action2', :controller => 'my_controller'}] 27 | assert @obj.highlights.kind_of?(Array) 28 | assert_equal 2, @obj.highlights.size, '2 highlights were added so far' 29 | 30 | @obj.highlights.each {|hl| assert hl.kind_of?(Hash)} 31 | 32 | # sanity check 33 | assert_equal 'my_action',@obj.highlights[0][:action] 34 | end 35 | 36 | def test_highlights_on_proc 37 | @bonus_points = 0 38 | @obj.highlights_on proc {@bonus_points > 5} 39 | assert !@obj.highlighted?, 'should not highlight until @bonus_points is greater than 5' 40 | 41 | @bonus_points = 10 42 | assert @obj.highlighted?, 'should highlight because @bonus_points is greater than 5' 43 | end 44 | 45 | def test_highlight_on_string 46 | @obj.highlights_on "http://www.seesaw.it" 47 | 48 | end 49 | 50 | def test_highlighted? 51 | @obj.highlights_on :controller => 'pippo' 52 | 53 | #check that highlights on its own link 54 | assert @obj.highlighted?(:controller => 'pippo'), 'should highlight' 55 | assert @obj.highlighted?(:controller => 'pippo', :action => 'list'), 'should highlight' 56 | assert !@obj.highlighted?(:controller => 'pluto', :action => 'list'), 'should NOT highlight' 57 | 58 | end 59 | 60 | def test_more_highlighted? 61 | # add some other highlighting rules 62 | # and check again 63 | @obj.highlights=[{:controller => 'pluto'}] 64 | assert @obj.highlighted?(:controller => 'pluto'), 'should highlight' 65 | 66 | @obj.highlights << {:controller => 'granny', :action => 'oyster'} 67 | assert @obj.highlighted?(:controller => 'granny', :action => 'oyster'), 'should highlight' 68 | assert !@obj.highlighted?(:controller => 'granny', :action => 'daddy'), 'should NOT highlight' 69 | end 70 | 71 | def test_highlighted_with_slash 72 | @obj.highlights_on :controller => '/pippo' 73 | assert @obj.highlighted?({:controller => 'pippo'}) 74 | end 75 | 76 | end -------------------------------------------------------------------------------- /test/navigation_helper_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class NavigationHelperTest < ActionView::TestCase 4 | attr_accessor :params 5 | include Widgets::NavigationHelper 6 | 7 | def setup 8 | @params = {} 9 | end 10 | 11 | def test_presence_of_instance_methods 12 | %w{navigation add_item}.each do |instance_method| 13 | assert respond_to?(instance_method), "#{instance_method} is not defined after including the helper" 14 | end 15 | end 16 | 17 | def test_empty_navigation 18 | expected = <<-END 19 | 20 | END 21 | 22 | render_navigation :main do; end # empty navigation 23 | assert_equal expected.strip, output_buffer; 24 | end 25 | 26 | def test_navigation_with_two_items 27 | expected = <<-END 28 | 33 | END 34 | 35 | render_navigation do 36 | add_item :name => 'seesaw', :link => 'http://www.seesaw.it' 37 | add_item :name => 'blog', :link => 'http://blog.seesaw.it' 38 | end 39 | 40 | assert_html expected, output_buffer; 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /test/showhide_helper_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | require 'test/unit' 3 | 4 | # tableless model 5 | class Post < ActiveRecord::Base 6 | def create_or_update 7 | errors.empty? 8 | end 9 | 10 | def self.columns() 11 | @columns ||= [] 12 | end 13 | 14 | def self.column(name, sql_type = nil, default = nil, null = true) 15 | columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) 16 | end 17 | end 18 | 19 | class Widgets::ShowhideHelperTest < ActionView::TestCase 20 | attr_accessor :output_buffer 21 | include Widgets::ShowhideHelper 22 | 23 | def setup 24 | @params = {:html => {:id=>'custom_html_id', :class=>'custom_css_class'}, 25 | :name => 'custom_name', 26 | :show_link_id => 'custom_show_link_id', 27 | :link_name => 'custom_link_name', 28 | :detail_box_id => 'custom_detail_box_id'} 29 | @post = Post.new 30 | @template = self 31 | clear_buffer 32 | end 33 | 34 | EXPECTED_INSTANCE_METHODS = %w{show_box_for detail_box_for hide_box_for} 35 | 36 | def test_presence_of_instance_methods 37 | EXPECTED_INSTANCE_METHODS.each do |instance_method| 38 | assert respond_to?(instance_method), "#{instance_method} is not defined after including the helper" 39 | end 40 | end 41 | 42 | def test_show_box_for_with_defaults 43 | expected = "show details" 44 | assert_equal expected, show_box_for(@post) 45 | 46 | @post[:id]=23 47 | expected = "show details" 48 | assert_equal expected, show_box_for(@post) 49 | end 50 | 51 | def test_show_box_for_with_name 52 | expected = "show details" 53 | assert_equal expected, show_box_for(@post, :name=>'happyness') 54 | 55 | @post[:id]=23 56 | expected = "show details" 57 | assert_equal expected, show_box_for(@post, :name=>'happyness') 58 | end 59 | 60 | def test_show_box_for_with_full_params 61 | expected = "custom_link_name" 62 | assert_equal expected, show_box_for(@post, @params.merge(:name=>'must_be_overrided')) 63 | end 64 | 65 | def test_show_box_if_not_ar 66 | expected = "show details" 67 | assert_equal expected, show_box_for('my_wonderful-name') 68 | end 69 | 70 | ## hide 71 | 72 | def test_hide_box_for_with_defaults 73 | expected = "hide details" 74 | assert_equal expected, hide_box_for(@post) 75 | 76 | @post[:id]=54 77 | expected = "hide details" 78 | assert_equal expected, hide_box_for(@post) 79 | end 80 | 81 | def test_hide_box_for_with_name 82 | expected = "hide details" 83 | assert_equal expected, hide_box_for(@post, :name=>'fear') 84 | 85 | @post[:id]=54 86 | expected = "hide details" 87 | assert_equal expected, hide_box_for(@post, :name=>'fear') 88 | end 89 | 90 | def test_hide_box_for_with_full_params 91 | expected = "custom_link_name" 92 | assert_equal expected, hide_box_for(@post, @params.merge(:name=>'must_be_overrided')) 93 | end 94 | 95 | def test_hide_box_if_non_ar 96 | expected = "hide details" 97 | assert_equal expected, hide_box_for('my_wonderful-name') 98 | end 99 | 100 | ## detail 101 | 102 | def test_detail_box_should_raise_argument_error 103 | assert_raise(ArgumentError) do 104 | detail_box_for @post 105 | end 106 | end 107 | 108 | def test_detail_box_css_generation 109 | expected = "\n"+ 110 | "
nice Content
" 111 | assert_nothing_raised do 112 | detail_box_for @post, :generate_css=>true do 113 | output_buffer.concat 'nice Content' 114 | end 115 | end 116 | assert_equal expected, output_buffer 117 | end 118 | 119 | def test_detail_box_with_defaults 120 | expected = "
nice Content
" 121 | assert_nothing_raised do 122 | detail_box_for @post do 123 | output_buffer.concat 'nice Content' 124 | end 125 | end 126 | assert_equal expected, output_buffer 127 | 128 | @post[:id]=87 129 | expected = "
nice Content
" 130 | clear_buffer 131 | 132 | assert_nothing_raised do 133 | detail_box_for @post do 134 | output_buffer.concat 'nice Content' 135 | end 136 | end 137 | assert_equal expected, output_buffer 138 | end 139 | 140 | def test_detail_box_with_name 141 | expected = "
nice Content
" 142 | assert_nothing_raised do 143 | detail_box_for @post, :name=>'master' do 144 | output_buffer.concat 'nice Content' 145 | end 146 | end 147 | assert_equal expected, output_buffer 148 | 149 | @post[:id]=87 150 | clear_buffer 151 | expected = "
nice Content
" 152 | assert_nothing_raised do 153 | detail_box_for @post, :name=>'master' do 154 | output_buffer.concat 'nice Content' 155 | end 156 | end 157 | assert_equal expected, output_buffer 158 | end 159 | 160 | def test_detail_box_with_full_params 161 | expected = "
nice Content
" 162 | assert_nothing_raised do 163 | detail_box_for @post, @params.merge(:name=>'must_be_overrided') do 164 | output_buffer.concat 'nice Content' 165 | end 166 | end 167 | assert_equal expected, output_buffer 168 | end 169 | 170 | def test_detail_box_if_not_ar 171 | expected = "
nice Content
" 172 | assert_nothing_raised do 173 | detail_box_for 'my_wonderful-name' do 174 | output_buffer.concat 'nice Content' 175 | end 176 | end 177 | assert_equal expected, output_buffer 178 | end 179 | 180 | protected 181 | 182 | def clear_buffer 183 | @output_buffer = '' 184 | end 185 | 186 | end 187 | -------------------------------------------------------------------------------- /test/spiffy_corners/simple.html: -------------------------------------------------------------------------------- 1 | 40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 |
Ciccio
48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | -------------------------------------------------------------------------------- /test/spiffy_corners/spiffy_corners_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require File.dirname(__FILE__) + '/../test_helper' 3 | 4 | class SpiffyCornersHelperTest < ActionView::TestCase 5 | 6 | attr_accessor :params 7 | include Widgets::SpiffyCorners::SpiffyCornersHelper 8 | 9 | def setup 10 | @params = {} 11 | end 12 | 13 | def test_simple_with_css 14 | expected = load_template('spiffy_corners/simple.html') 15 | 16 | spiffy_corners(:generate_css => true) do concat("Ciccio"); end 17 | assert_equal expected, output_buffer 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/tab_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class TabTest < Test::Unit::TestCase 4 | include Widgets 5 | 6 | EXPECTED_INSTANCE_METHODS = %w{highlights link name title html highlighted? highlights_on links_to named titled} 7 | 8 | def setup 9 | @myname = 'Paolo' 10 | @mysurname = 'Dona' 11 | 12 | @tab = Tab.new :name => 'tab', :link => {:controller => 'pippo', :action => 'pluto'} 13 | @simple_tab = Tab.new :name => 'simple_tab', :link => {:controller =>'pippo'} 14 | 15 | @dyntab = Tab.new :name => @myname, 16 | :link => {:controller => 'pippo', :action => @myname}, 17 | :highlights => [{:controller => @mysurname}] 18 | 19 | @distab = Tab.new :name => 'disabled_tab', 20 | :link => {:controller => 'pippo'}, 21 | :disabled_if => proc { 1 == 1 } 22 | 23 | @empty = Tab.new :name => 'empty' 24 | end 25 | 26 | def test_initialize_with_hash 27 | tab = Tab.new :name => 'sample' 28 | assert tab 29 | assert_equal 'sample', tab.name 30 | end 31 | 32 | def test_initialize_with_block 33 | tab = Tab.new do |t| 34 | t.name = 'sample' 35 | end 36 | assert tab 37 | assert_equal 'sample', tab.name 38 | end 39 | 40 | def test_initialize_with_highlights_array 41 | tab = Tab.new :name=>'test', :highlights => [{:action=>'list'}, {:action => 'index'}] 42 | assert_kind_of Array, tab.highlights 43 | assert_equal 2, tab.highlights.size 44 | assert_kind_of Hash, tab.highlights[0] 45 | assert_kind_of Hash, tab.highlights[1] 46 | end 47 | 48 | def test_initialize_with_single_highlight 49 | tab = Tab.new :name=>'test', :highlights => {:action=>'list'} 50 | assert_kind_of Array, tab.highlights 51 | assert_equal 1, tab.highlights.size 52 | assert_kind_of Hash, tab.highlights[0] 53 | end 54 | 55 | 56 | def test_presence_of_instance_methods 57 | EXPECTED_INSTANCE_METHODS.each do |instance_method| 58 | assert @tab.respond_to?(instance_method), "#{instance_method} is not defined in #{@tab.inspect} (#{@tab.class})" 59 | end 60 | end 61 | 62 | def test_name_dynamic 63 | assert_equal 'Paolo', @dyntab.name 64 | 65 | @dyntab.name= @mysurname 66 | assert_equal 'Dona', @dyntab.name 67 | end 68 | 69 | def test_links_to 70 | assert_equal({:controller => 'pippo', :action => 'pluto'}, @tab.link) 71 | 72 | @tab.link= {:controller => 'pluto'} 73 | assert_equal({:controller => 'pluto'}, @tab.link) 74 | end 75 | 76 | def test_links_to_dynamic 77 | assert_equal({:controller => 'pippo', :action => 'Paolo'}, @dyntab.link) 78 | 79 | @dyntab.link= {:controller => @mysurname} 80 | assert_equal({:controller => 'Dona'}, @dyntab.link) 81 | end 82 | 83 | def test_highlighted? 84 | t = Tab.new :name => 'cats', :highlights => {:controller => 'cats'} 85 | assert t.highlighted?({:controller => 'cats'}) 86 | end 87 | 88 | def test_disabled? 89 | assert @distab.disabled? 90 | assert !@simple_tab.disabled? 91 | end 92 | 93 | end 94 | -------------------------------------------------------------------------------- /test/table_helper_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class TableHelperTest < ActionView::TestCase 4 | 5 | include Widgets::TableHelper 6 | 7 | EXPECTED_INSTANCE_METHODS = %w{tableize} 8 | 9 | def test_presence_of_instance_methods 10 | EXPECTED_INSTANCE_METHODS.each do |instance_method| 11 | assert respond_to?(instance_method), "#{instance_method} is not defined in #{@controller.inspect}" 12 | end 13 | end 14 | 15 | def test_should_raise_argument_error_when_no_block_supplied 16 | assert_raise(ArgumentError, "Missing block in tableize call") do 17 | tableize [], :cols => 3 18 | end 19 | end 20 | 21 | def test_should_raise_argument_error_when_less_than_2_columns_specified 22 | assert_raise(ArgumentError, "Tableize columns must be two or more") do 23 | tableize [], :cols => 1 do; end; 24 | end 25 | end 26 | 27 | def test_should_raise_argument_error_when_collection_not_supplied 28 | assert_raise(ArgumentError, "Missing collection parameter in tableize call") do 29 | tableize nil, {} do; end; 30 | end 31 | 32 | assert_raise(ArgumentError, "Missing collection parameter in tableize call") do 33 | tableize nil, {:collection => nil} do; end; 34 | end 35 | end 36 | 37 | def test_block_invariance 38 | assert_nothing_raised do 39 | tableize ['IS', 'Same!', 'Thing?'], :name => :the_name do |i| 40 | output_buffer.concat i 41 | end 42 | end 43 | expected = output_buffer 44 | assert_nothing_raised do 45 | tableize(['IS', 'Same!', 'Thing?'], :name => :the_name) { |i| output_buffer.concat i } 46 | end 47 | assert_dom_equal expected, output_buffer, 'Block vs Proc generation differs' 48 | end 49 | 50 | def test_empty_layout 51 | tableize [], :cols => 2, :name => :empty_layout do |i| 52 | output_buffer.concat 'nowhere' 53 | end 54 | root = HTML::Document.new(output_buffer).root 55 | assert_select root, 'table.empty_layout_table:root', :count => 1 do 56 | assert_select 'tbody:only-of-type' do 57 | assert_select 'tr', :count => 1 58 | assert_select 'tr td', :count => 0 59 | end 60 | end 61 | end 62 | 63 | def test_1_item_layout 64 | tableize [1], :name => '1_item_layout' do |i| 65 | output_buffer.concat i.to_s 66 | end 67 | root = HTML::Document.new(output_buffer).root 68 | assert_select root, 'table.1_item_layout_table:root', :count => 1 do 69 | assert_select 'tbody:only-of-type' do 70 | assert_select 'tr', :count => 1 71 | assert_select 'tr:first-of-type td', :count => 3 do 72 | assert_select 'td:first-of-type', '1' 73 | assert_select 'td.blank:nth-of-type(2)', ' ' 74 | assert_select 'td.blank:last-of-type', ' ' 75 | end 76 | end 77 | end 78 | end 79 | 80 | def test_row_less_1_item_layout 81 | tableize %w{1 2 3 4 5}, :cols => 6, :name => 'row_less_1_item_layout' do |i| 82 | output_buffer.concat i.to_s 83 | end 84 | root = HTML::Document.new(output_buffer).root 85 | assert_select root, 'table.row_less_1_item_layout_table:root', :count => 1 do 86 | assert_select 'tbody:only-of-type' do 87 | assert_select 'tr', :count => 1 88 | assert_select 'tr:first-of-type td', 6 do 89 | assert_select 'td:first-of-type', '1' 90 | assert_select 'td:nth-of-type(2)', '2' 91 | assert_select 'td:nth-of-type(3)', '3' 92 | assert_select 'td:nth-of-type(4)', '4' 93 | assert_select 'td:nth-of-type(5)', '5' 94 | assert_select 'td.blank:last-of-type', ' ' 95 | end 96 | end 97 | end 98 | end 99 | 100 | def test_full_row_layout 101 | tableize %w{1 2 3 4 5}, :cols => 5, :name => :full_row_layout do |i| 102 | output_buffer.concat i.to_s 103 | end 104 | root = HTML::Document.new(output_buffer).root 105 | assert_select root, 'table.full_row_layout_table:root', :count => 1 do 106 | assert_select 'tbody:only-of-type' do 107 | assert_select 'tr', :count => 1 108 | assert_select 'tr:first-of-type td', :count => 5 do 109 | assert_select 'td:first-of-type', '1' 110 | assert_select 'td:nth-of-type(2)', '2' 111 | assert_select 'td:nth-of-type(3)', '3' 112 | assert_select 'td:nth-of-type(4)', '4' 113 | assert_select 'td:last-of-type', '5' 114 | end 115 | end 116 | end 117 | end 118 | 119 | def test_row_plus_1_item_layout 120 | tableize %w{1 2 3 4 5}, :cols => 4, :name=> 'row_plus_1_item_layout' do |i| 121 | output_buffer.concat i.to_s 122 | end 123 | root = HTML::Document.new(output_buffer).root 124 | assert_select root, 'table.row_plus_1_item_layout_table:root', :count => 1 do 125 | assert_select 'tbody:only-of-type' do 126 | assert_select 'tr', :count => 2 127 | assert_select 'tr:first-of-type td', :count => 4 do 128 | assert_select 'td:first-of-type', '1' 129 | assert_select 'td:nth-of-type(2)', '2' 130 | assert_select 'td:nth-of-type(3)', '3' 131 | assert_select 'td:last-of-type', '4' 132 | end 133 | assert_select 'tr:last-of-type td', :count => 4 do 134 | assert_select 'td:first-of-type', '5' 135 | assert_select 'td.blank:nth-of-type(2)', ' ' 136 | assert_select 'td.blank:nth-of-type(3)', ' ' 137 | assert_select 'td.blank:last-of-type', ' ' 138 | end 139 | end 140 | end 141 | end 142 | 143 | def test_row_with_header_title 144 | tableize %w{1 2 3}, :cols => 4, :header => 'I am a title', :name=> 'row_with_header_title' do |i| 145 | output_buffer.concat i.to_s 146 | end 147 | root = HTML::Document.new(output_buffer).root 148 | assert_select root, 'table.row_with_header_title_table:root', :count => 1 do 149 | assert_select 'tbody:only-of-type' do 150 | assert_select 'tr', :count => 1 151 | assert_select 'th:first-child', 'I am a title' 152 | assert_select 'th:only-of-type', 'I am a title' 153 | 154 | assert_select 'tr > td', 3 155 | assert_select 'td:first-of-type', '1' 156 | assert_select 'td:nth-of-type(2)', '2' 157 | assert_select 'td:last-of-type', '3' 158 | end 159 | end 160 | end 161 | 162 | def test_multiple_rows_skip_header_column 163 | tableize %w{1 2 3 4 5}, :cols => 3, :skip_header_column => true do |i| 164 | output_buffer.concat i.to_s 165 | end 166 | root = HTML::Document.new(output_buffer).root 167 | assert_select root, 'table:root', :count => 1 do 168 | assert_select 'tbody:only-of-type' do 169 | assert_select 'tr', :count => 2 170 | assert_select 'tr:first-of-type td', :count => 3 do 171 | assert_select 'td:first-of-type', '1' 172 | assert_select 'td:nth-of-type(2)', '2' 173 | assert_select 'td:last-of-type', '3' 174 | end 175 | assert_select 'tr:last-of-type td', :count => 3 do 176 | assert_select 'td.blank:first-of-type', ' ' 177 | assert_select 'td:nth-of-type(2)', '4' 178 | assert_select 'td:last-of-type', '5' 179 | end 180 | end 181 | end 182 | end 183 | 184 | def test_options 185 | tableize nil, 186 | :name => :options, 187 | :collection => %w{1 2 3 4 5}, 188 | :generate_css => true, 189 | :header => 'TiTlE', 190 | :html => {:id => 'number', :class => 'demo'}, 191 | :cols => 4 do |i| 192 | output_buffer.concat i.to_s 193 | end 194 | root = HTML::Document.new(output_buffer).root 195 | assert_select root, 'style:root', :count => 1 196 | assert_select root, 'table[class=demo][id=number]:root', :count => 1 do 197 | assert_select 'tbody:only-of-type' do 198 | assert_select 'tr', :count => 2 199 | assert_select 'tr:first-of-type th, tr:first-of-type td', :count => 4 do 200 | assert_select 'th:first-child', 'TiTlE' 201 | assert_select 'th:only-of-type', 'TiTlE' 202 | assert_select 'td:first-of-type', '1' 203 | assert_select 'td:nth-child(2)', '1' 204 | assert_select 'td:nth-of-type(2)', '2' 205 | assert_select 'td:last-of-type', '3' 206 | assert_select 'td:nth-child(4)', '3' 207 | end 208 | assert_select 'tr:last-of-type td', :count => 4 do 209 | assert_select 'td:first-of-type', '4' 210 | assert_select 'td:nth-of-type(2)', '5' 211 | assert_select 'td.blank:nth-of-type(3)', ' ' 212 | assert_select 'td.blank:last-of-type', ' ' 213 | end 214 | end 215 | end 216 | end 217 | 218 | end 219 | -------------------------------------------------------------------------------- /test/tabnav_helper_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class TabnavHelperTest < Test::Unit::TestCase 4 | 5 | EXPECTED_INSTANCE_METHODS = %w{tabnav render_tabnav add_tab} 6 | 7 | def setup 8 | @view = ActionView::Base.new 9 | @view.extend Widgets::TabnavHelper 10 | end 11 | 12 | def test_presence_of_instance_methods 13 | EXPECTED_INSTANCE_METHODS.each do |instance_method| 14 | assert @view.respond_to?(instance_method), "#{instance_method} is not defined in #{@controller.inspect}" 15 | end 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /test/tabnav_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class TabnavTest < ActionView::TestCase 4 | 5 | include Widgets::TabnavHelper 6 | attr_accessor :params 7 | 8 | def setup 9 | @params = {} 10 | end 11 | 12 | def test_default_html_options 13 | tabnav = Widgets::Tabnav.new :sample 14 | assert_equal 'sample_tabnav', tabnav.html[:id] 15 | assert_equal 'sample_tabnav', tabnav.html[:class] 16 | end 17 | 18 | def test_multiple_css_class 19 | render_tabnav :main do 20 | add_tab :html=>{:class=>'home'} do |t| 21 | t.named 'active-tab' 22 | t.links_to 'my/demo/link' 23 | t.highlight! 24 | end 25 | add_tab :html=>{:class=>'custom'} do |t| 26 | t.named 'second' 27 | end 28 | add_tab do |t| 29 | t.named 'middle' 30 | end 31 | add_tab :html=>{:class=>'last'} do |t| 32 | t.named 'disabled-tab' 33 | t.disable! 34 | end 35 | end 36 | 37 | root = HTML::Document.new(output_buffer).root 38 | assert_select root, 'div[class=main_tabnav][id=main_tabnav]:root', :count => 1 do 39 | assert_select 'ul:only-of-type li', :count => 4 do 40 | assert_select 'li[class=home active]:first-of-type' do 41 | assert_select 'a[class=home active]:only-of-type', 'active-tab' 42 | end 43 | assert_select 'li.custom:nth-of-type(2)', 'second' 44 | assert_select 'li:nth-of-type(3)', 'middle' 45 | assert_select 'li[class=last disabled]:last-of-type' do 46 | assert_select 'span[class=last disabled]:only-of-type', 'disabled-tab' 47 | end 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(File.dirname(__FILE__) + '/..') 2 | $:.unshift(File.dirname(__FILE__) + '/../lib') 3 | 4 | require 'rubygems' 5 | require 'test/unit' 6 | require 'active_record' 7 | require 'action_controller' 8 | require 'action_controller/test_process' 9 | require 'action_view/test_case' 10 | require 'init' 11 | 12 | # gem install redgreen for colored test output 13 | begin require 'redgreen'; rescue LoadError; end 14 | 15 | def assert_html expected, actual 16 | expected = clean_html(expected) 17 | actual = clean_html(actual) 18 | assert_equal expected, actual 19 | end 20 | 21 | def clean_html(html_string) 22 | return html_string.strip.gsub(/[\n\r]/, '').gsub(/>\s+<') 23 | end 24 | 25 | def load_template(name) 26 | IO.read(File.join(File.dirname(__FILE__),name)) 27 | end 28 | -------------------------------------------------------------------------------- /test/tooltip_helper_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/test_helper' 2 | 3 | class TooltipHelperTest < ActionView::TestCase 4 | attr_accessor :params 5 | include Widgets::TooltipHelper 6 | 7 | def setup 8 | @params = {} 9 | end 10 | 11 | def test_presence_of_instance_methods 12 | %w{tooltip}.each do |instance_method| 13 | assert respond_to?(instance_method), "#{instance_method} is not defined after including the helper" 14 | end 15 | end 16 | 17 | def test_tooltip_link_function 18 | expected = "$('tooltip_link_one').observe('click', function(event){toggleTooltip(event, $('tooltip_one'))});" 19 | assert_equal expected.strip, tooltip_link_function(:one); 20 | 21 | expected = "$('tooltip_link_two').observe('click', function(event){toggleTooltip(event, $('tooltip_two'))});" 22 | assert_equal expected.strip, tooltip_link_function(:two); 23 | end 24 | 25 | def test_close_tooltip_link 26 | expected = "close" 27 | assert_equal expected.strip, close_tooltip_link(:first); 28 | 29 | expected = "chiudi" 30 | assert_equal expected.strip, close_tooltip_link(:second, 'chiudi'); 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /uninstall.rb: -------------------------------------------------------------------------------- 1 | # Uninstall hook code here 2 | --------------------------------------------------------------------------------