tristandunn-calendar_date_select 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +240 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +42 -0
  5. data/README.txt +18 -0
  6. data/Rakefile +35 -0
  7. data/VERSION +1 -0
  8. data/calendar_date_select.gemspec +96 -0
  9. data/init.rb +1 -0
  10. data/js_test/functional/.tmp_cds_test.html +306 -0
  11. data/js_test/functional/cds_test.html +349 -0
  12. data/js_test/functional/format_iso_date_test.html +52 -0
  13. data/js_test/prototype.js +4184 -0
  14. data/js_test/test.css +40 -0
  15. data/js_test/unit/cds_helper_methods.html +46 -0
  16. data/js_test/unittest.js +564 -0
  17. data/lib/calendar_date_select/calendar_date_select.rb +121 -0
  18. data/lib/calendar_date_select/form_helpers.rb +229 -0
  19. data/lib/calendar_date_select/includes_helper.rb +29 -0
  20. data/lib/calendar_date_select.rb +33 -0
  21. data/public/blank_iframe.html +2 -0
  22. data/public/images/calendar_date_select/calendar.gif +0 -0
  23. data/public/javascripts/calendar_date_select/calendar_date_select.js +443 -0
  24. data/public/javascripts/calendar_date_select/format_american.js +35 -0
  25. data/public/javascripts/calendar_date_select/format_danish.js +31 -0
  26. data/public/javascripts/calendar_date_select/format_db.js +27 -0
  27. data/public/javascripts/calendar_date_select/format_euro_24hr.js +7 -0
  28. data/public/javascripts/calendar_date_select/format_euro_24hr_ymd.js +7 -0
  29. data/public/javascripts/calendar_date_select/format_finnish.js +32 -0
  30. data/public/javascripts/calendar_date_select/format_hyphen_ampm.js +37 -0
  31. data/public/javascripts/calendar_date_select/format_iso_date.js +29 -0
  32. data/public/javascripts/calendar_date_select/format_italian.js +24 -0
  33. data/public/javascripts/calendar_date_select/locale/ar.js +10 -0
  34. data/public/javascripts/calendar_date_select/locale/da.js +11 -0
  35. data/public/javascripts/calendar_date_select/locale/de.js +11 -0
  36. data/public/javascripts/calendar_date_select/locale/es.js +11 -0
  37. data/public/javascripts/calendar_date_select/locale/fi.js +10 -0
  38. data/public/javascripts/calendar_date_select/locale/fr.js +11 -0
  39. data/public/javascripts/calendar_date_select/locale/it.js +9 -0
  40. data/public/javascripts/calendar_date_select/locale/nl.js +11 -0
  41. data/public/javascripts/calendar_date_select/locale/pl.js +11 -0
  42. data/public/javascripts/calendar_date_select/locale/pt.js +11 -0
  43. data/public/javascripts/calendar_date_select/locale/ru.js +10 -0
  44. data/public/javascripts/calendar_date_select/locale/sl.js +11 -0
  45. data/public/stylesheets/calendar_date_select/blue.css +130 -0
  46. data/public/stylesheets/calendar_date_select/default.css +135 -0
  47. data/public/stylesheets/calendar_date_select/green.css +142 -0
  48. data/public/stylesheets/calendar_date_select/plain.css +128 -0
  49. data/public/stylesheets/calendar_date_select/red.css +135 -0
  50. data/public/stylesheets/calendar_date_select/silver.css +133 -0
  51. data/spec/calendar_date_select/calendar_date_select_spec.rb +14 -0
  52. data/spec/calendar_date_select/form_helpers_spec.rb +203 -0
  53. data/spec/calendar_date_select/includes_helper_spec.rb +46 -0
  54. data/spec/spec_helper.rb +26 -0
  55. metadata +113 -0
