Skip to content
Browse files

Add support for a single text input picker.

  • Loading branch information...
1 parent e33aa68 commit 85be3574dd53192f890bb2a7109d4d560f73bc05 brianjlandau committed Oct 1, 2008
View
18 README.rdoc
@@ -34,8 +34,10 @@ There are 4 main methods:
- unobtrusive_datetime_picker
- unobtrusive_date_picker_tags
- unobtrusive_datetime_picker_tags
+ - unobtrusive_date_text_picker
+ - unobtrusive_date_text_picker_tag
-Options (* indicates same functionality as is in Rails helpers):
+Options (* indicates same functionality as is in Rails Date helpers):
- *:order => the order the selects should be positioned in
- *:include_blank => include a blank option at the top of every select
- *:start_year => year that the year select should start on (defaults to 5
@@ -66,6 +68,20 @@ Options (* indicates same functionality as is in Rails helpers):
- :no_transparency => if set to true it disables the fade in/out
visual effect of the datepicker
+The `unobtrusive_date_text_picker` and `unobtrusive_date_text_picker_tag` methods
+don't except the ":order", ":include_blank", ":start_year", ":end_year", ":minute_step", ":use_short_month",
+":use_month_numbers", and ":add_month_numbers" options.
+It does use these options though:
+ - :format => the format the date should be in
+ - m-d-y
+ - d-m-y
+ - y-m-d
+ - :divider => the divider used between the dates
+ - "slash" or "/"
+ - "dash" or "-"
+ - "dot" or "."
+ - "space" or " "
+
==== RJS Method
View
2 about.yml
@@ -1,6 +1,6 @@
name: Unobtrusive Date-Picker Widget
author: Brian Landau
-version: 1.3
+version: 1.4
description: Helper to create a set of Date/Time selects that use the Unobtrusive Date Picker Widget.
url: http://code.google.com/p/rails-unobtrusive-date-picker/
install: http://rails-unobtrusive-date-picker.googlecode.com/svn/trunk/unobtrusive_date_picker
View
180 lib/12_hour_time.rb
@@ -1,4 +1,3 @@
-
#
# == Rails Twelve Hour Time Plugin
#
@@ -15,115 +14,122 @@
# :enddoc:
class ActiveRecord::Base # :nodoc: all
- def extract_callstack_for_multiparameter_attributes_with_ampm(pairs)
- attributes = extract_callstack_for_multiparameter_attributes_without_ampm(pairs)
- attributes.each do |name, values|
- klass = (self.class.reflect_on_aggregation(name) ||
- column_for_attribute(name)).klass
- if klass == Time && values.length == 6
- if values[5] == ActionView::Helpers::DateHelper::AM && values[3] == 12
- values[3] = 0
- elsif values[5] == ActionView::Helpers::DateHelper::PM && values[3] != 12
- values[3] += 12
- end
- end
+ def extract_callstack_for_multiparameter_attributes_with_ampm(pairs)
+ attributes = extract_callstack_for_multiparameter_attributes_without_ampm(pairs)
+ attributes.each do |name, values|
+ klass = (self.class.reflect_on_aggregation(name) ||
+ column_for_attribute(name)).klass
+ if klass == Time && values.length == 6
+ if values[5] == ActionView::Helpers::DateHelper::AM && values[3] == 12
+ values[3] = 0
+ elsif values[5] == ActionView::Helpers::DateHelper::PM && values[3] != 12
+ values[3] += 12
+ end
end
- end
+ end
+ end
- alias_method_chain :extract_callstack_for_multiparameter_attributes, :ampm
+ alias_method_chain :extract_callstack_for_multiparameter_attributes, :ampm
end
module ActionView::Helpers::DateHelper # :nodoc: all
- AM = 'AM'
- PM = 'PM'
+ AM = 'AM'
+ PM = 'PM'
- def select_hour_with_ampm(datetime, options = {}, html_options = {})
- options[:twelve_hour] or return select_hour_without_ampm(datetime, options)
+ def select_hour_with_ampm(datetime, options = {}, html_options = {})
+ options[:twelve_hour] or return select_hour_without_ampm(datetime, options, html_options)
- val = _12_hour(datetime)
+ val = _12_hour(datetime)
- if options[:use_hidden]
- return hidden_html(options[:field_name] || 'hour', val, options)
- end
+ if options[:use_hidden]
+ return hidden_html(options[:field_name] || 'hour', val, options)
+ end
- hour_options = []
- 1.upto(12) do |hour|
- selected = (hour == val) ? ' selected="selected"' : ''
- hour_options << %(<option value="#{leading_zero_on_single_digits(hour)}"#{selected}>#{leading_zero_on_single_digits(hour)}</option>\n)
- end
+ hour_options = []
+ 1.upto(12) do |hour|
+ hour_options << ((val == hour) ?
+ content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour), :selected => "selected") :
+ content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour))
+ )
+ hour_options << "\n"
+ end
- select_html(options[:field_name] || 'hour', hour_options, options, html_options)
- end
+ select_html(options[:field_name] || 'hour', hour_options, options, html_options)
+ end
- alias_method_chain :select_hour, :ampm
+ alias_method_chain :select_hour, :ampm
- def select_ampm(datetime, options = {}, html_options = {})
- ampm = [AM, PM]
- val = datetime ? (ampm.include?(datetime) ? datetime : datetime.strftime("%p")) : ''
+ def select_ampm(datetime, options = {}, html_options = {})
+ ampm = [AM, PM]
+ val = datetime ? (ampm.include?(datetime) ? datetime : datetime.strftime("%p")) : ''
- if options[:use_hidden]
- return hidden_html(options[:field_name] || 'ampm', val, options)
- end
+ if options[:use_hidden]
+ return hidden_html(options[:field_name] || 'ampm', val, options)
+ end
- ampm_options = []
- ampm.each do |meridiem|
- selected = (meridiem == val) ? ' selected="selected"' : ''
- ampm_options << %(<option value="#{meridiem}"#{selected}>#{meridiem}</option>\n)
- end
+ ampm_options = []
+ ampm.each do |meridiem|
+ selected = (meridiem == val) ? ' selected="selected"' : ''
+ ampm_options << ((meridiem == val) ?
+ content_tag(:option, meridiem, :value => meridiem, :selected => "selected") :
+ content_tag(:option, meridiem, :value => meridiem)
+ )
+ ampm_options << "\n"
+ end
- select_html(options[:field_name] || 'ampm', ampm_options, options, html_options)
- end
+ select_html(options[:field_name] || 'ampm', ampm_options, options, html_options)
+ end
- def select_time_with_ampm(datetime = Time.now, options = {}, html_options = {})
- select = select_time_without_ampm(datetime, options, html_options)
- select << select_ampm(datetime, options, html_options) if options[:twelve_hour]
- select
- end
+ def select_time_with_ampm(datetime = Time.now, options = {}, html_options = {})
+ select = select_time_without_ampm(datetime, options, html_options)
+ select << select_ampm(datetime, options, html_options) if options[:twelve_hour]
+ select
+ end
- alias_method_chain :select_time, :ampm
+ alias_method_chain :select_time, :ampm
- private
+ private
- def _12_hour(datetime)
- return '' if datetime.blank?
+ def _12_hour(datetime)
+ return '' if datetime.blank?
- hour = datetime.kind_of?(Fixnum) ? datetime : datetime.hour
- hour = 12 if hour == 0
- hour -= 12 if hour > 12
+ hour = datetime.kind_of?(Fixnum) ? datetime : datetime.hour
+ hour = 12 if hour == 0
+ hour -= 12 if hour > 12
- return hour
- end
+ return hour
+ end
end
class ActionView::Helpers::InstanceTag # :nodoc: all
- def date_or_time_select_with_ampm(options, html_options)
- options[:twelve_hour] and not options[:discard_hour] or
- return date_or_time_select_without_ampm(options, html_options)
-
- defaults = { :discard_type => true }
- options = defaults.merge(options)
-
- datetime = value(object)
- datetime ||= Time.now unless options[:include_blank]
-
- date_or_time_select_without_ampm(options, html_options) +
- select_ampm(datetime, options_with_prefix(6, options.merge(:use_hidden => options[:discard_hour], :string => true)))
- end
-
- alias_method_chain :date_or_time_select, :ampm
-
- def options_with_prefix_with_ampm(position, options)
- prefix = "#{@object_name}"
- if options[:index]
- prefix << "[#{options[:index]}]"
- elsif @auto_index
- prefix << "[#{@auto_index}]"
- end
- if options[:string]
- options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}s)]")
- else
- options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
- end
- end
+ def date_or_time_select_with_ampm(options, html_options = {})
+ options[:twelve_hour] and not options[:discard_hour] or
+ return date_or_time_select_without_ampm(options, html_options)
+
+ defaults = { :discard_type => true }
+ options = defaults.merge(options)
+
+ datetime = value(object)
+ datetime ||= default_time_from_options(options[:default]) unless options[:include_blank]
+
+ date_or_time_select_without_ampm(options, html_options) +
+ select_ampm(datetime, options_with_prefix(6, options.merge(:use_hidden => options[:discard_hour], :string => true)))
+ end
+
+ alias_method_chain :date_or_time_select, :ampm
+
+ def options_with_prefix_with_ampm(position, options)
+ prefix = "#{@object_name}"
+ if options[:index]
+ prefix << "[#{options[:index]}]"
+ elsif @auto_index
+ prefix << "[#{@auto_index}]"
+ end
+ if options[:string]
+ options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}s)]")
+ else
+ options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
+ end
+ end
end
View
800 lib/unobtrusive_date_picker.rb
@@ -2,411 +2,473 @@
require 'time'
module UnobtrusiveDatePicker
-
- # == Unobtrusive Date-Picker Helper
- #
- # This Module helps to create date and date-time fields that use the
- # Unobtrusive Date-Picker Javascript Widget.
- #
- # They also use the 12-hour AM/PM time format.
- #
- module UnobtrusiveDatePickerHelper
-
- DATEPICKER_DEFAULT_NAME_ID_SUFFIXES = {:year => {:id => '', :name => 'year'},
- :month => {:id => 'mm', :name => 'month'},
- :day => {:id => 'dd', :name => 'day'}}
-
- DATEPICKER_DAYS_OF_WEEK = {:Monday => '0',
- :Tuesday => '1',
- :Wednesday => '2',
- :Thursday => '3',
- :Friday => '4',
- :Saturday => '5',
- :Sunday => '6'}
-
- RANGE_DATE_FORMAT = '%Y-%m-%d'
-
- ##
- # Creates the date picker with the calendar widget.
- #
- def unobtrusive_date_picker(object_name, method, options = {})
- ActionView::Helpers::InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datepicker_date_select_tag(options)
+
+ # == Unobtrusive Date-Picker Helper
+ #
+ # This Module helps to create date and date-time fields that use the
+ # Unobtrusive Date-Picker Javascript Widget.
+ #
+ # They also use the 12-hour AM/PM time format.
+ #
+ module UnobtrusiveDatePickerHelper
+
+ DATEPICKER_DEFAULT_NAME_ID_SUFFIXES = { :year => {:id => '', :name => 'year'},
+ :month => {:id => 'mm', :name => 'month'},
+ :day => {:id => 'dd', :name => 'day'} }
+
+ DATEPICKER_DAYS_OF_WEEK = { :Monday => '0',
+ :Tuesday => '1',
+ :Wednesday => '2',
+ :Thursday => '3',
+ :Friday => '4',
+ :Saturday => '5',
+ :Sunday => '6'}
+
+ DATEPICKER_DIVIDERS = { 'slash' => '/',
+ 'dash' => '-',
+ 'dot' => '.',
+ 'space' => ' ' }
+
+ RANGE_DATE_FORMAT = '%Y-%m-%d'
+
+ ##
+ # Creates the date picker with the calendar widget.
+ #
+ def unobtrusive_date_picker(object_name, method, options = {}, html_options = {})
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datepicker_date_select_tag(options, html_options)
+ end
+
+ ##
+ # Creates the date-time picker with the calendar widget, and AM/PM select.
+ #
+ def unobtrusive_datetime_picker(object_name, method, options = {}, html_options = {})
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datepicker_datetime_select_tag(options, html_options)
+ end
+
+ ##
+ # Creates the date picker with the calendar widget.
+ #
+ def unobtrusive_date_text_picker(object_name, method, options = {}, html_options = {})
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datepicker_text_tag(options, html_options)
+ end
+
+ ##
+ # Creates the date picker with the calendar widget without a model object.
+ #
+ def unobtrusive_date_picker_tags(date = Date.today, options = {}, html_options = {})
+ options[:prefix] = html_options.delete(:id)
+ options[:order] ||= []
+ [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
+
+ date_picker = ''
+ options[:order].each do |o|
+ date_picker << self.send("datepicker_select_#{o}", date, options, html_options)
end
-
- ##
- # Creates the date-time picker with the calendar widget, and AM/PM select.
- #
- def unobtrusive_datetime_picker(object_name, method, options = {})
- ActionView::Helpers::InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datepicker_datetime_select_tag(options)
+ date_picker
+ end
+
+ ##
+ # Creates the date-time picker with the calendar widget, and AM/PM select without a model object
+ #
+ def unobtrusive_datetime_picker_tags(datetime = Time.now, options = {}, html_options = {})
+ options[:prefix] = html_options.delete(:id)
+ separator = options[:datetime_separator] || ''
+
+ datetime_picker = unobtrusive_date_picker_tags(datetime, options, html_options) + separator
+
+ datetime_picker << datepicker_select_hour(datetime, options, html_options) + ':'
+ datetime_picker << datepicker_select_minute(datetime, options, html_options) + ' '
+ datetime_picker << datepicker_select_ampm(datetime, options, html_options)
+
+ datetime_picker
+ end
+
+ ##
+ # Creates the text field based date picker with the calendar widget without a model object.
+ #
+ def unobtrusive_date_text_picker_tag(name, date = Date.today, options = {}, html_options = {})
+ options, html_options = datepicker_text_field_options(options, html_options)
+ value = format_date_value_for_text_field(options[:format], options[:divider], date)
+ text_field_tag(name, value, html_options)
+ end
+
+ def datepicker_select_ampm(datetime, options = {}, html_options = {})
+ ampm = %w(AM PM)
+ val = datetime ? (ampm.include?(datetime) ? datetime : datetime.strftime("%p")) : ''
+
+ ampm_options = []
+ ampm.each { |meridiem|
+ ampm_options << ((val == meridiem) ?
+ %(<option value="#{meridiem}" selected="selected">#{meridiem}</option>\n) :
+ %(<option value="#{meridiem}">#{meridiem}</option>\n)
+ )
+ }
+
+ select_html(options[:field_name] || 'ampm', ampm_options, options, html_options)
+ end
+
+ def datepicker_select_hour(datetime, options = {}, html_options = {})
+ val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.strftime("%I").to_i) : ''
+
+ hour_options = []
+ 1.upto(12) do |hour|
+ hour_options << ((val == hour) ?
+ %(<option value="#{hour}" selected="selected">#{hour}</option>\n) :
+ %(<option value="#{hour}">#{hour}</option>\n)
+ )
end
-
- ##
- # Creates the date picker with the calendar widget without a model object.
- #
- def unobtrusive_date_picker_tags(date = Date.today, options = {})
- options[:prefix] = options.delete(:id)
- options[:order] ||= []
- [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
-
- date_picker = ''
- options[:order].each do |o|
- date_picker << self.send("datepicker_select_#{o}", date, options)
- end
- date_picker
+
+ select_html(options[:field_name] || 'hour', hour_options, options, html_options)
+ end
+
+ ##
+ # Can except a "<tt>minute_step</tt>" option which will specify how many minutes to move forward on each loop.
+ #
+ # i.e. if set to 15: 0, 15, 30, and 45 will be the options supplied in the minute select
+ #
+ def datepicker_select_minute(datetime, options = {}, html_options = {})
+ val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.strftime("%M").to_i) : ''
+
+ minute_options = []
+ 0.step(59, options[:minute_step] || 1) do |minute|
+ minute_options << ((val == minute) ?
+ %(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
+ %(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
+ )
end
-
- ##
- # Creates the date-time picker with the calendar widget, and AM/PM select without a model object
- #
- def unobtrusive_datetime_picker_tags(datetime = Time.now, options = {})
- options[:prefix] = options.delete(:id)
- separator = options[:datetime_separator] || ''
-
- datetime_picker = unobtrusive_date_picker_tags(datetime, options) + separator
-
- datetime_picker << datepicker_select_hour(datetime, options) + ':'
- datetime_picker << datepicker_select_minute(datetime, options) + ' '
- datetime_picker << datepicker_select_ampm(datetime, options)
-
- datetime_picker
+
+ select_html(options[:field_name] || 'minute', minute_options, options, html_options)
+ end
+
+ def datepicker_select_day(date, options = {}, html_options = {})
+ val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
+
+ day_options = []
+ 1.upto(31) do |day|
+ day_options << ((val == day) ?
+ %(<option value="#{day}" selected="selected">#{day}</option>\n) :
+ %(<option value="#{day}">#{day}</option>\n)
+ )
end
-
- def datepicker_select_ampm(datetime, options = {})
- ampm = %w(AM PM)
- val = datetime ? (ampm.include?(datetime) ? datetime : datetime.strftime("%p")) : ''
-
- ampm_options = []
- ampm.each { |meridiem|
- ampm_options << ((val == meridiem) ?
- %(<option value="#{meridiem}" selected="selected">#{meridiem}</option>\n) :
- %(<option value="#{meridiem}">#{meridiem}</option>\n)
- )
- }
-
- select_html(options[:field_name] || 'ampm', ampm_options, options)
+
+ datepicker_select_html(:day, day_options, options, html_options)
+ end
+
+ ##
+ # This method will accept a hash for the option "<tt>use_month_names</tt>" where the key is the month number
+ # and the value is the month name. It will also accept a boolean option "<tt>use_short_mont</tt>" that will
+ # allow the use of short names instead of full names for the option text. Will also take "<tt>use_month_numbers</tt>",
+ # and "<tt>add_month_numbers</tt>" which use or add month numbers to the option item text.
+ #
+ def datepicker_select_month(date, options = {}, html_options = {})
+ val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
+
+ month_options = []
+ month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
+ month_names.unshift(nil) if month_names.size < 13
+ 1.upto(12) do |month_number|
+ month_name = if options[:use_month_numbers]
+ month_number
+ elsif options[:add_month_numbers]
+ month_number.to_s + ' - ' + month_names[month_number]
+ else
+ month_names[month_number]
+ end
+
+ month_options << ((val == month_number) ?
+ %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
+ %(<option value="#{month_number}">#{month_name}</option>\n)
+ )
end
-
- def datepicker_select_hour(datetime, options = {})
- val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.strftime("%I").to_i) : ''
-
- hour_options = []
- 1.upto(12) do |hour|
- hour_options << ((val == hour) ?
- %(<option value="#{hour}" selected="selected">#{hour}</option>\n) :
- %(<option value="#{hour}">#{hour}</option>\n)
- )
- end
-
- select_html(options[:field_name] || 'hour', hour_options, options)
+
+ datepicker_select_html(:month, month_options, options, html_options)
+ end
+
+ ##
+ # This method will accept a "<tt>start_year</tt>" and "<tt>end_year</tt>" options.
+ #
+ def datepicker_select_year(date, options = {}, html_options = {})
+ val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
+
+ y = date ? (date.kind_of?(Fixnum) ? (date == 0 ? Date.today.year : date) : date.year) : Date.today.year
+ start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
+ step_val = start_year < end_year ? 1 : -1
+
+ year_options = []
+ start_year.step(end_year, step_val) do |year|
+ year_options << ((val == year) ?
+ %(<option value="#{year}" selected="selected">#{year}</option>\n) :
+ %(<option value="#{year}">#{year}</option>\n)
+ )
end
+
+ html_classes = make_date_picker_class_options(options).push('split-date')
+ html_options[:class] = html_options[:class] ? "#{html_options[:class]} #{html_classes.join(' ')}" : html_classes.join(' ')
+ datepicker_select_html(:year, year_options, options, html_options)
+ end
+
+ protected
+
+ def datepicker_select_html(type, html_options, options, select_tag_options = {}) # :nodoc:
+ datepicker_name_and_id(type, options)
+
+ select_options = {:id => options[:id], :name => options[:name]}
+ select_options.merge!(:disabled => 'disabled') if options[:disabled]
+ select_options.merge!(select_tag_options) unless select_tag_options.empty?
- ##
- # Can except a "<tt>minute_step</tt>" option which will specify how many minutes to move forward on each loop.
- #
- # i.e. if set to 15: 0, 15, 30, and 45 will be the options supplied in the minute select
- #
- def datepicker_select_minute(datetime, options = {})
- val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.strftime("%M").to_i) : ''
-
- minute_options = []
- 0.step(59, options[:minute_step] || 1) do |minute|
- minute_options << ((val == minute) ?
- %(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
- %(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
- )
- end
-
- select_html(options[:field_name] || 'minute', minute_options, options)
+ select_html = "\n"
+ select_html << content_tag(:option, '', :value => '') + "\n" if options[:include_blank]
+ select_html << html_options.to_s
+ content_tag(:select, select_html, select_options) + "\n"
+ end
+
+ def datepicker_name_and_id(type, html_options) # :nodoc:
+ if html_options[:id_prefix]
+ html_options[:id] = (type == :year) ? "#{html_options[:id_prefix]}" : "#{html_options[:id_prefix]}-#{DATEPICKER_DEFAULT_NAME_ID_SUFFIXES[type][:id]}"
+ else
+ html_options[:prefix] ||= ActionView::Helpers::DateHelper::DEFAULT_PREFIX
+ html_options[:id] = ((type == :year) ?
+ html_options[:prefix] :
+ html_options[:prefix] + "-#{DATEPICKER_DEFAULT_NAME_ID_SUFFIXES[type][:id]}"
+ )
+ html_options[:name] = html_options[:prefix] + "[#{DATEPICKER_DEFAULT_NAME_ID_SUFFIXES[type][:name]}]"
end
+ end
+
+ def datepicker_text_field_options(options, html_options)
+ defaults = {:format => 'm-d-y', :divider => 'slash'}
+ options = defaults.merge(options)
+ html_classes = make_date_picker_class_options(options)
+ html_options[:class] = html_options[:class] ? "#{html_options[:class]} #{html_classes.join(' ')}" : html_classes.join(' ')
+ [options, html_options]
+ end
+
+ def format_date_value_for_text_field(format, divider_option, value)
+ divider = DATEPICKER_DIVIDERS[parse_divider_option(divider_option)]
+ format_string = format.downcase.gsub(/(m|d)/, '%\1').gsub(/y/, '%Y').gsub('-', divider)
+ value.strftime(format_string)
+ end
- def datepicker_select_day(date, options = {})
- val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
-
- day_options = []
- 1.upto(31) do |day|
- day_options << ((val == day) ?
- %(<option value="#{day}" selected="selected">#{day}</option>\n) :
- %(<option value="#{day}">#{day}</option>\n)
- )
- end
-
- datepicker_select_html(:day, day_options, options)
+ def make_date_picker_class_options(options = {}) # :nodoc:
+ html_classes = []
+
+ if options[:highlight_days]
+ highlight_days = parse_days_of_week(options[:highlight_days])
+ if !highlight_days.blank?
+ html_classes << "highlight-days-#{highlight_days}"
+ end
end
-
- ##
- # This method will accept a hash for the option "<tt>use_month_names</tt>" where the key is the month number
- # and the value is the month name. It will also accept a boolean option "<tt>use_short_mont</tt>" that will
- # allow the use of short names instead of full names for the option text. Will also take "<tt>use_month_numbers</tt>",
- # and "<tt>add_month_numbers</tt>" which use or add month numbers to the option item text.
- #
- def datepicker_select_month(date, options = {})
- val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
-
- month_options = []
- month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
- month_names.unshift(nil) if month_names.size < 13
- 1.upto(12) do |month_number|
- month_name = if options[:use_month_numbers]
- month_number
- elsif options[:add_month_numbers]
- month_number.to_s + ' - ' + month_names[month_number]
- else
- month_names[month_number]
- end
-
- month_options << ((val == month_number) ?
- %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
- %(<option value="#{month_number}">#{month_name}</option>\n)
- )
- end
-
- datepicker_select_html(:month, month_options, options)
+
+ if options[:range_low]
+ range_low = parse_range_option(options[:range_low], 'low')
+ if !range_low.blank?
+ html_classes << range_low
+ end
end
-
- ##
- # This method will accept a "<tt>start_year</tt>" and "<tt>end_year</tt>" options.
- #
- def datepicker_select_year(date, options = {})
- val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
-
- y = date ? (date.kind_of?(Fixnum) ? (date == 0 ? Date.today.year : date) : date.year) : Date.today.year
- start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
- step_val = start_year < end_year ? 1 : -1
-
- year_options = []
- start_year.step(end_year, step_val) do |year|
- year_options << ((val == year) ?
- %(<option value="#{year}" selected="selected">#{year}</option>\n) :
- %(<option value="#{year}">#{year}</option>\n)
- )
- end
-
- html_classes = add_date_picker_class_options(options).push('split-date')
- options[:class] = options[:class] ? "#{options[:class]} #{html_classes.join(' ')}" : html_classes.join(' ')
- datepicker_select_html(:year, year_options, options)
+
+ if options[:range_high]
+ range_high = parse_range_option(options[:range_high], 'high')
+ if !range_high.blank?
+ html_classes << range_high
+ end
end
- protected
-
- def datepicker_select_html(type, date_options, html_options = {}) # :nodoc:
- datepicker_name_and_id(type, html_options)
-
- select_html = %(<select id="#{html_options[:id]}" name="#{html_options[:name]}")
- select_html << %( class="#{html_options[:class]}") if html_options[:class]
- select_html << %( title="#{html_options[:title]}") if html_options[:title]
- select_html << %( disabled="disabled") if html_options[:disabled]
- select_html << %(>\n)
- select_html << %(<option value=""></option>\n) if html_options[:include_blank]
- select_html << date_options.to_s
- select_html << "</select>\n"
+ if options[:disable_days]
+ disable_days = parse_days_of_week(options[:disable_days])
+ if !disable_days.blank?
+ html_classes << "disable-days-#{disable_days}"
+ end
end
- def datepicker_name_and_id(type, html_options) # :nodoc:
- if html_options[:id_prefix]
- html_options[:id] = (type == :year) ? "#{html_options[:id_prefix]}" : "#{html_options[:id_prefix]}-#{DATEPICKER_DEFAULT_NAME_ID_SUFFIXES[type][:id]}"
- else
- html_options[:prefix] ||= ActionView::Helpers::DateHelper::DEFAULT_PREFIX
- html_options[:id] = ((type == :year) ?
- html_options[:prefix] :
- html_options[:prefix] + "-#{DATEPICKER_DEFAULT_NAME_ID_SUFFIXES[type][:id]}"
- )
- html_options[:name] = html_options[:prefix] + "[#{DATEPICKER_DEFAULT_NAME_ID_SUFFIXES[type][:name]}]"
- end
+ if options[:no_transparency]
+ html_classes << 'no-transparency'
end
- def add_date_picker_class_options(options = {}) # :nodoc:
- html_classes = []
-
- if options[:highlight_days]
- highlight_days = parse_days_of_week(options[:highlight_days])
- if !highlight_days.blank?
- html_classes << "highlight-days-#{highlight_days}"
- end
- end
-
- if options[:range_low]
- range_low = parse_range_option(options[:range_low], 'low')
- if !range_low.blank?
- html_classes << range_low
- end
- end
-
- if options[:range_high]
- range_high = parse_range_option(options[:range_high], 'high')
- if !range_high.blank?
- html_classes << range_high
- end
- end
-
- if options[:disable_days]
- disable_days = parse_days_of_week(options[:disable_days])
- if !disable_days.blank?
- html_classes << "disable-days-#{disable_days}"
- end
- end
-
- if options[:no_transparency]
- html_classes << 'no-transparency'
- end
-
- html_classes
+ if options[:format] && %W(d-m-y m-d-y y-m-d).include?(options[:format].downcase)
+ html_classes << "format-#{options[:format].downcase}"
end
- def parse_days_of_week(option) # :nodoc:
- if option.is_a? String
- option
- elsif option.is_a? Symbol
- DATEPICKER_DAYS_OF_WEEK[option]
- elsif option.is_a? Array
- days = ''
- option.each do |day|
- days << DATEPICKER_DAYS_OF_WEEK[day]
- end
- days
- end
+ if options[:divider]
+ html_classes << "divider-#{parse_divider_option(options[:divider])}"
end
-
- def parse_range_option(option, direction) # :nodoc:
- if option.is_a? Symbol
- case option
- when :today
- range_class = 'today'
- when :tomorrow
- range_class = Date.tomorrow.strftime(RANGE_DATE_FORMAT)
- when :yesterday
- range_class = Date.yesterday.strftime(RANGE_DATE_FORMAT)
- end
- elsif option.is_a? String
- if !option.blank?
- range_class = Date.parse(option).strftime(RANGE_DATE_FORMAT)
- else
- range_class = nil
- end
- elsif (option.is_a?(Date) || option.is_a?(DateTime) || option.is_a?(Time))
- range_class = option.strftime(RANGE_DATE_FORMAT)
- else
- range_class = nil
- end
-
- if !range_class.blank?
- range_class = 'range-' + direction + '-' + range_class
- else
- nil
- end
+
+ html_classes
+ end
+
+ def parse_days_of_week(option) # :nodoc:
+ if option.is_a? String
+ option
+ elsif option.is_a? Symbol
+ DATEPICKER_DAYS_OF_WEEK[option]
+ elsif option.is_a? Array
+ days = ''
+ option.each do |day|
+ days << DATEPICKER_DAYS_OF_WEEK[day]
+ end
+ days
end
-
- end
-
- module AssetTagHelper
- ##
- # This will add the necessary <link> and <script> tags to include the necessary stylesheet and
- # javascripts.
- #
- def unobtrusive_datepicker_includes(options = {})
- output = []
- output << javascript_include_tag('datepicker', options)
- output << stylesheet_link_tag('datepicker', options)
- output * "\n"
+ end
+
+ def parse_range_option(option, direction) # :nodoc:
+ if option.is_a? Symbol
+ case option
+ when :today
+ range_class = 'today'
+ when :tomorrow
+ range_class = Date.tomorrow.strftime(RANGE_DATE_FORMAT)
+ when :yesterday
+ range_class = Date.yesterday.strftime(RANGE_DATE_FORMAT)
+ end
+ elsif option.is_a? String
+ if !option.blank?
+ range_class = Date.parse(option).strftime(RANGE_DATE_FORMAT)
+ else
+ range_class = nil
+ end
+ elsif (option.is_a?(Date) || option.is_a?(DateTime) || option.is_a?(Time))
+ range_class = option.strftime(RANGE_DATE_FORMAT)
+ else
+ range_class = nil
end
- end
-
- module InstanceTag # :nodoc: all
- include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
-
- def to_datepicker_datetime_select_tag(options)
- datepicker_select(options, true)
+
+ if !range_class.blank?
+ range_class = 'range-' + direction + '-' + range_class
+ else
+ nil
end
-
- def to_datepicker_date_select_tag(options)
- datepicker_select(options, false)
+ end
+
+ def parse_divider_option(option)
+ if DATEPICKER_DIVIDERS.keys.include?(option)
+ option
+ else
+ DATEPICKER_DIVIDERS.find {|name, value| option == value}.first
end
-
- private
-
- def datepicker_select(options, time)
- defaults = { :discard_type => true }
- options = defaults.merge(options)
-
- datetime = value(object)
- datetime ||= Time.now unless options[:include_blank]
-
- position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :ampm => 6 }
- order = (options[:order] ||= [:day, :month, :year])
-
- # Maintain valid dates by including hidden fields for discarded elements
- [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
-
- # Ensure proper ordering of :hour, :minute and :second
- if time
- [:hour, :minute, :ampm].each { |o| order.delete(o); order.push(o) }
- end
-
- date_or_time_select = ''
- order.reverse.each do |param|
- if param == :ampm
- date_or_time_select.insert(0, self.send("datepicker_select_#{param}", datetime, datepicker_options_with_prefix(position[param], options.merge(:string => true))))
- else
- date_or_time_select.insert(0, self.send("datepicker_select_#{param}", datetime, datepicker_options_with_prefix(position[param], options)))
- end
- date_or_time_select.insert(0,
- case param
- when :hour then " &nbsp; "
- when :minute then " : "
- else ""
- end)
- end
-
- date_or_time_select
+ end
+
+ end
+
+ module AssetTagHelper
+ ##
+ # This will add the necessary <link> and <script> tags to include the necessary stylesheet and
+ # javascripts.
+ #
+ def unobtrusive_datepicker_includes(options = {})
+ output = []
+ output << javascript_include_tag('datepicker', options)
+ output << stylesheet_link_tag('datepicker', options)
+ output * "\n"
+ end
+ end
+
+ module InstanceTag # :nodoc: all
+ include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
+
+ def to_datepicker_datetime_select_tag(options = {}, html_options = {})
+ datepicker_select(options, true, html_options)
+ end
+
+ def to_datepicker_date_select_tag(options = {}, html_options = {})
+ datepicker_select(options, false, html_options)
+ end
+
+ def to_datepicker_text_tag(options = {}, html_options = {})
+ options, html_options = datepicker_text_field_options(options, html_options)
+ html_options[:value] = format_date_value_for_text_field(options[:format], options[:divider], value(object))
+ to_input_field_tag('text', html_options)
+ end
+
+ private
+
+ def datepicker_select(options, time, html_options = {})
+ defaults = { :discard_type => true }
+ options = defaults.merge(options)
+
+ datetime = value(object)
+ datetime ||= Time.now unless options[:include_blank]
+
+ position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :ampm => 6 }
+ order = (options[:order] ||= [:day, :month, :year])
+
+ # Maintain valid dates by including hidden fields for discarded elements
+ [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
+
+ # Ensure proper ordering of :hour, :minute and :second
+ if time
+ [:hour, :minute, :ampm].each { |o| order.delete(o); order.push(o) }
end
-
- def datepicker_options_with_prefix(position, options)
- prefix = "#{@object_name}"
- if options[:index]
- prefix << "[#{options[:index]}]"
- elsif @auto_index
- prefix << "[#{@auto_index}]"
- end
- options[:id_prefix] = "#{@object_name}_#{@method_name}"
- if options[:string]
- options[:name] = "#{prefix}[#{@method_name}(#{position}s)]"
- options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}s)]")
- else
- options[:name] = "#{prefix}[#{@method_name}(#{position}i)]"
- options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
- end
+
+ date_or_time_select = ''
+ order.reverse.each do |param|
+ if param == :ampm
+ date_or_time_select.insert(0, self.send("datepicker_select_#{param}", datetime, datepicker_options_with_prefix(position[param], options.merge(:string => true)), html_options))
+ else
+ date_or_time_select.insert(0, self.send("datepicker_select_#{param}", datetime, datepicker_options_with_prefix(position[param], options), html_options))
+ end
+ date_or_time_select.insert(0,
+ case param
+ when :hour then " &nbsp; "
+ when :minute then " : "
+ else ""
+ end
+ )
end
-
- end
+
+ date_or_time_select
+ end
+
+ def datepicker_options_with_prefix(position, options)
+ prefix = "#{@object_name}"
+ if options[:index]
+ prefix << "[#{options[:index]}]"
+ elsif @auto_index
+ prefix << "[#{@auto_index}]"
+ end
+ options[:id_prefix] = "#{@object_name}_#{@method_name}"
+ if options[:string]
+ options[:name] = "#{prefix}[#{@method_name}(#{position}s)]"
+ options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}s)]")
+ else
+ options[:name] = "#{prefix}[#{@method_name}(#{position}i)]"
+ options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
+ end
+ end
+
+ end
end
# /UnobtrusiveDatePicker
module ActionView::Helpers::PrototypeHelper # :nodoc: all
- class JavaScriptGenerator
- module GeneratorMethods
- def unobtrusive_date_picker_create(id = nil)
- if id
- call "datePickerController.create", "$(#{id})"
- else
- record "datePickerController.create"
- end
- end
+ class JavaScriptGenerator
+ module GeneratorMethods
+ def unobtrusive_date_picker_create(id = nil)
+ if id
+ call "datePickerController.create", "$(#{id})"
+ else
+ record "datePickerController.create"
+ end
end
- end
+ end
+ end
end
module ActionView # :nodoc: all
- module Helpers
- class FormBuilder
- def unobtrusive_date_picker(method, options = {})
- @template.unobtrusive_date_picker(@object_name, method, options.merge(:object => @object))
- end
-
- def unobtrusive_datetime_picker(method, options = {})
- @template.unobtrusive_datetime_picker(@object_name, method, options.merge(:object => @object))
- end
+ module Helpers
+ class FormBuilder
+ def unobtrusive_date_picker(method, options = {}, html_options = {})
+ @template.unobtrusive_date_picker(@object_name, method, options.merge(:object => @object), html_options)
+ end
+
+ def unobtrusive_date_text_picker(method, options = {}, html_options = {})
+ @template.unobtrusive_date_text_picker(@object_name, method, options.merge(:object => @object), html_options)
+ end
+
+ def unobtrusive_datetime_picker(method, options = {}, html_options = {})
+ @template.unobtrusive_datetime_picker(@object_name, method, options.merge(:object => @object), html_options)
end
- end
+ end
+ end
end
View
48 spec/date_picker_form_builder_spec.rb
@@ -2,55 +2,57 @@
require 'erb'
describe "the date picker form builder helpers" do
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::TextHelper
- include ActionView::Helpers::UrlHelper
- include ActionView::Helpers::FormTagHelper
- include ActionView::Helpers::FormHelper
- include ActionView::Helpers::DateHelper
- include ActionView::Helpers::ActiveRecordHelper
- include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
+ it_should_behave_like "all date picker helpers"
before(:each) do
- @date = Date.parse("March 15, 2007")
- @date_model = stub('DateModel', :date => @date, :id => 1)
+ @created = Date.parse("March 5, 2007")
+ @updated = Date.parse("March 15, 2007")
+
+ @date_model = stub('DateModel', :updated_at => @updated, :created_at => @created, :id => 1)
@template = ERB.new <<-ERB
<% form_for(:date_model, @date_model, :url => 'http://www.example.com/submit', :html => {:method => :get}) do |form| %>
- <%= form.unobtrusive_date_picker(:date) %>
+ <%= form.unobtrusive_date_picker(:created_at) %>
+ <%= form.unobtrusive_date_text_picker(:updated_at) %>
<% end %>
ERB
@form = @template.result(binding)
end
it "should have the correct year select with class and select the correct year" do
- year_id = 'date_model_date'
- year_name = 'date_model[date(1i)]'
+ year_id = 'date_model_created_at'
+ year_name = 'date_model[created_at(1i)]'
@form.should include_tag(:select, :attributes => {:id => year_id, :name => year_name, :class => 'split-date'},
:child => {:tag => 'option',
- :attributes => {:value => @date.year.to_s, :selected => 'selected'},
- :content => @date.year.to_s})
+ :attributes => {:value => @created.year.to_s, :selected => 'selected'},
+ :content => @created.year.to_s})
end
it "should have the correct month select with class and select the correct month" do
- month_id = 'date_model_date-mm'
- month_name = 'date_model[date(2i)]'
+ month_id = 'date_model_created_at-mm'
+ month_name = 'date_model[created_at(2i)]'
@form.should include_tag(:select, :attributes => {:id => month_id, :name => month_name},
:child => {:tag => 'option',
- :attributes => {:value => @date.month.to_s, :selected => 'selected'},
- :content => Date::MONTHNAMES[@date.month]})
+ :attributes => {:value => @created.month.to_s, :selected => 'selected'},
+ :content => Date::MONTHNAMES[@created.month]})
end
it "should have the correct day select with class and select the correct day" do
- day_id = 'date_model_date-dd'
- day_name = 'date_model[date(3i)]'
+ day_id = 'date_model_created_at-dd'
+ day_name = 'date_model[created_at(3i)]'
@form.should include_tag(:select, :attributes => {:id => day_id, :name => day_name},
:child => {:tag => 'option',
- :attributes => {:value => @date.day.to_s, :selected => 'selected'},
- :content => @date.day.to_s})
+ :attributes => {:value => @created.day.to_s, :selected => 'selected'},
+ :content => @created.day.to_s})
+ end
+
+ it "should have a text field with the correct classes" do
+ text_field_id = 'date_model_updated_at'
+
+ @form.should selector_tag("input\##{text_field_id}.format-m-d-y.divider-slash[type='text'][value='03/15/2007']")
end
after(:each) do
View
11 spec/date_picker_tag_spec.rb
@@ -1,14 +1,5 @@
require File.dirname(__FILE__) + '/spec_helper'
-describe "all date picker helpers", :shared => true do
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::FormTagHelper
- include ActionView::Helpers::FormHelper
- include ActionView::Helpers::DateHelper
- include ActionView::Helpers::ActiveRecordHelper
- include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
-end
-
describe UnobtrusiveDatePicker, "with no data passed to tag helper" do
it_should_behave_like "all date picker helpers"
@@ -82,7 +73,7 @@
@date = Date.parse("March 15, 2007")
@start_year = 1945
@end_year = Date.today.year
- @datepicker = unobtrusive_date_picker_tags(@date, {:id => @id, :use_short_month => true, :start_year => @start_year, :end_year => @end_year})
+ @datepicker = unobtrusive_date_picker_tags(@date, {:use_short_month => true, :start_year => @start_year, :end_year => @end_year}, {:id => @id})
end
it "should have a year select tag with options that start with the start date and end with the end date" do
View
36 spec/date_picker_text_field_spec.rb
@@ -0,0 +1,36 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe "a unobtrusive_date_text_picker with a stub ActiveRecord object" do
+ it_should_behave_like "all date picker helpers"
+
+ before(:each) do
+ @date = Date.parse("March 15, 2007")
+ @date_model = stub('DateModel', :date => @date, :id => 1)
+ @datepicker_html = unobtrusive_date_text_picker(:date_model, :date, :format => 'd-m-y', :divider => 'dash')
+ end
+
+ it "should have all the correct classes and attributes" do
+ @datepicker_html.should selector_tag("input#date_model_date.format-d-m-y.divider-dash[type='text'][value='15-03-2007']")
+ end
+
+ after(:each) do
+ @date, @date_model, @datepicker_html = nil
+ end
+end
+
+describe "a unobtrusive_date_text_picker_tag with a stub ActiveRecord object" do
+ it_should_behave_like "all date picker helpers"
+
+ before(:each) do
+ @date = Date.parse("March 15, 2007")
+ @datepicker_html = unobtrusive_date_text_picker_tag(:date_value, @date, :divider => '.')
+ end
+
+ it "should have all the correct classes and attributes" do
+ @datepicker_html.should selector_tag("input#date_value.format-m-d-y.divider-dot[type='text'][value='03.15.2007']")
+ end
+
+ after(:each) do
+ @date, @datepicker_html = nil
+ end
+end
View
19 spec/datepicker_html_class_options_spec.rb
@@ -1,13 +1,6 @@
require File.dirname(__FILE__) + '/spec_helper'
describe "all date picker form helpers", :shared => true do
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::FormTagHelper
- include ActionView::Helpers::FormHelper
- include ActionView::Helpers::DateHelper
- include ActionView::Helpers::ActiveRecordHelper
- include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
-
before(:each) do
@date = Date.parse("March 15, 2007")
@date_model = stub('DateModel', :date => @date, :id => 1)
@@ -20,6 +13,7 @@
describe UnobtrusiveDatePicker, "with :highlight_days option passed a string" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -42,6 +36,7 @@
describe UnobtrusiveDatePicker, "with :highlight_days option passed an array of symbols" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -64,6 +59,7 @@
describe UnobtrusiveDatePicker, "with :highlight_days option passed an empty array" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -84,6 +80,7 @@
describe UnobtrusiveDatePicker, "with :range_low option passed :today" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -105,6 +102,7 @@
describe UnobtrusiveDatePicker, "with :range_low option passed :tomorrow" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -127,6 +125,7 @@
describe UnobtrusiveDatePicker, "with :range_high option passed a string" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -150,6 +149,7 @@
describe UnobtrusiveDatePicker, "with :range_high option passed a Date object" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -173,6 +173,7 @@
describe UnobtrusiveDatePicker, "with :range_high passed nil and :range_low option passed an empty string" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -193,6 +194,7 @@
describe UnobtrusiveDatePicker, "with :disable_days option passed an array of symbols" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -215,6 +217,7 @@
describe UnobtrusiveDatePicker, "with :disable_days option passed an empty array" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -235,6 +238,7 @@
describe UnobtrusiveDatePicker, "with :no_transparency option set to true" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
@@ -256,6 +260,7 @@
describe UnobtrusiveDatePicker, "with :no_transparency option set to false" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all date picker form helpers"
before(:each) do
View
11 spec/spec_helper.rb
@@ -20,10 +20,21 @@
ActionController::Base.consider_all_requests_local = true
ActionController::Base.allow_forgery_protection = false
+describe "all date picker helpers", :shared => true do
+ include ActionView::Helpers::TagHelper
+ include ActionView::Helpers::TextHelper
+ include ActionView::Helpers::UrlHelper
+ include ActionView::Helpers::FormTagHelper
+ include ActionView::Helpers::FormHelper
+ include ActionView::Helpers::DateHelper
+ include ActionView::Helpers::ActiveRecordHelper
+ include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
+end
Spec::Runner.configure do |config|
config.include(TagMatcher)
+ config.include(SelectorMatcher)
# == Mock Framework
#
View
110 spec/tag_matcher.rb
@@ -30,3 +30,113 @@ def include_tag(*opts)
end
end
+
+module SelectorMatcher
+ class SelectorTag
+ def initialize(*expected)
+ # Then get mandatory selector.
+ arg = expected.shift
+
+ # string and we pass all remaining arguments.
+ # Array and we pass the argument. Also accepts selector itself.
+ case arg
+ when String
+ selector = HTML::Selector.new(arg, expected)
+ when Array
+ selector = HTML::Selector.new(*arg)
+ when HTML::Selector
+ selector = arg
+ else raise ArgumentError, "Expecting a selector as the first argument"
+ end
+
+ # Next argument is used for equality tests.
+ equals = {}
+ case arg = expected.shift
+ when Hash
+ equals = arg
+ when String, Regexp
+ equals[:text] = arg
+ when Integer
+ equals[:count] = arg
+ when Range
+ equals[:minimum] = arg.begin
+ equals[:maximum] = arg.end
+ when FalseClass
+ equals[:count] = 0
+ when NilClass, TrueClass
+ equals[:minimum] = 1
+ else raise ArgumentError, "I don't understand what you're trying to match"
+ end
+
+ # By default we're looking for at least one match.
+ if equals[:count]
+ equals[:minimum] = equals[:maximum] = equals[:count]
+ else
+ equals[:minimum] = 1 unless equals[:minimum]
+ end
+
+ @expected = {:selector => selector, :equals => equals}
+ end
+
+ def matches?(target)
+ @target = HTML::Document.new(target, false, false).root
+
+ matches = @expected[:selector].select(@target)
+
+ # If text/html, narrow down to those elements that match it.
+ content_mismatch = nil
+ if match_with = @expected[:equals][:text]
+ matches.delete_if do |match|
+ text = ""
+ text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding)
+ stack = match.children.reverse
+ while node = stack.pop
+ if node.tag?
+ stack.concat node.children.reverse
+ else
+ content = node.content
+ content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding)
+ text << content
+ end
+ end
+ text.strip! unless NO_STRIP.include?(match.name)
+ unless match_with.is_a?(Regexp) ? (text =~ match_with) : (text == match_with.to_s)
+ true
+ end
+ end
+ elsif match_with = @expected[:equals][:html]
+ matches.delete_if do |match|
+ html = match.children.map(&:to_s).join
+ html.strip! unless NO_STRIP.include?(match.name)
+ unless match_with.is_a?(Regexp) ? (html =~ match_with) : (html == match_with.to_s)
+ true
+ end
+ end
+ end
+
+ # Test minimum/maximum occurrence.
+ min, max = @expected[:equals][:minimum], @expected[:equals][:maximum]
+ if min && !max
+ return matches.size >= min
+ elsif max && !min
+ return matches.size <= max
+ elsif min && max
+ return (matches.size >= min) && (matches.size <= max)
+ else
+ return true
+ end
+ end
+
+ def failure_message
+ "expected tag, but no tag found matching #{@expected.inspect} in #{@target.to_s}"
+ end
+
+ def negative_failure_message
+ "expected no tag, but tag was found matching #{@expected.inspect} in #{@target.to_s}"
+ end
+ end
+
+ def selector_tag(*opts)
+ SelectorTag.new(*opts)
+ end
+end
View
9 spec/unobtrusive_date_picker_spec.rb
@@ -1,13 +1,6 @@
require File.dirname(__FILE__) + '/spec_helper'
describe "all datetime picker form helpers", :shared => true do
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::FormTagHelper
- include ActionView::Helpers::FormHelper
- include ActionView::Helpers::DateHelper
- include ActionView::Helpers::ActiveRecordHelper
- include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
-
before(:each) do
@time = Time.parse("March 15, 2007 2:37PM")
@datetime_model = stub('DateTimeModel', :datetime => @time, :id => 2)
@@ -19,6 +12,7 @@
end
describe UnobtrusiveDatePicker, "with a stub ActiveRecord object" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all datetime picker form helpers"
before(:each) do
@@ -93,6 +87,7 @@
describe UnobtrusiveDatePicker, "with a minute step and month numbers options specified" do
+ it_should_behave_like "all date picker helpers"
it_should_behave_like "all datetime picker form helpers"
before(:each) do

0 comments on commit 85be357

Please sign in to comment.
Something went wrong with that request. Please try again.