Permalink
Browse files

Merge pull request #827 from justinfrench/date_picker

Add HTML5 date, time & datetime inputs for use with JS date pickers, etc
  • Loading branch information...
2 parents b9dafa3 + e3def79 commit 7bfdb019f98a801fca33c19fe17f3d1b3b15d777 @justinfrench committed Mar 25, 2012
@@ -8,6 +8,8 @@ module Inputs
autoload :CheckBoxesInput
autoload :CountryInput
autoload :DateInput
+ autoload :DatePickerInput
+ autoload :DatetimePickerInput
autoload :DatetimeInput
autoload :EmailInput
autoload :FileInput
@@ -23,6 +25,7 @@ module Inputs
autoload :StringInput
autoload :TextInput
autoload :TimeInput
+ autoload :TimePickerInput
autoload :TimeZoneInput
autoload :Timeish
autoload :UrlInput
@@ -42,6 +42,7 @@ def removed_option!(old_option_name)
extend ActiveSupport::Autoload
+ autoload :DatetimePickerish
autoload :Associations
autoload :Collections
autoload :Choices
@@ -64,6 +65,7 @@ def removed_option!(old_option_name)
include Html
include Options
include Database
+ include Database
include Errors
include Hints
include Naming
@@ -0,0 +1,85 @@
+module Formtastic
+ module Inputs
+ module Base
+ module DatetimePickerish
+ include Base::Placeholder
+
+ def html_input_type
+ raise NotImplementedError
+ end
+
+ def default_size
+ raise NotImplementedError
+ end
+
+ def value
+ raise NotImplementedError
+ end
+
+ def input_html_options
+ super.merge(extra_input_html_options)
+ end
+
+ def extra_input_html_options
+ {
+ :type => html_input_type,
+ :size => size,
+ :maxlength => maxlength,
+ :step => step,
+ :value => value
+ }
+ end
+
+ def size
+ return options[:size] if options.key?(:size)
+ return options[:input_html][:size] if options[:input_html] && options[:input_html].key?(:size)
+ default_size
+ end
+
+ def step
+ return step_from_macro(options[:input_html][:step]) if options[:input_html] && options[:input_html][:step] && options[:input_html][:step].is_a?(Symbol)
+ return options[:input_html][:step] if options[:input_html] && options[:input_html].key?(:step)
+ default_step
+ end
+
+ def maxlength
+ return options[:maxlength] if options.key?(:maxlength)
+ return options[:input_html][:maxlength] if options[:input_html] && options[:input_html].key?(:maxlength)
+ default_size
+ end
+
+ def default_maxlength
+ default_size
+ end
+
+ def default_step
+ 1
+ end
+
+ protected
+
+ def step_from_macro(sym)
+ case sym
+
+ # date
+ when :day then "1"
+ when :seven_days, :week then "7"
+ when :two_weeks, :fortnight then "14"
+ when :four_weeks then "28"
+ when :thirty_days then "30"
+
+ # time
+ when :second then "1"
+ when :minute then "60"
+ when :fifteen_minutes, :quarter_hour then "900"
+ when :thirty_minutes, :half_hour then "1800"
+ when :sixty_minutes, :hour then "3600"
+
+ else sym
+ end
+ end
+
+ end
+ end
+ end
+end
@@ -14,11 +14,19 @@ def to_html
# Overrides standard `input_html_options` to provide a `maxlength` and `size` attribute.
def input_html_options
{
- :maxlength => options[:input_html].try(:[], :maxlength) || limit,
- :size => builder.default_text_field_size
+ :maxlength => maxlength,
+ :size => size
}.merge(super)
end
+ def size
+ builder.default_text_field_size
+ end
+
+ def maxlength
+ options[:input_html].try(:[], :maxlength) || limit
+ end
+
def wrapper_html_options
new_class = [super[:class], "stringish"].compact.join(" ")
super.merge(:class => new_class)
@@ -0,0 +1,93 @@
+module Formtastic
+ module Inputs
+
+ # Outputs a simple `<label>` with a HTML5 `<input type="date">` wrapped in the standard
+ # `<li>` wrapper. This is an alternative to `:date_select` for `:date`, `:time`, `:datetime`
+ # database columns. You can use this input with `:as => :date_picker`.
+ #
+ # *Please note:* Formtastic only provides suitable markup for a date picker, but does not supply
+ # any additional CSS or Javascript to render calendar-style date pickers. Browsers that support
+ # this input type (such as Mobile Webkit and Opera on the desktop) will render a native widget.
+ # Browsers that don't will default to a plain text field`<input type="text">` and can be
+ # poly-filled with some Javascript and a UI library of your choice.
+ #
+ # @example Full form context and output
+ #
+ # <%= semantic_form_for(@post) do |f| %>
+ # <%= f.inputs do %>
+ # <%= f.input :publish_at, :as => :date_picker %>
+ # <% end %>
+ # <% end %>
+ #
+ # <form...>
+ # <fieldset>
+ # <ol>
+ # <li class="string">
+ # <label for="post_publish_at">First name</label>
+ # <input type="date" id="post_publish_at" name="post[publish_at]">
+ # </li>
+ # </ol>
+ # </fieldset>
+ # </form>
+ #
+ # @example Setting the size (defaults to 10 for YYYY-MM-DD)
+ # <%= f.input :publish_at, :as => :date_picker, :size => 20 %>
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :size => 20 } %>
+ #
+ # @example Setting the maxlength (defaults to 10 for YYYY-MM-DD)
+ # <%= f.input :publish_at, :as => :date_picker, :maxlength => 20 %>
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :maxlength => 20 } %>
+ #
+ # @example Setting the value (defaults to YYYY-MM-DD for Date and Time objects, otherwise renders string)
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :value => "1970-01-01" } %>
+ #
+ # @example Setting the step attribute (defaults to 1)
+ # <%= f.input :publish_at, :as => :date_picker, :step => 7 %>
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :step => 7 } %>
+ #
+ # @example Setting the step attribute with a macro
+ # <%= f.input :publish_at, :as => :date_picker, :step => :day %>
+ # <%= f.input :publish_at, :as => :date_picker, :step => :week %>
+ # <%= f.input :publish_at, :as => :date_picker, :step => :seven_days %>
+ # <%= f.input :publish_at, :as => :date_picker, :step => :fortnight %>
+ # <%= f.input :publish_at, :as => :date_picker, :step => :two_weeks %>
+ # <%= f.input :publish_at, :as => :date_picker, :step => :four_weeks %>
+ # <%= f.input :publish_at, :as => :date_picker, :step => :thirty_days %>
+ #
+ # @example Setting the min attribute
+ # <%= f.input :publish_at, :as => :date_picker, :min => "2012-01-01" %>
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :min => "2012-01-01" } %>
+ #
+ # @example Setting the max attribute
+ # <%= f.input :publish_at, :as => :date_picker, :max => "2012-12-31" %>
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :max => "2012-12-31" } %>
+ #
+ # @example Setting the placeholder attribute
+ # <%= f.input :publish_at, :as => :date_picker, :placeholder => 20 %>
+ # <%= f.input :publish_at, :as => :date_picker, :input_html => { :placeholder => "YYYY-MM-DD" } %>
+ #
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
+ class DatePickerInput
+ include Base
+ include Base::Stringish
+ include Base::DatetimePickerish
+
+ def html_input_type
+ "date"
+ end
+
+ def default_size
+ 10
+ end
+
+ def value
+ return options[:input_html][:value] if options[:input_html] && options[:input_html].key?(:value)
+ val = object.send(method)
+ return Date.new(val.year, val.month, val.day).to_s if val.is_a?(Time)
+ return val if val.nil?
+ val.to_s
+ end
+
+ end
+ end
+end
@@ -0,0 +1,100 @@
+module Formtastic
+ module Inputs
+
+ # Outputs a simple `<label>` with a HTML5 `<input type="datetime-local">` (or
+ # `<input type="datetime">`) wrapped in the standard `<li>` wrapper. This is an alternative to
+ # `:date_select` for `:date`, `:time`, `:datetime` database columns. You can use this input with
+ # `:as => :datetime_picker`.
+ #
+ # *Please note:* Formtastic only provides suitable markup for a date picker, but does not supply
+ # any additional CSS or Javascript to render calendar-style date pickers. Browsers that support
+ # this input type (such as Mobile Webkit and Opera on the desktop) will render a native widget.
+ # Browsers that don't will default to a plain text field`<input type="text">` and can be
+ # poly-filled with some Javascript and a UI library of your choice.
+ #
+ # @example Full form context and output
+ #
+ # <%= semantic_form_for(@post) do |f| %>
+ # <%= f.inputs do %>
+ # <%= f.input :publish_at, :as => :datetime_picker %>
+ # <% end %>
+ # <% end %>
+ #
+ # <form...>
+ # <fieldset>
+ # <ol>
+ # <li class="string">
+ # <label for="post_publish_at">First name</label>
+ # <input type="date" id="post_publish_at" name="post[publish_at]">
+ # </li>
+ # </ol>
+ # </fieldset>
+ # </form>
+ #
+ # @example Setting the size (defaults to 16 for YYYY-MM-DD HH:MM)
+ # <%= f.input :publish_at, :as => :datetime_picker, :size => 20 %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :size => 20 } %>
+ #
+ # @example Setting the maxlength (defaults to 16 for YYYY-MM-DD HH:MM)
+ # <%= f.input :publish_at, :as => :datetime_picker, :maxlength => 20 %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :maxlength => 20 } %>
+ #
+ # @example Setting the value (defaults to YYYY-MM-DD HH:MM for Date and Time objects, otherwise renders string)
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :value => "1970-01-01 00:00" } %>
+ #
+ # @example Setting the step attribute (defaults to 1)
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => 60 %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :step => 60 } %>
+ #
+ # @example Setting the step attribute with a macro
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :second %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :minute %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :quarter_hour %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :fifteen_minutes %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :half_hour %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :thirty_minutes %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :hour %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :step => :sixty_minutes %>
+ #
+ # @example Setting the min attribute
+ # <%= f.input :publish_at, :as => :datetime_picker, :min => "2012-01-01 09:00" %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :min => "2012-01-01 09:00" } %>
+ #
+ # @example Setting the max attribute
+ # <%= f.input :publish_at, :as => :datetime_picker, :max => "2012-12-31 16:00" %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :max => "2012-12-31 16:00" } %>
+ #
+ # @example Setting the placeholder attribute
+ # <%= f.input :publish_at, :as => :datetime_picker, :placeholder => "YYYY-MM-DD HH:MM" %>
+ # <%= f.input :publish_at, :as => :datetime_picker, :input_html => { :placeholder => "YYYY-MM-DD HH:MM" } %>
+ #
+ # @example Using `datetime` (UTC) or `datetime-local` with `:local` (defaults to true, `datetime-local` input)
+ # <%= f.input :publish_at, :as => :datetime_picker, :local => false %>
+ #
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
+ class DatetimePickerInput
+ include Base
+ include Base::Stringish
+ include Base::DatetimePickerish
+
+ def html_input_type
+ options[:local] = true unless options.key?(:local)
+ options[:local] ? "datetime-local" : "datetime"
+ end
+
+ def default_size
+ 16
+ end
+
+ def value
+ return options[:input_html][:value] if options[:input_html] && options[:input_html].key?(:value)
+ val = object.send(method)
+ return val.strftime("%Y-%m-%d %H:%M") if val.is_a?(Time)
+ return "#{val.year}-#{val.month}-#{val.day} 00:00" if val.is_a?(Date)
+ return val if val.nil?
+ val.to_s
+ end
+
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 7bfdb01

Please sign in to comment.