@@ -0,0 +1,121 @@
1
+ module CalendarDateSelect
2
+ VERSION = '1.15'
3
+ FORMATS = {
4
+ :natural => {
5
+ :date => "%B %d, %Y",
6
+ :time => " %I:%M %p"
7
+ },
8
+ :hyphen_ampm => {
9
+ :date => "%Y-%m-%d",
10
+ :time => " %I:%M %p",
11
+ :javascript_include => "format_hyphen_ampm"
12
+ },
13
+ :iso_date => {
14
+ :date => "%Y-%m-%d",
15
+ :time => " %H:%M",
16
+ :javascript_include => "format_iso_date"
17
+ },
18
+ :finnish => {
19
+ :date => "%d.%m.%Y",
20
+ :time => " %H:%M",
21
+ :javascript_include => "format_finnish"
22
+ },
23
+ :danish => {
24
+ :date => "%d/%m/%Y",
25
+ :time => " %H:%M",
26
+ :javascript_include => "format_danish"
27
+ },
28
+ :american => {
29
+ :date => "%m/%d/%Y",
30
+ :time => " %I:%M %p",
31
+ :javascript_include => "format_american"
32
+ },
33
+ :euro_24hr => {
34
+ :date => "%d %B %Y",
35
+ :time => " %H:%M",
36
+ :javascript_include => "format_euro_24hr"
37
+ },
38
+ :euro_24hr_ymd => {
39
+ :date => "%Y.%m.%d",
40
+ :time => " %H:%M",
41
+ :javascript_include => "format_euro_24hr_ymd"
42
+ },
43
+ :italian => {
44
+ :date => "%d/%m/%Y",
45
+ :time => " %H:%M",
46
+ :javascript_include => "format_italian"
47
+ },
48
+ :db => {
49
+ :date => "%Y-%m-%d",
50
+ :time => " %H:%M",
51
+ :javascript_include => "format_db"
52
+ }
53
+ }
54
+
55
+ # Returns the default_options hash. These options are by default provided to every calendar_date_select control, unless otherwise overrided.
56
+ #
57
+ # Example:
58
+ # # At the bottom of config/environment.rb:
59
+ # CalendarDateSelect.default_options.update(
60
+ # :popup => "force",
61
+ # :month_year => "label",
62
+ # :image => "custom_calendar_picker.png"
63
+ # )
64
+ def self.default_options
65
+ @calendar_date_select_default_options ||= { :image => "calendar_date_select/calendar.gif" }
66
+ end
67
+
68
+ # Set the picker image. Provide the image url the same way you would provide it to image_tag
69
+ def self.image=(value)
70
+ default_options[:image] = value
71
+ end
72
+
73
+ # Returns the options for the given format
74
+ #
75
+ # Example:
76
+ # CalendarDateSelect.format = :italian
77
+ # puts CalendarDateSelect.format[:date]
78
+ # => "%d/%m/%Y"
79
+ def self.format
80
+ @calendar_date_select_format ||= FORMATS[:natural]
81
+ end
82
+
83
+ # Set the format. To see a list of available formats, CalendarDateSelect::FORMATS.keys, or open lib/calendar_date_select/calendar_date_select.rb
84
+ #
85
+ # (e.g. CalendarDateSelect.format = :italian)
86
+ def self.format=(format)
87
+ raise "CalendarDateSelect: Unrecognized format specification: #{format}" unless FORMATS.has_key?(format)
88
+ @calendar_date_select_format = FORMATS[format]
89
+ end
90
+
91
+ def self.date_format_string(time = false)
92
+ format[:date] + (time ? format[:time] : "")
93
+ end
94
+
95
+ def self.format_date(date)
96
+ if date.is_a?(Date)
97
+ date.strftime(date_format_string(false))
98
+ else
99
+ date.strftime(date_format_string(true))
100
+ end
101
+ end
102
+
103
+ def self.format_time(value, options = {})
104
+ return value unless value.respond_to?("strftime")
105
+ if options[:time]
106
+ format_date(value)
107
+ else
108
+ format_date(value.to_date)
109
+ end
110
+ end
111
+
112
+ # Detects the presence of time in a date, string
113
+ def self.has_time?(value)
114
+ case value
115
+ when DateTime, Time then true
116
+ when Date then false
117
+ else
118
+ /[0-9]:[0-9]{2}/.match(value.to_s) ? true : false
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,229 @@
1
+ # Various helpers available for use in your view
2
+ module CalendarDateSelect::FormHelpers
3
+
4
+ # Similar to text_field_tag, but adds a calendar picker, naturally.
5
+ #
6
+ # == Arguments
7
+ #
8
+ # +name+ - the html name of the tag
9
+ # +value+ - When specified as a string, uses value verbatim. When Date, DateTime, Time, it converts it to a string basd off the format set by CalendarDateSelect#format=
10
+ # +options+ - ...
11
+ #
12
+ # == Options
13
+ #
14
+ # === :embedded
15
+ #
16
+ # Put the calendar straight into the form, rather than using a popup type of form.
17
+ #
18
+ # <%= calendar_date_select_tag "name", "2007-01-01", :embedded => true %>
19
+ #
20
+ # === :hidden
21
+ #
22
+ # Use a hidden element instead of a text box for a pop up calendar. Not compatible with :embedded => true. You'll probably want to use an onchange callback to do something with the value.
23
+ #
24
+ # <span id='cds_value' />
25
+ # <%= calendar_date_select_tag "hidden_date_selector", "", :hidden => "true", :onchange => "$('cds_value').update($F(this));" %>
26
+ #
27
+ # === :image
28
+ #
29
+ # Specify an alternative icon to use for the date picker.
30
+ #
31
+ # To use /images/groovy.png:
32
+ #
33
+ # <%= calendar_date_select_tag "altered_image", "", :image => "groovy.png" %>
34
+ #
35
+ # === :minute_interval
36
+ #
37
+ # Specifies the minute interval used in the hour/minute selector. Default is 5.
38
+ #
39
+ # <%= calendar_date_select_tag "month_year_selector_label", "", :minute_interval => 15 %>
40
+ #
41
+ # === :month_year
42
+ #
43
+ # Customize the month and year selectors at the top of the control.
44
+ #
45
+ # Valid values:
46
+ # * "dropdowns" (default) - Use a separate dropdown control for both the month and year
47
+ # * "label" - Use static text to show the month and the year.
48
+ #
49
+ # <%= calendar_date_select_tag "month_year_selector_label", "", :month_year => "label" %>
50
+ #
51
+ # === :popup => 'force'
52
+ #
53
+ # Forces the user to use the popup calendar by making it's text-box read-only and causing calendar_date_select to override it's default behavior of not allowing selection of a date on a target element that is read-only.
54
+ #
55
+ # <%= calendar_date_select_tag "name", "2007-01-01", :popup => "force" %>
56
+ #
57
+ # === :time
58
+ #
59
+ # Show time in the controls. There's three options:
60
+ #
61
+ # * +true+ - show an hour/minute selector.
62
+ # * +false+ - don't show an hour/minute selector.
63
+ # * +"mixed"+ - Show an hour/minute selector, but include a "all day" option - allowing them to choose whether or not to specify a time.
64
+ #
65
+ # === :year_range
66
+ #
67
+ # Limit the year range. You can pass in an array or range of ruby Date/Time objects or FixNum's.
68
+ #
69
+ # <%= calendar_date_select_tag "e_date", nil, :year_range => 10.years.ago..0.years.from_now %>
70
+ # <%= calendar_date_select_tag "e_date", nil, :year_range => [0.years.ago, 10.years.from_now] %>
71
+ # <%= calendar_date_select_tag "e_date", nil, :year_range => 2000..2007 %>
72
+ # <%= calendar_date_select_tag "e_date", nil, :year_range => [2000, 2007] %>
73
+ #
74
+ # == CALLBACKS
75
+ #
76
+ # The following callbacks are available:
77
+ #
78
+ # * before_show / after_show
79
+ # * before_close / after_close
80
+ # * after_navigate - Called when navigating to a different month. Passes first parameter as a date object refering to the current month viewed
81
+ # * onchange - Called when the form input value changes
82
+ #
83
+ # <%= calendar_date_select_tag "event_demo", "",
84
+ # :before_show => "log('Calendar Showing');" ,
85
+ # :after_show => "log('Calendar Shown');" ,
86
+ # :before_close => "log('Calendar closing');" ,
87
+ # :after_close => "log('Calendar closed');",
88
+ # :after_navigate => "log('Current month is ' + (param.getMonth()+1) + '/' + (param.getFullYear()));",
89
+ # :onchange => "log('value changed to - ' + $F(this));"
90
+ #
91
+ # }}}
92
+ #
93
+ # All callbacks are executed within the context of the target input element. If you'd like to access the CalendarDateSelect object itself, you can access it via "this.calendar_date_select".
94
+ #
95
+ # For example:
96
+ #
97
+ # <%= calendar_date_select_tag "event_demo", "", :after_navigate => "alert('The current selected month is ' + this.calendar_date_select.selected_date.getMonth());" ,
98
+ def calendar_date_select_tag( name, value = nil, options = {})
99
+ image, options, javascript_options = calendar_date_select_process_options(options)
100
+ value = CalendarDateSelect.format_time(value, javascript_options)
101
+
102
+ javascript_options.delete(:format)
103
+
104
+ options[:id] ||= name
105
+ tag = javascript_options[:hidden] || javascript_options[:embedded] ?
106
+ hidden_field_tag(name, value, options) :
107
+ text_field_tag(name, value, options)
108
+
109
+ calendar_date_select_output(tag, image, options, javascript_options)
110
+ end
111
+
112
+ # Similar to the difference between +text_field_tag+ and +text_field+, this method behaves like +text_field+
113
+ #
114
+ # It receives the same options as +calendar_date_select_tag+. Need for time selection is automatically detected by checking the corresponding column meta information of Model#columns_hash
115
+ def calendar_date_select(object, method, options={})
116
+ obj = options[:object] || instance_variable_get("@#{object}")
117
+
118
+ if !options.include?(:time) && obj.class.respond_to?("columns_hash")
119
+ column_type = obj.class.columns_hash[method.to_s].type if obj.class.columns_hash.include?(method.to_s)
120
+ options[:time] = true if column_type == :datetime
121
+ end
122
+
123
+ use_time = options[:time]
124
+
125
+ if options[:time].to_s=="mixed"
126
+ use_time = false if Date===(obj.respond_to?(method) && obj.send(method))
127
+ end
128
+
129
+ image, options, javascript_options = calendar_date_select_process_options(options)
130
+
131
+ options[:value] ||=
132
+ if(obj.respond_to?(method) && obj.send(method).respond_to?(:strftime))
133
+ obj.send(method).strftime(CalendarDateSelect.date_format_string(use_time))
134
+ elsif obj.respond_to?("#{method}_before_type_cast")
135
+ obj.send("#{method}_before_type_cast")
136
+ elsif obj.respond_to?(method)
137
+ obj.send(method).to_s
138
+ else
139
+ begin
140
+ obj.send(method).strftime(CalendarDateSelect.date_format_string(use_time))
141
+ rescue
142
+ nil
143
+ end
144
+ end
145
+
146
+ tag = ActionView::Helpers::InstanceTag.new_with_backwards_compatibility(object, method, self, options.delete(:object))
147
+ calendar_date_select_output(
148
+ tag.to_input_field_tag( (javascript_options[:hidden] || javascript_options[:embedded]) ? "hidden" : "text", options),
149
+ image,
150
+ options,
151
+ javascript_options
152
+ )
153
+ end
154
+
155
+ private
156
+ # extracts any options passed into calendar date select, appropriating them to either the Javascript call or the html tag.
157
+ def calendar_date_select_process_options(options)
158
+ options, javascript_options = CalendarDateSelect.default_options.merge(options), {}
159
+ image = options.delete(:image)
160
+ callbacks = [:before_show, :before_close, :after_show, :after_close, :after_navigate]
161
+ for key in [:time, :valid_date_check, :embedded, :buttons, :clear_button, :format, :year_range, :month_year, :popup, :hidden, :minute_interval] + callbacks
162
+ javascript_options[key] = options.delete(key) if options.has_key?(key)
163
+ end
164
+
165
+ # if passing in mixed, pad it with single quotes
166
+ javascript_options[:time] = "'mixed'" if javascript_options[:time].to_s=="mixed"
167
+ javascript_options[:month_year] = "'#{javascript_options[:month_year]}'" if javascript_options[:month_year]
168
+
169
+ # if we are forcing the popup, automatically set the readonly property on the input control.
170
+ if javascript_options[:popup].to_s == "force"
171
+ javascript_options[:popup] = "'force'"
172
+ options[:readonly] = true
173
+ end
174
+
175
+ if (vdc=javascript_options.delete(:valid_date_check))
176
+ if vdc.include?(";") || vdc.include?("function")
177
+ raise ArgumentError, ":valid_date_check function is missing a 'return' statement. Try something like: :valid_date_check => 'if (date > new(Date)) return true; else return false;'" unless vdc.include?("return");
178
+ end
179
+
180
+ vdc = "return(#{vdc})" unless vdc.include?("return")
181
+ vdc = "function(date) { #{vdc} }" unless vdc.include?("function")
182
+ javascript_options[:valid_date_check] = vdc
183
+ end
184
+
185
+ javascript_options[:popup_by] ||= "this" if javascript_options[:hidden]
186
+
187
+ # surround any callbacks with a function, if not already done so
188
+ for key in callbacks
189
+ javascript_options[key] = "function(param) { #{javascript_options[key]} }" unless javascript_options[key].include?("function") if javascript_options[key]
190
+ end
191
+
192
+ javascript_options[:year_range] = format_year_range(javascript_options[:year_range] || 10)
193
+ [image, options, javascript_options]
194
+ end
195
+
196
+ def calendar_date_select_output(input, image, options = {}, javascript_options = {})
197
+ out = input
198
+ if javascript_options[:embedded]
199
+ uniq_id = "cds_placeholder_#{(rand*100000).to_i}"
200
+ # we need to be able to locate the target input element, so lets stick an invisible span tag here we can easily locate
201
+ out << content_tag(:span, nil, :style => "display: none; position: absolute;", :id => uniq_id)
202
+ out << javascript_tag("new CalendarDateSelect( $('#{uniq_id}').previous('input'), #{options_for_javascript(javascript_options)} ); ")
203
+ else
204
+ out << " "
205
+ out << image_tag(image,
206
+ :onclick => "new CalendarDateSelect( $(this).previous('input'), #{options_for_javascript(javascript_options)} );",
207
+ :style => 'border:0px; cursor:pointer;',
208
+ :class=>'calendar_date_select_popup_icon')
209
+ end
210
+ out
211
+ end
212
+
213
+ def format_year_range(year) # nodoc
214
+ return year unless year.respond_to?(:first)
215
+ return "[#{year.first}, #{year.last}]" unless year.first.respond_to?(:strftime)
216
+ return "[#{year.first.year}, #{year.last.year}]"
217
+ end
218
+ end
219
+
220
+ # Helper method for form builders
221
+ module ActionView
222
+ module Helpers
223
+ class FormBuilder
224
+ def calendar_date_select(method, options = {})
225
+ @template.calendar_date_select(@object_name, method, options.merge(:object => @object))
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,29 @@
1
+ module CalendarDateSelect::IncludesHelper
2
+ # returns the selected calendar_date_select stylesheet (not an array)
3
+ def calendar_date_select_stylesheets(options = {})
4
+ options.assert_valid_keys(:style)
5
+ "calendar_date_select/#{options[:style] || "default"}"
6
+ end
7
+
8
+ # returns an array of javascripts needed for the selected locale, date_format, and calendar control itself.
9
+ def calendar_date_select_javascripts(options = {})
10
+ options.assert_valid_keys(:locale)
11
+ files = ["calendar_date_select/calendar_date_select"]
12
+ files << "calendar_date_select/locale/#{options[:locale]}" if options[:locale]
13
+ files << "calendar_date_select/#{CalendarDateSelect.format[:javascript_include]}" if CalendarDateSelect.format[:javascript_include]
14
+ files
15
+ end
16
+
17
+ # returns html necessary to load javascript and css to make calendar_date_select work
18
+ def calendar_date_select_includes(*args)
19
+ return "" if @cds_already_included
20
+ @cds_already_included=true
21
+
22
+ options = (Hash === args.last) ? args.pop : {}
23
+ options.assert_valid_keys(:style, :locale)
24
+ options[:style] ||= args.shift
25
+
26
+ javascript_include_tag(*calendar_date_select_javascripts(:locale => options[:locale])) + "\n" +
27
+ stylesheet_link_tag(*calendar_date_select_stylesheets(:style => options[:style])) + "\n"
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ require "calendar_date_select/calendar_date_select.rb"
2
+ require "calendar_date_select/form_helpers.rb"
3
+ require "calendar_date_select/includes_helper.rb"
4
+
5
+ if Object.const_defined?(:Rails) && File.directory?(Rails.public_path.to_s)
6
+ ActionView::Helpers::FormHelper.send(:include, CalendarDateSelect::FormHelpers)
7
+ ActionView::Base.send(:include, CalendarDateSelect::FormHelpers)
8
+ ActionView::Base.send(:include, CalendarDateSelect::IncludesHelper)
9
+
10
+ # Filthy backwards compatibility hooks... grumble
11
+ if ([Rails::VERSION::MAJOR, Rails::VERSION::MINOR] <=> [2, 2]) == -1
12
+ ActionView::Helpers::InstanceTag.class_eval do
13
+ def self.new_with_backwards_compatibility(object_name, method_name, template_object, object = nil)
14
+ new(object_name, method_name, template_object, nil, object)
15
+ end
16
+ end
17
+
18
+ else
19
+ ActionView::Helpers::InstanceTag.class_eval do
20
+ class << self; alias new_with_backwards_compatibility new; end
21
+ end
22
+ end
23
+
24
+ # install files
25
+ unless File.exists?(Rails.public_path.to_s + '/javascripts/calendar_date_select/calendar_date_select.js')
26
+ ['/public', '/public/javascripts/calendar_date_select', '/public/stylesheets/calendar_date_select', '/public/images/calendar_date_select', '/public/javascripts/calendar_date_select/locale'].each do |dir|
27
+ source = File.dirname(__FILE__) + "/../#{dir}"
28
+ dest = File.expand_path(Rails.public_path.to_s + '/..' + dir)
29
+ FileUtils.mkdir_p(dest)
30
+ FileUtils.cp(Dir.glob(source+'/*.*'), dest)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,2 @@
1
+ <!-- Nothing here; part of the calendar_date_select plugin -->
2
+ <html><head></head><body></body></html>