rd_unobtrusive_date_picker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/MIT-LICENSE +19 -0
  2. data/Manifest +45 -0
  3. data/README.rdoc +165 -0
  4. data/Rakefile +29 -0
  5. data/about.yml +7 -0
  6. data/init.rb +8 -0
  7. data/install.rb +14 -0
  8. data/lib/12_hour_time.rb +102 -0
  9. data/lib/unobtrusive_date_picker.rb +407 -0
  10. data/public/images/backstripes.gif +0 -0
  11. data/public/images/bg_header.jpg +0 -0
  12. data/public/images/bullet1.gif +0 -0
  13. data/public/images/bullet2.gif +0 -0
  14. data/public/images/cal.gif +0 -0
  15. data/public/images/gradient-e5e5e5-ffffff.gif +0 -0
  16. data/public/javascripts/datepicker.js +1445 -0
  17. data/public/javascripts/lang/af.js +40 -0
  18. data/public/javascripts/lang/ar.js +50 -0
  19. data/public/javascripts/lang/de.js +40 -0
  20. data/public/javascripts/lang/du.js +40 -0
  21. data/public/javascripts/lang/en.js +42 -0
  22. data/public/javascripts/lang/es.js +41 -0
  23. data/public/javascripts/lang/fi.js +40 -0
  24. data/public/javascripts/lang/fr.js +44 -0
  25. data/public/javascripts/lang/gr.js +40 -0
  26. data/public/javascripts/lang/he.js +49 -0
  27. data/public/javascripts/lang/it.js +13 -0
  28. data/public/javascripts/lang/nl.js +40 -0
  29. data/public/javascripts/lang/no.js +40 -0
  30. data/public/javascripts/lang/pt.js +50 -0
  31. data/public/javascripts/lang/ro.js +40 -0
  32. data/public/javascripts/lang/ru.js +40 -0
  33. data/public/javascripts/lang/sp.js +40 -0
  34. data/public/javascripts/lang/sv.js +41 -0
  35. data/public/javascripts/lang/ua.js +40 -0
  36. data/public/stylesheets/datepicker.css +263 -0
  37. data/spec/date_picker_tag_spec.rb +122 -0
  38. data/spec/date_picker_text_field_spec.rb +54 -0
  39. data/spec/datepicker_html_class_options_spec.rb +281 -0
  40. data/spec/spec.opts +12 -0
  41. data/spec/spec_helper.rb +52 -0
  42. data/spec/tag_matcher.rb +142 -0
  43. data/spec/unobtrusive_date_picker_spec.rb +129 -0
  44. data/tasks/datepicker_tasks.rake +17 -0
  45. data/uninstall.rb +12 -0
  46. data/unobtrusive_date_picker.gemspec +30 -0
  47. metadata +116 -0
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007 Brian J. Landau, <brianjlandau@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ MIT-LICENSE
2
+ Manifest
3
+ README.rdoc
4
+ Rakefile
5
+ about.yml
6
+ init.rb
7
+ install.rb
8
+ lib/12_hour_time.rb
9
+ lib/unobtrusive_date_picker.rb
10
+ public/images/backstripes.gif
11
+ public/images/bg_header.jpg
12
+ public/images/bullet1.gif
13
+ public/images/bullet2.gif
14
+ public/images/cal.gif
15
+ public/images/gradient-e5e5e5-ffffff.gif
16
+ public/javascripts/datepicker.js
17
+ public/javascripts/lang/af.js
18
+ public/javascripts/lang/ar.js
19
+ public/javascripts/lang/de.js
20
+ public/javascripts/lang/du.js
21
+ public/javascripts/lang/en.js
22
+ public/javascripts/lang/es.js
23
+ public/javascripts/lang/fi.js
24
+ public/javascripts/lang/fr.js
25
+ public/javascripts/lang/gr.js
26
+ public/javascripts/lang/he.js
27
+ public/javascripts/lang/it.js
28
+ public/javascripts/lang/nl.js
29
+ public/javascripts/lang/no.js
30
+ public/javascripts/lang/pt.js
31
+ public/javascripts/lang/ro.js
32
+ public/javascripts/lang/ru.js
33
+ public/javascripts/lang/sp.js
34
+ public/javascripts/lang/sv.js
35
+ public/javascripts/lang/ua.js
36
+ public/stylesheets/datepicker.css
37
+ spec/date_picker_tag_spec.rb
38
+ spec/date_picker_text_field_spec.rb
39
+ spec/datepicker_html_class_options_spec.rb
40
+ spec/spec.opts
41
+ spec/spec_helper.rb
42
+ spec/tag_matcher.rb
43
+ spec/unobtrusive_date_picker_spec.rb
44
+ tasks/datepicker_tasks.rake
45
+ uninstall.rb
@@ -0,0 +1,165 @@
1
+ = Unobtrusive Date-Picker Widget Plugin
2
+
3
+ This is a helper for creating a date or date-time picker that uses the
4
+ Unobtrusive Date-Picker Widget(sic)
5
+ (http://www.frequency-decoder.com/2006/10/02/unobtrusive-date-picker-widgit-update)
6
+ to add a clickable calendar image that will bring up a calendar picker if
7
+ javascript is available. It replicates as much of the API of the Rails
8
+ `date_select`, and `datetime_select` form helpers.
9
+
10
+ It also uses the 12 Hour Time plugin
11
+ (http://code.google.com/p/rails-twelve-hour-time-plugin/) so that 12 Hour times
12
+ can be processed by Active Record.
13
+
14
+ You may want to consider compressing the javascript files with Dean Edward's
15
+ Packer (http://dean.edwards.name/packer/) or Douglas Crockford's JSMin
16
+ (http://www.crockford.com/javascript/jsmin.html) before deploying your
17
+ application.
18
+
19
+ == Install
20
+
21
+ `script/plugin install git://github.com/brianjlandau/unobtrusive_date_picker.git`
22
+
23
+ == Usage
24
+
25
+ To be able to use the date-picker methods below you need to include the
26
+ javascript library file and CSS stylesheet in the <head> of your layout
27
+ template. You can do this either by manually including the files via a
28
+ `javascript_include_tag` and a `stylesheet_link_tag` (the files are both named
29
+ "datepicker"), OR by using the included `unobtrusive_datepicker_includes` helper
30
+ method, which will do this for you.
31
+
32
+ There are 4 main methods:
33
+ - unobtrusive_date_picker
34
+ - unobtrusive_datetime_picker
35
+ - unobtrusive_date_picker_tags
36
+ - unobtrusive_datetime_picker_tags
37
+ - unobtrusive_date_text_picker
38
+ - unobtrusive_date_text_picker_tag
39
+
40
+ Options (* indicates same functionality as is in Rails Date helpers):
41
+ - *:order => the order the selects should be positioned in
42
+ - *:include_blank => include a blank option at the top of every select
43
+ - *:start_year => year that the year select should start on (defaults to 5
44
+ below either the year of the date value or current year)
45
+ - *:end_year => year that the year select should end on (defaults to 5 above
46
+ either the year of the date value or current year)
47
+ - *:minute_step => how many minutes apart each minute option should be
48
+ - example: (:minute_step => 5) would result in [0, 15, 30, 45] as options
49
+ - *:use_short_month => use short month names (Jan, Feb, etc.) instead of long
50
+ names (January) for option text
51
+ - *:use_month_numbers => use month numbers instead of names for option text
52
+ - *:add_month_numbers => add month numbers to names for option text ("1 - January")
53
+ - :highlight_days => which days of the week should be highlighted in the datepicker (by default Saturday and Sunday)
54
+ - Excepts either a string of number representing days of the week (0 = Monday, 1 = Tuesday ... 6 = Sunday)
55
+ - Or a singular symbol for one day of the week
56
+ - Or an array of symbols representing days of the week, i.e. [:Monday, :Sunday]
57
+ - :range_low => the low range of acceptable dates (not times) for this input
58
+ - managed by the Javascript, thus should be enforced with your own validations
59
+ - Excepts:
60
+ - One of the following symbols: :today, :tomorrow, :yesterday
61
+ - A string representation of a date
62
+ - A Date, DateTime, or Time object
63
+ - :range_high => the high range of acceptable dates (not times) for this input
64
+ - Excepts same options as :range_low; also managed by javascript
65
+ - :disable_days => days of the week that may not be selected
66
+ - Excepts the same format as :highlight_days
67
+ - Also managed by javascript
68
+ - :no_transparency => if set to true it disables the fade in/out
69
+ visual effect of the datepicker
70
+
71
+ The `unobtrusive_date_text_picker` and `unobtrusive_date_text_picker_tag` methods
72
+ don't except the ":order", ":include_blank", ":start_year", ":end_year", ":minute_step", ":use_short_month",
73
+ ":use_month_numbers", and ":add_month_numbers" options.
74
+ It does use these options though:
75
+ - :format => the format the date should be in
76
+ - m-d-y
77
+ - d-m-y
78
+ - y-m-d
79
+ - :divider => the divider used between the dates
80
+ - "slash" or "/"
81
+ - "dash" or "-"
82
+ - "dot" or "."
83
+ - "space" or " "
84
+
85
+
86
+ ==== RJS Method
87
+
88
+ There is an additional RJS method to re initialize the Date Pickers when an AJAX
89
+ response is supplied to the client:
90
+
91
+ - unobtrusive_date_picker_create
92
+ - This method can accept the DOM ID of a year select element to turn into
93
+ a date picker widget or if none is provided it will create all based on
94
+ the appropriate class name.
95
+
96
+
97
+ ==== Rake task
98
+
99
+ There is also a rake task that can be executed by running `rake
100
+ datepicker:update` in your Rails apps root directory. This task will update your
101
+ datepicker javascripts, stylesheets, and images. This is useful if you are using
102
+ an old version of the plugin that had an older version of the Unobtrusive
103
+ Date-Picker Widget Javascript library, or in the future when new version are
104
+ release and I update the plugin with them.
105
+
106
+
107
+
108
+ === Example:
109
+ <% form_for :article, :url => { :action => @form_action, :id => @article } do |f| %>
110
+ <fieldset>
111
+ ...
112
+ <label>Date: <%= f.unobtrusive_datetime_picker :date %></label><br />
113
+ ...
114
+ </fieldset>
115
+ <% end %>
116
+
117
+ === Produces (Current date when output: 12/6/07):
118
+ <form action="/form/create" method="post">
119
+ <fieldset>
120
+
121
+ <label>Date:
122
+ <select id="article_date-dd" name="article[date(3i)]">
123
+ <option value="1">1</option>
124
+ ...
125
+ <option value="31">31</option>
126
+ </select>
127
+ <select id="article_date-mm" name="article[date(2i)]">
128
+ <option value="1">January</option>
129
+ ...
130
+ <option value="12" selected="selected">December</option>
131
+ </select>
132
+ <select id="article_date" name="article[date(1i)]" class="split-date">
133
+ <option value="2002">2002</option>
134
+ ...
135
+ <option value="2012">2012</option>
136
+ </select>
137
+ &nbsp;
138
+ <select id="article_date_4i" name="article[date(4i)][hour]">
139
+ <option value="1">1</option>
140
+ ...
141
+ <option value="12">12</option>
142
+ </select>
143
+ :
144
+ <select id="article_date_5i" name="article[date(5i)][minute]">
145
+ <option value="00">00</option>
146
+ ...
147
+ <option value="59">59</option>
148
+ </select>
149
+ <select id="article_date_6i" name="article[date(6i)][ampm]">
150
+ <option value="AMPM>AMPM</option>
151
+ <option value="AMPM>AMPM</option>
152
+ </select>
153
+ </label><br />
154
+
155
+ </fieldset>
156
+ </form>
157
+
158
+
159
+
160
+ == LICENSE
161
+
162
+ See MIT-LICENSE file for copyright and licensing information for this plugin.
163
+
164
+ Unobtrusive Date-Picker Widget is provided under the Creative Commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/) by frequency-decoder.com
165
+
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ require 'rubygems'
4
+ require 'spec/rake/spectask'
5
+
6
+ desc 'Generate documentation for the unobtrusive_date_picker plugin.'
7
+ Rake::RDocTask.new(:rdoc) do |rdoc|
8
+ rdoc.rdoc_dir = 'rdoc'
9
+ rdoc.title = 'Unobtrusive Date-Picker'
10
+ rdoc.options << '--line-numbers' << '--inline-source'
11
+ rdoc.rdoc_files.add ['lib/**/*.rb', 'README.rdoc']
12
+ rdoc.options << '--main' << 'README.rdoc'
13
+ end
14
+
15
+ desc "Run all specs"
16
+ Spec::Rake::SpecTask.new do |t|
17
+ t.spec_opts = ['--options', 'spec/spec.opts']
18
+ end
19
+
20
+ require 'echoe'
21
+
22
+ Echoe.new('unobtrusive_date_picker', '0.1.0') do |p|
23
+ p.description = "Helper for creating a date or date-time picker that uses the Unobtrusive Date-Picker Widge"
24
+ p.url = "http://github.com/brianjlandau/unobtrusive_date_picker"
25
+ p.author = "Brian landau"
26
+ p.email = ""
27
+ p.ignore_pattern = ["tmp/*", "script/*"]
28
+ p.development_dependencies = []
29
+ end
@@ -0,0 +1,7 @@
1
+ name: Unobtrusive Date-Picker Widget
2
+ author: Brian Landau
3
+ version: 2.0
4
+ description: Helper to create a set of Date/Time selects that use the Unobtrusive Date Picker Widget.
5
+ url: http://github.com/brianjlandau/unobtrusive_date_picker/
6
+ install: git@github.com:brianjlandau/unobtrusive_date_picker.git
7
+ license: MIT
data/init.rb ADDED
@@ -0,0 +1,8 @@
1
+ require '12_hour_time'
2
+ require 'unobtrusive_date_picker'
3
+
4
+ # Include all the necessary functions in to the appropriate point in the Rails framework
5
+ ActionView::Base.send :include, UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
6
+ ActionView::Helpers::DateHelper.send :include, UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
7
+ ActionView::Base.send :include, UnobtrusiveDatePicker::AssetTagHelper
8
+ ActionView::Helpers::AssetTagHelper.send :include, UnobtrusiveDatePicker::AssetTagHelper
@@ -0,0 +1,14 @@
1
+ require 'fileutils'
2
+
3
+ # Install all the needed support files (CSS and JavaScript)
4
+
5
+ js_dir = File.dirname(__FILE__) + '/../../../public/javascripts/'
6
+ datepicker_js = js_dir + 'datepicker.js'
7
+ lang_dir = js_dir + 'lang'
8
+ datepicker_css = File.dirname(__FILE__) + '/../../../public/stylesheets/datepicker.css'
9
+ images_dir = File.dirname(__FILE__) + '/../../../public/images/datepicker'
10
+
11
+ FileUtils.cp File.dirname(__FILE__) + '/public/javascripts/datepicker.js', datepicker_js unless File.exists?(datepicker_js)
12
+ FileUtils.cp_r File.dirname(__FILE__) + '/public/javascripts/lang/', lang_dir unless File.exists?(lang_dir)
13
+ FileUtils.cp File.dirname(__FILE__) + '/public/stylesheets/datepicker.css', datepicker_css unless File.exists?(datepicker_css)
14
+ FileUtils.cp_r File.dirname(__FILE__) + '/public/images/', images_dir unless File.exists?(images_dir)
@@ -0,0 +1,102 @@
1
+ #
2
+ # == Rails Twelve Hour Time Plugin
3
+ #
4
+ # http://code.google.com/p/rails-twelve-hour-time-plugin/
5
+ #
6
+ # ==== Authors
7
+ # * Nick Muerdter (original code)
8
+ # * Maurice Aubrey
9
+ #
10
+ # ==== Used for
11
+ # Allows UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper to use a AM/PM select of it's own,
12
+ # and still be processed correctly by Active Record.
13
+ #
14
+
15
+ # :enddoc:
16
+ if defined? ActiveRecord
17
+ class ActiveRecord::Base # :nodoc: all
18
+ def instantiate_time_object_with_ampm(name, values)
19
+ if values.last < 0
20
+ ampm = values.pop
21
+ if ampm == ActionView::Helpers::DateTimeSelector::AM and values[3] == 12
22
+ values[3] = 0
23
+ elsif ampm == ActionView::Helpers::DateTimeSelector::PM and values[3] != 12
24
+ values[3] += 12
25
+ end
26
+ end
27
+
28
+ instantiate_time_object_without_ampm(name, values)
29
+ end
30
+
31
+ alias_method_chain :instantiate_time_object, :ampm
32
+ end
33
+ end
34
+
35
+ ActionView::Helpers::DateTimeSelector.send(:remove_const, :POSITION)
36
+ ActionView::Helpers::DateTimeSelector.const_set(:POSITION, {
37
+ :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5,
38
+ :second => 6, :ampm => 7
39
+ })
40
+
41
+ # Included manully in UnobtrusiveDatePicker
42
+ # module ActionView::Helpers
43
+ # class DateTimeSelector
44
+ # POSITION = {
45
+ # :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5,
46
+ # :second => 6, :ampm => 7
47
+ # }
48
+ # # XXX would like to do this, but it's frozen
49
+ # # POSITION[:ampm] = 7
50
+ #
51
+ # # We give them negative values so can differentiate between normal
52
+ # # date/time values. The way the multi param stuff works, from what I
53
+ # # can see, results in a variable number of fields (if you tell it to
54
+ # # include seconds, for example). So we expect the AM/PM field, if
55
+ # # present, to be last and have a negative value.
56
+ # AM = -1
57
+ # PM = -2
58
+ #
59
+ # def select_hour_with_ampm
60
+ # unless @options[:twelve_hour]
61
+ # return select_hour_without_ampm
62
+ # end
63
+ #
64
+ # if @options[:use_hidden] || @options[:discard_hour]
65
+ # build_hidden(:hour, hour12)
66
+ # else
67
+ # build_options_and_select(:hour, hour12, :start => 1, :end => 12)
68
+ # end
69
+ # end
70
+ #
71
+ # alias_method_chain :select_hour, :ampm
72
+ #
73
+ # def select_ampm
74
+ # selected = hour < 12 ? AM : PM
75
+ #
76
+ # # XXX i18n?
77
+ # label = { AM => 'AM', PM => 'PM' }
78
+ # ampm_options = []
79
+ # [AM, PM].each do |meridiem|
80
+ # option = { :value => meridiem }
81
+ # option[:selected] = "selected" if selected == meridiem
82
+ # ampm_options << content_tag(:option, label[meridiem], option) + "\n"
83
+ # end
84
+ # build_select(:ampm, ampm_options.join)
85
+ # end
86
+ #
87
+ # private
88
+ #
89
+ # def build_selects_from_types_with_ampm(order)
90
+ # order += [:ampm] if @options[:twelve_hour] and !order.include?(:ampm)
91
+ # build_selects_from_types_without_ampm(order)
92
+ # end
93
+ #
94
+ # alias_method_chain :build_selects_from_types, :ampm
95
+ #
96
+ # def hour12
97
+ # h12 = hour % 12
98
+ # h12 = 12 if h12 == 0
99
+ # return h12
100
+ # end
101
+ # end
102
+ # end
@@ -0,0 +1,407 @@
1
+ require File.join(File.dirname(__FILE__), '12_hour_time')
2
+
3
+ module UnobtrusiveDatePicker
4
+
5
+ DATEPICKER_DEFAULT_NAME_ID_SUFFIXES = { :year => {:id => '', :name => 'year'},
6
+ :month => {:id => 'mm', :name => 'month'},
7
+ :day => {:id => 'dd', :name => 'day'} }
8
+
9
+ DATEPICKER_DAYS_OF_WEEK = { :Monday => '0',
10
+ :Tuesday => '1',
11
+ :Wednesday => '2',
12
+ :Thursday => '3',
13
+ :Friday => '4',
14
+ :Saturday => '5',
15
+ :Sunday => '6'}
16
+
17
+ DATEPICKER_DIVIDERS = { 'slash' => '/',
18
+ 'dash' => '-',
19
+ 'dot' => '.',
20
+ 'space' => ' ' }
21
+
22
+ RANGE_DATE_FORMAT = '%Y-%m-%d'
23
+
24
+ # == Unobtrusive Date-Picker Helper
25
+ #
26
+ # This Module helps to create date and date-time fields that use the
27
+ # Unobtrusive Date-Picker Javascript Widget.
28
+ #
29
+ # They also use the 12-hour AM/PM time format.
30
+ #
31
+ module UnobtrusiveDatePickerHelper
32
+
33
+ ##
34
+ # Creates the date picker with the calendar widget.
35
+ #
36
+ def unobtrusive_date_picker(object_name, method, options = {}, html_options = {})
37
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, options.delete(:object)).to_datepicker_date_select_tag(options, html_options)
38
+ end
39
+
40
+ ##
41
+ # Creates the date-time picker with the calendar widget, and AM/PM select.
42
+ #
43
+ def unobtrusive_datetime_picker(object_name, method, options = {}, html_options = {})
44
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, options.delete(:object)).to_datepicker_datetime_select_tag(options, html_options)
45
+ end
46
+
47
+ ##
48
+ # Creates the date picker with the calendar widget.
49
+ #
50
+ def unobtrusive_date_text_picker(object_name, method, options = {}, html_options = {})
51
+ ActionView::Helpers::InstanceTag.new(object_name, method, self, options.delete(:object)).to_datepicker_text_tag(options, html_options)
52
+ end
53
+
54
+ def unobtrusive_datetime_picker_tags(datetime = Time.current, options = {}, html_options = {})
55
+ datetime ||= Time.current
56
+ DateTimePickerSelector.new(datetime, options.merge(:twelve_hour => true), html_options).select_datetime
57
+ end
58
+
59
+ def unobtrusive_date_picker_tags(date = Date.current, options = {}, html_options = {})
60
+ date ||= Date.current
61
+ DateTimePickerSelector.new(date, options, html_options).select_date
62
+ end
63
+
64
+ ##
65
+ # Creates the text field based date picker with the calendar widget without a model object.
66
+ #
67
+ def unobtrusive_date_text_picker_tag(name, date = Date.current, options = {}, html_options = {})
68
+ date ||= Date.current
69
+ options = merge_defaults_for_text_picker(options)
70
+ DateTimePickerSelector.new(date, options, html_options).text_date_picker(name)
71
+ end
72
+
73
+ private
74
+ def merge_defaults_for_text_picker(options)
75
+ defaults = {:format => 'm-d-y', :divider => 'slash'}
76
+ options = defaults.merge(options)
77
+ end
78
+
79
+ end
80
+
81
+ module AssetTagHelper
82
+ ##
83
+ # This will add the necessary <link> and <script> tags to include the necessary stylesheet and
84
+ # javascripts.
85
+ #
86
+ def unobtrusive_datepicker_includes(options = {})
87
+ tags = []
88
+ tags << javascript_include_tag('datepicker', options)
89
+ tags << stylesheet_link_tag('datepicker', options)
90
+ tags * "\n"
91
+ end
92
+ end
93
+
94
+ module OptionParser
95
+ protected
96
+ def parse_divider_option(option)
97
+ if DATEPICKER_DIVIDERS.keys.include?(option)
98
+ option
99
+ else
100
+ DATEPICKER_DIVIDERS.find {|name, value| option == value}.first
101
+ end
102
+ end
103
+
104
+ def format_date_value_for_text_field(value, format, divider_option)
105
+ divider = DATEPICKER_DIVIDERS[parse_divider_option(divider_option)]
106
+ format_string = format.downcase.gsub(/(m|d)/, '%\1').gsub(/y/, '%Y').gsub('-', divider)
107
+ value.nil? ? '' : value.strftime(format_string)
108
+ end
109
+
110
+ def get_html_classes_for_datepicker(options, html_options_class, extra_class = nil)
111
+ html_classes = make_date_picker_class_options(options)
112
+ html_classes << extra_class if extra_class
113
+ html_options_class.blank? ?
114
+ html_classes.join(' ') : "#{html_options_class} #{html_classes.join(' ')}"
115
+ end
116
+
117
+ def make_date_picker_class_options(options)
118
+ html_classes = []
119
+
120
+ if options[:highlight_days]
121
+ highlight_days = parse_days_of_week(options[:highlight_days])
122
+ if !highlight_days.blank?
123
+ html_classes << "highlight-days-#{highlight_days}"
124
+ end
125
+ end
126
+
127
+ if options[:range_low]
128
+ range_low = parse_range_option(options[:range_low], 'low')
129
+ if !range_low.blank?
130
+ html_classes << range_low
131
+ end
132
+ end
133
+
134
+ if options[:range_high]
135
+ range_high = parse_range_option(options[:range_high], 'high')
136
+ if !range_high.blank?
137
+ html_classes << range_high
138
+ end
139
+ end
140
+
141
+ if options[:disable_days]
142
+ disable_days = parse_days_of_week(options[:disable_days])
143
+ if !disable_days.blank?
144
+ html_classes << "disable-days-#{disable_days}"
145
+ end
146
+ end
147
+
148
+ if options[:no_transparency]
149
+ html_classes << 'no-transparency'
150
+ end
151
+
152
+ if options[:format] && %W(d-m-y m-d-y y-m-d).include?(options[:format].downcase)
153
+ html_classes << "format-#{options[:format].downcase}"
154
+ end
155
+
156
+ if options[:divider]
157
+ html_classes << "divider-#{parse_divider_option(options[:divider])}"
158
+ end
159
+
160
+ html_classes
161
+ end
162
+
163
+ def parse_days_of_week(option)
164
+ if option.is_a? String
165
+ option
166
+ elsif option.is_a? Symbol
167
+ DATEPICKER_DAYS_OF_WEEK[option]
168
+ elsif option.is_a? Array
169
+ days = ''
170
+ option.each do |day|
171
+ days << DATEPICKER_DAYS_OF_WEEK[day]
172
+ end
173
+ days
174
+ end
175
+ end
176
+
177
+ def parse_range_option(option, direction)
178
+ if option.is_a? Symbol
179
+ case option
180
+ when :today
181
+ range_class = 'today'
182
+ when :tomorrow
183
+ range_class = Date.tomorrow.strftime(RANGE_DATE_FORMAT)
184
+ when :yesterday
185
+ range_class = Date.yesterday.strftime(RANGE_DATE_FORMAT)
186
+ end
187
+ elsif option.is_a? String
188
+ if !option.blank?
189
+ range_class = Date.parse(option).strftime(RANGE_DATE_FORMAT)
190
+ else
191
+ range_class = nil
192
+ end
193
+ elsif (option.is_a?(Date) || option.is_a?(DateTime) || option.is_a?(Time))
194
+ range_class = option.strftime(RANGE_DATE_FORMAT)
195
+ else
196
+ range_class = nil
197
+ end
198
+
199
+ if !range_class.blank?
200
+ range_class = 'range-' + direction + '-' + range_class
201
+ else
202
+ nil
203
+ end
204
+ end
205
+ end
206
+
207
+ class DateTimePickerSelector < ActionView::Helpers::DateTimeSelector
208
+ include ActionView::Helpers::FormTagHelper
209
+ include OptionParser
210
+
211
+ POSITION = {
212
+ :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5,
213
+ :second => 6, :ampm => 7
214
+ }
215
+ # XXX would like to do this, but it's frozen
216
+ # POSITION[:ampm] = 7
217
+
218
+ # We give them negative values so can differentiate between normal
219
+ # date/time values. The way the multi param stuff works, from what I
220
+ # can see, results in a variable number of fields (if you tell it to
221
+ # include seconds, for example). So we expect the AM/PM field, if
222
+ # present, to be last and have a negative value.
223
+ AM = -1
224
+ PM = -2
225
+
226
+ def text_date_picker(name)
227
+ value = format_date_value_for_text_field(@datetime, @options[:format], @options[:divider])
228
+ @html_options[:class] = get_html_classes_for_datepicker(@options, @html_options[:class])
229
+ text_field_tag(name, value, @html_options)
230
+ end
231
+
232
+ def select_hour_with_ampm
233
+ unless @options[:twelve_hour]
234
+ return select_hour_without_ampm
235
+ end
236
+
237
+ if @options[:use_hidden] || @options[:discard_hour]
238
+ build_hidden(:hour, hour12)
239
+ else
240
+ build_options_and_select(:hour, hour12, :start => 1, :end => 12)
241
+ end
242
+ end
243
+
244
+ alias_method_chain :select_hour, :ampm
245
+
246
+ def select_ampm
247
+ selected = hour < 12 ? AM : PM
248
+
249
+ # XXX i18n?
250
+ label = { AM => 'AM', PM => 'PM' }
251
+ ampm_options = []
252
+ [AM, PM].each do |meridiem|
253
+ option = { :value => meridiem }
254
+ option[:selected] = "selected" if selected == meridiem
255
+ ampm_options << content_tag(:option, label[meridiem], option) + "\n"
256
+ end
257
+ build_select(:ampm, ampm_options.join)
258
+ end
259
+
260
+ private
261
+ def build_selects_from_types_with_ampm(order)
262
+ order += [:ampm] if @options[:twelve_hour] and !order.include?(:ampm)
263
+ build_selects_from_types_without_ampm(order)
264
+ end
265
+
266
+ alias_method_chain :build_selects_from_types, :ampm
267
+
268
+ def hour12
269
+ h12 = hour % 12
270
+ h12 = 12 if h12 == 0
271
+ return h12
272
+ end
273
+
274
+ def build_select(type, select_options_as_html)
275
+ select_options = @html_options.merge(
276
+ :id => input_id_from_type(type, @html_options[:id]),
277
+ :name => input_name_from_type(type)
278
+ )
279
+ select_options.merge!(:disabled => 'disabled') if @options[:disabled]
280
+
281
+ if type.to_sym == :year
282
+ select_options[:class] = get_html_classes_for_datepicker(@options, select_options[:class], 'split-date')
283
+ end
284
+
285
+ select_html = "\n"
286
+ select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
287
+ select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
288
+ select_html << select_options_as_html.to_s
289
+
290
+ content_tag(:select, select_html, select_options) + "\n"
291
+ end
292
+
293
+ def build_hidden(type, value)
294
+ hidden_html_options = {
295
+ :type => "hidden",
296
+ :id => input_id_from_type(type, @html_options[:id]),
297
+ :name => input_name_from_type(type),
298
+ :value => value
299
+ }
300
+
301
+ if type.to_sym == :year
302
+ hidden_html_options[:class] = get_html_classes_for_datepicker(@options, hidden_html_options[:class], 'split-date')
303
+ end
304
+
305
+ tag(:input, hidden_html_options) + "\n"
306
+ end
307
+
308
+ def input_id_from_type(type, html_options_id = nil)
309
+ if html_options_id.blank?
310
+ prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
311
+ prefix += "_#{@options[:index]}" if @options.has_key?(:index)
312
+ prefix += "_#{@options[:field_name]}" if @options.has_key?(:field_name)
313
+ else
314
+ prefix = html_options_id
315
+ end
316
+ case type.to_sym
317
+ when :year
318
+ prefix
319
+ when :month
320
+ prefix + '-mm'
321
+ when :day
322
+ prefix + '-dd'
323
+ else
324
+ super(type)
325
+ end
326
+ end
327
+
328
+ end
329
+
330
+ end
331
+ # /UnobtrusiveDatePicker
332
+
333
+ module ActionView # :nodoc: all
334
+ module Helpers
335
+ class InstanceTag
336
+ include UnobtrusiveDatePicker::UnobtrusiveDatePickerHelper
337
+ include UnobtrusiveDatePicker::OptionParser
338
+
339
+ def to_datepicker_date_select_tag(options = {}, html_options = {})
340
+ datepicker_selector(options, html_options).select_date
341
+ end
342
+
343
+ def to_datepicker_datetime_select_tag(options = {}, html_options = {})
344
+ datepicker_selector(options.merge(:twelve_hour => true), html_options).select_datetime
345
+ end
346
+
347
+ def to_datepicker_text_tag(options = {}, html_options = {})
348
+ options = merge_defaults_for_text_picker(options)
349
+ html_options[:class] = get_html_classes_for_datepicker(options, html_options[:class])
350
+ html_options[:value] = format_date_value_for_text_field(value(object), options[:format], options[:divider])
351
+ to_input_field_tag('text', html_options)
352
+ end
353
+
354
+ private
355
+ def datepicker_selector(options, html_options)
356
+ datetime = value(object) || default_datetime(options)
357
+
358
+ options = options.dup
359
+ options[:field_name] = @method_name
360
+ options[:include_position] = true
361
+ options[:prefix] ||= @object_name
362
+ options[:index] = @auto_index if @auto_index && !options.has_key?(:index)
363
+ options[:datetime_separator] ||= ' &mdash; '
364
+ options[:time_separator] ||= ' : '
365
+
366
+ UnobtrusiveDatePicker::DateTimePickerSelector.new(datetime, options.merge(:tag => true), html_options)
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ module ActionView::Helpers::PrototypeHelper
373
+ class JavaScriptGenerator
374
+ module GeneratorMethods
375
+ def unobtrusive_date_picker_create(id = nil)
376
+ if id
377
+ call "datePickerController.create", "$(#{id})"
378
+ else
379
+ record "datePickerController.create"
380
+ end
381
+ end
382
+
383
+ def unobtrusive_date_picker_cleanup(id = nil)
384
+ record "datePickerController.cleanUp"
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+
391
+ module ActionView # :nodoc: all
392
+ module Helpers
393
+ class FormBuilder
394
+ def unobtrusive_date_picker(method, options = {}, html_options = {})
395
+ @template.unobtrusive_date_picker(@object_name, method, objectify_options(options), html_options)
396
+ end
397
+
398
+ def unobtrusive_date_text_picker(method, options = {}, html_options = {})
399
+ @template.unobtrusive_date_text_picker(@object_name, method, objectify_options(options), html_options)
400
+ end
401
+
402
+ def unobtrusive_datetime_picker(method, options = {}, html_options = {})
403
+ @template.unobtrusive_datetime_picker(@object_name, method, objectify_options(options), html_options)
404
+ end
405
+ end
406
+ end
407
+ end