rd_unobtrusive_date_picker 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +19 -0
- data/Manifest +45 -0
- data/README.rdoc +165 -0
- data/Rakefile +29 -0
- data/about.yml +7 -0
- data/init.rb +8 -0
- data/install.rb +14 -0
- data/lib/12_hour_time.rb +102 -0
- data/lib/unobtrusive_date_picker.rb +407 -0
- data/public/images/backstripes.gif +0 -0
- data/public/images/bg_header.jpg +0 -0
- data/public/images/bullet1.gif +0 -0
- data/public/images/bullet2.gif +0 -0
- data/public/images/cal.gif +0 -0
- data/public/images/gradient-e5e5e5-ffffff.gif +0 -0
- data/public/javascripts/datepicker.js +1445 -0
- data/public/javascripts/lang/af.js +40 -0
- data/public/javascripts/lang/ar.js +50 -0
- data/public/javascripts/lang/de.js +40 -0
- data/public/javascripts/lang/du.js +40 -0
- data/public/javascripts/lang/en.js +42 -0
- data/public/javascripts/lang/es.js +41 -0
- data/public/javascripts/lang/fi.js +40 -0
- data/public/javascripts/lang/fr.js +44 -0
- data/public/javascripts/lang/gr.js +40 -0
- data/public/javascripts/lang/he.js +49 -0
- data/public/javascripts/lang/it.js +13 -0
- data/public/javascripts/lang/nl.js +40 -0
- data/public/javascripts/lang/no.js +40 -0
- data/public/javascripts/lang/pt.js +50 -0
- data/public/javascripts/lang/ro.js +40 -0
- data/public/javascripts/lang/ru.js +40 -0
- data/public/javascripts/lang/sp.js +40 -0
- data/public/javascripts/lang/sv.js +41 -0
- data/public/javascripts/lang/ua.js +40 -0
- data/public/stylesheets/datepicker.css +263 -0
- data/spec/date_picker_tag_spec.rb +122 -0
- data/spec/date_picker_text_field_spec.rb +54 -0
- data/spec/datepicker_html_class_options_spec.rb +281 -0
- data/spec/spec.opts +12 -0
- data/spec/spec_helper.rb +52 -0
- data/spec/tag_matcher.rb +142 -0
- data/spec/unobtrusive_date_picker_spec.rb +129 -0
- data/tasks/datepicker_tasks.rake +17 -0
- data/uninstall.rb +12 -0
- data/unobtrusive_date_picker.gemspec +30 -0
- metadata +116 -0
data/MIT-LICENSE
ADDED
@@ -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.
|
data/Manifest
ADDED
@@ -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
|
data/README.rdoc
ADDED
@@ -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
|
+
|
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
|
+
|
data/Rakefile
ADDED
@@ -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
|
data/about.yml
ADDED
@@ -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
|
data/install.rb
ADDED
@@ -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)
|
data/lib/12_hour_time.rb
ADDED
@@ -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] ||= ' — '
|
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
|