datetimepicker 0.0.1

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.
@@ -0,0 +1,2 @@
1
+ @import "datetimepicker/bootstrap_datepicker";
2
+ @import "datetimepicker/bootstrap_timepicker";
@@ -0,0 +1,156 @@
1
+ /*!
2
+ * Datepicker for Bootstrap
3
+ *
4
+ * Copyright 2012 Stefan Petre
5
+ * Licensed under the Apache License v2.0
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ */
9
+ .datepicker {
10
+ top: 0;
11
+ left: 0;
12
+ padding: 4px;
13
+ margin-top: 1px;
14
+ -webkit-border-radius: 4px;
15
+ -moz-border-radius: 4px;
16
+ border-radius: 4px;
17
+ /*.dow {
18
+ border-top: 1px solid #ddd !important;
19
+ }*/
20
+ }
21
+ .datepicker:before {
22
+ content: '';
23
+ display: inline-block;
24
+ border-left: 7px solid transparent;
25
+ border-right: 7px solid transparent;
26
+ border-bottom: 7px solid #ccc;
27
+ border-bottom-color: rgba(0, 0, 0, 0.2);
28
+ position: absolute;
29
+ top: -7px;
30
+ left: 6px;
31
+ }
32
+ .datepicker:after {
33
+ content: '';
34
+ display: inline-block;
35
+ border-left: 6px solid transparent;
36
+ border-right: 6px solid transparent;
37
+ border-bottom: 6px solid #ffffff;
38
+ position: absolute;
39
+ top: -6px;
40
+ left: 7px;
41
+ }
42
+ .datepicker > div {
43
+ display: none;
44
+ }
45
+ .datepicker table {
46
+ width: 100%;
47
+ margin: 0;
48
+ }
49
+ .datepicker td, .datepicker th {
50
+ text-align: center;
51
+ width: 20px;
52
+ height: 20px;
53
+ -webkit-border-radius: 4px;
54
+ -moz-border-radius: 4px;
55
+ border-radius: 4px;
56
+ }
57
+ .datepicker td.day:hover {
58
+ background: #eeeeee;
59
+ cursor: pointer;
60
+ }
61
+ .datepicker td.old, .datepicker td.new {
62
+ color: #999999;
63
+ }
64
+ .datepicker td.active, .datepicker td.active:hover {
65
+ background-color: #006dcc;
66
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
67
+ background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
68
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
69
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
70
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
71
+ background-image: linear-gradient(top, #0088cc, #0044cc);
72
+ background-repeat: repeat-x;
73
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
74
+ border-color: #0044cc #0044cc #002a80;
75
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
76
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
77
+ color: #fff;
78
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
79
+ }
80
+ .datepicker td.active:hover,
81
+ .datepicker td.active:hover:hover,
82
+ .datepicker td.active:active,
83
+ .datepicker td.active:hover:active,
84
+ .datepicker td.active.active,
85
+ .datepicker td.active:hover.active,
86
+ .datepicker td.active.disabled,
87
+ .datepicker td.active:hover.disabled,
88
+ .datepicker td.active[disabled],
89
+ .datepicker td.active:hover[disabled] {
90
+ background-color: #0044cc;
91
+ }
92
+ .datepicker td.active:active,
93
+ .datepicker td.active:hover:active,
94
+ .datepicker td.active.active,
95
+ .datepicker td.active:hover.active {
96
+ background-color: #003399 \9;
97
+ }
98
+ .datepicker td span {
99
+ display: block;
100
+ width: 47px;
101
+ height: 54px;
102
+ line-height: 54px;
103
+ float: left;
104
+ margin: 2px;
105
+ cursor: pointer;
106
+ -webkit-border-radius: 4px;
107
+ -moz-border-radius: 4px;
108
+ border-radius: 4px;
109
+ }
110
+ .datepicker td span:hover {
111
+ background: #eeeeee;
112
+ }
113
+ .datepicker td span.active {
114
+ background-color: #006dcc;
115
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
116
+ background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
117
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
118
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
119
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
120
+ background-image: linear-gradient(top, #0088cc, #0044cc);
121
+ background-repeat: repeat-x;
122
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
123
+ border-color: #0044cc #0044cc #002a80;
124
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
125
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
126
+ color: #fff;
127
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
128
+ }
129
+ .datepicker td span.active:hover,
130
+ .datepicker td span.active:active,
131
+ .datepicker td span.active.active,
132
+ .datepicker td span.active.disabled,
133
+ .datepicker td span.active[disabled] {
134
+ background-color: #0044cc;
135
+ }
136
+ .datepicker td span.active:active, .datepicker td span.active.active {
137
+ background-color: #003399 \9;
138
+ }
139
+ .datepicker td span.old {
140
+ color: #999999;
141
+ }
142
+ .datepicker th.switch {
143
+ width: 145px;
144
+ }
145
+ .datepicker thead tr:first-child th {
146
+ cursor: pointer;
147
+ }
148
+ .datepicker thead tr:first-child th:hover {
149
+ background: #eeeeee;
150
+ }
151
+ .input-append.date .add-on i, .input-prepend.date .add-on i {
152
+ display: block;
153
+ cursor: pointer;
154
+ width: 16px;
155
+ height: 16px;
156
+ }
@@ -0,0 +1,81 @@
1
+ .bootstrap-timepicker.dropdown-menu {
2
+ border-radius: 4px 4px 4px 4px;
3
+ display: none;
4
+ left: 0;
5
+ margin-top: 1px;
6
+ padding: 4px;
7
+ top: 0;
8
+ min-width: 10px;
9
+ }
10
+ .bootstrap-timepicker.dropdown-menu.open {
11
+ display: inline-block;
12
+ }
13
+ .bootstrap-timepicker.dropdown-menu:before {
14
+ border-bottom: 7px solid rgba(0, 0, 0, 0.2);
15
+ border-left: 7px solid transparent;
16
+ border-right: 7px solid transparent;
17
+ content: "";
18
+ left: 6px;
19
+ position: absolute;
20
+ top: -7px;
21
+ }
22
+ .bootstrap-timepicker.dropdown-menu:after {
23
+ border-bottom: 6px solid #FFFFFF;
24
+ border-left: 6px solid transparent;
25
+ border-right: 6px solid transparent;
26
+ content: "";
27
+ left: 7px;
28
+ position: absolute;
29
+ top: -6px;
30
+ }
31
+ .bootstrap-timepicker.modal {
32
+ margin-left: -100px;
33
+ margin-top: 0;
34
+ top: 30%;
35
+ width: 200px;
36
+ }
37
+ .bootstrap-timepicker.modal .modal-content {
38
+ padding: 0;
39
+ }
40
+ .bootstrap-timepicker table {
41
+ margin: 0;
42
+ width: 100%;
43
+ }
44
+ .bootstrap-timepicker table td {
45
+ height: 30px;
46
+ margin: 0;
47
+ padding: 2px;
48
+ text-align: center;
49
+ }
50
+ .bootstrap-timepicker table td span {
51
+ width: 100%;
52
+ }
53
+ .bootstrap-timepicker table td a {
54
+ border: 1px solid transparent;
55
+ display: inline-block;
56
+ margin: 0;
57
+ outline: 0 none;
58
+ padding: 8px 0;
59
+ width: 3em;
60
+ }
61
+ .bootstrap-timepicker table td a:hover {
62
+ background-color: #EEEEEE;
63
+ border-color: #DDDDDD;
64
+ border-radius: 4px 4px 4px 4px;
65
+ }
66
+ .bootstrap-timepicker table td a i {
67
+ margin-top: 2px;
68
+ }
69
+ .bootstrap-timepicker table td input {
70
+ margin: 0;
71
+ text-align: center;
72
+ width: 25px;
73
+ }
74
+ .bootstrap-timepicker-component .add-on {
75
+ cursor: pointer;
76
+ }
77
+ .bootstrap-timepicker-component .add-on i {
78
+ display: block;
79
+ height: 16px;
80
+ width: 16px;
81
+ }
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/datetimepicker/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Daniel Ott"]
6
+ gem.email = ["danott@marshill.com"]
7
+ gem.description = %q{Custom field for individual setting of date and time for Rails :datetime attributes.}
8
+ gem.summary = %q{Custom field for individual setting of date and time for Rails :datetime attributes.}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "datetimepicker"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Datetimepicker::VERSION
17
+ end
@@ -0,0 +1,14 @@
1
+ require "datetimepicker/version"
2
+
3
+ module Datetimepicker
4
+ autoload :DateAndTimeManipulator, "datetimepicker/date_and_time_manipulator"
5
+
6
+ class Engine < ::Rails::Engine
7
+ require "datetimepicker/engine"
8
+ end
9
+
10
+ end
11
+
12
+ require "datetimepicker/date_formats"
13
+ require "datetimepicker/activerecord"
14
+ require "datetimepicker/simple_form/inputs/datetimepicker_input"
@@ -0,0 +1,122 @@
1
+ # Extension made to ActiveRecord::Base to handle datetimepickers dynamic methods.
2
+ ActiveRecord::Base.class_eval do
3
+
4
+ # Public: All the available :datetime columns for this model.
5
+ #
6
+ # Returns an Array of attribute names.
7
+ def self.datetime_columns
8
+ @datetime_columns ||= columns.select { |c| c.type == :datetime }.map(&:name)
9
+ end
10
+
11
+ # Public: we need to retain all of ActiveRecord's existing respond_to? fun.
12
+ alias_method :active_record_original_respond_to?, :respond_to?
13
+
14
+ # Public: ActiveRecord::Base should recognize our dynamic methods as existing.
15
+ #
16
+ # This respond_to? override will do exactly that. If the method being
17
+ # tested does not match any of these, the pre-exisiting respond_to? for
18
+ # ActiveRecord::Base is called to continue looking.
19
+ def respond_to?(method, include_private = false)
20
+ (method =~ datetimepicker_method_regex) || active_record_original_respond_to?(method, include_private)
21
+ end
22
+
23
+ private
24
+
25
+ # Private: we need to retain all of ActiveRecord's existing method_missing fun.
26
+ alias_method :active_record_original_method_missing, :method_missing
27
+
28
+ # Private: handle missing methods for datetimepickers.
29
+ #
30
+ # This method_missing override will do exactly that. If the method being
31
+ # tested does not match any of these, the pre-exisiting method_missing for
32
+ # ActiveRecord::Base is called to continue looking
33
+ def method_missing(method, *args, &block)
34
+ if method =~ datetimepicker_method_regex
35
+ # First matched group in datetimepicker_method_regex is the attribute
36
+ # we're trying to set/get.
37
+ attribute_name = $1
38
+
39
+ # Second matched group in datetimepicker_method_regex is the method
40
+ # on datetimepicker that is trying to be sent.
41
+ # Possible values: "date", "date=", "time", "time=",
42
+ # "date_before_type_cast", "time_before_type_cast"
43
+ datetimepicker_method = $2
44
+
45
+ # When simple_form is generating inputs, it's looking for the value of
46
+ # "#{attribute_name}_datepicker_date_before_type_cast". Since this
47
+ # "column" we're generating inputs for is dynamic, we can cut that part
48
+ # out to keep things working the way we expect.
49
+ datetimepicker_method.gsub!("_before_type_cast", "")
50
+
51
+ send(:datetimepicker_proxy, attribute_name, datetimepicker_method, *args)
52
+ else
53
+ active_record_original_method_missing(method, *args, &block)
54
+ end
55
+ end
56
+
57
+ # Private: the regex that matches datetimepicker's dynamic methods.
58
+ #
59
+ # The method we want to allow to be called dynamically:
60
+ #
61
+ # - attribute_name_datetimepicker_date
62
+ # - attribute_name_datetimepicker_date=
63
+ # - attribute_name_datetimepicker_date_before_type_cast
64
+ # - attribute_name_datetimepicker_time
65
+ # - attribute_name_datetimepicker_time=
66
+ # - attribute_name_datetimepicker_time_before_type_cast
67
+ #
68
+ # Returns a Regex
69
+ def datetimepicker_method_regex
70
+ /^(\w+)_datetimepicker_((?:date|time)(?:_before_type_cast)?=?)$/
71
+ end
72
+
73
+ # Private: does a datetime column exist for this attribute_name?
74
+ #
75
+ # attribute_name - the column we're testing for.
76
+ #
77
+ # Returns a Boolean.
78
+ def datetimepicker_column?(attribute_name)
79
+ self.class.datetime_columns.include?(attribute_name.to_s)
80
+ end
81
+
82
+ # Private: Proxy method written so we can utilize dynamic methods for
83
+ # manipulating columns of type datetime by their date and time independently.
84
+ #
85
+ # Getters get date/time values.
86
+ #
87
+ # Setters set date/time values, and update the datetime column.
88
+ #
89
+ # attribute_name - The active record attribute we're wrapping.
90
+ # datetimepicker_method - the message to pass along to manipulate the column
91
+ # using the Datetimepicker.
92
+ # args - Any attitional arguments to pass along to
93
+ # Datetimepicker.
94
+ #
95
+ # Examples
96
+ #
97
+ # datetimepicker_proxy(:created_at, "date=", "2012/01/01")
98
+ #
99
+ # Returns mixed. Getters return gotten value. Setters return the new
100
+ # attribute_name value.
101
+ def datetimepicker_proxy(attribute_name, datetimepicker_method, *args)
102
+ if !datetimepicker_column?(attribute_name)
103
+ raise "Datetimepicker can only be used on columns of type :datetime"
104
+ end
105
+
106
+ # Datetimepicker won't work so good with a nil value.
107
+ attribute_value = send(attribute_name) || Time.now.beginning_of_hour
108
+
109
+ datetimepicker = Datetimepicker::DateAndTimeManipulator.new(attribute_value,
110
+ Time::DATE_FORMATS[:datetimepicker_date],
111
+ Time::DATE_FORMATS[:datetimepicker_time])
112
+ return_value = datetimepicker.send(datetimepicker_method, *args)
113
+
114
+ # Setters gonna set.
115
+ if datetimepicker_method =~ /=$/
116
+ return_value = write_attribute(attribute_name.to_sym, datetimepicker.datetime)
117
+ end
118
+
119
+ return_value
120
+ end
121
+
122
+ end
@@ -0,0 +1,84 @@
1
+ # Public: A simple structure for independently manipulating the date and time
2
+ # components of a TimeWithZone object, while maintining the the existing date
3
+ # and time information.
4
+ #
5
+ # datetime - an instance of DateTime/Time/TimeWithZone.
6
+ # date_format - A String containing the strftime format for setting/getting
7
+ # date component of datetime.
8
+ # time_format - A String containing the strftime format for setting/getting
9
+ # time component of datetime.
10
+ # Examples
11
+ #
12
+ # DateTimePicker.new(Post.first.created_at, "%Y/%m/%d", "%H:%M")
13
+ module Datetimepicker
14
+ class DateAndTimeManipulator < Struct.new(:datetime, :date_format, :time_format)
15
+
16
+ # Public: get the date component of datetime.
17
+ #
18
+ # Returns a String in the format of date_format.
19
+ def date
20
+ datetime.strftime(date_format)
21
+ end
22
+
23
+ # Public: set the date component of datetime.
24
+ #
25
+ # new_date - The String representation of date component for datetime.
26
+ # The String should be in the format of date_format.
27
+ def date=(new_date)
28
+ self.datetime = parse_date_and_time(new_date, time)
29
+ end
30
+
31
+ # Public: get the time component of datetime.
32
+ #
33
+ # Returns a String in the format of time_format.
34
+ def time
35
+ datetime.strftime(time_format)
36
+ end
37
+
38
+ # Public: set the time component of datetime.
39
+ #
40
+ # new_time - The String representation of time component for datetime.
41
+ # The String should be in the format of time_format.
42
+ def time=(new_time)
43
+ self.datetime = parse_date_and_time(date, new_time)
44
+ end
45
+
46
+ private
47
+
48
+ # Private: create a new TimeWithZone from date and time Strings.
49
+ #
50
+ # date - A String of the date in the format of date_format
51
+ # time - A String of the time in the format of time_format.
52
+ #
53
+ # The following blog post was infinitely valuable in figuring out how to
54
+ # parse dates and times while maintaining a time zone in Rails.
55
+ #
56
+ # http://www.elabs.se/blog/36-working-with-time-zones-in-ruby-on-rails
57
+ #
58
+ # Returns an instance of TimeWithZone.
59
+ def parse_date_and_time(parse_date, parse_time)
60
+ Time.strptime(date_and_time_format(parse_date, parse_time),
61
+ date_and_time_format(date_format, time_format)).in_time_zone(Time.zone)
62
+ end
63
+
64
+ # Private: generate strings for parsing datetime in a consistent way.
65
+ #
66
+ # date_component - A String of the date component of the date and time pair.
67
+ # time_component - A String of the time component of the date and time pair.
68
+ # separator - (optional) String used to concatenate the components.
69
+ #
70
+ # Examples
71
+ #
72
+ # date_and_time_format("%Y/%m/%d", "%H:%M")
73
+ # => "%Y/%m/%d %H:%M"
74
+ #
75
+ # date_and_time_format("2004/08/15", "16:23", "T")
76
+ # => "2004/0815T16:23"
77
+ #
78
+ # Returns a String.
79
+ def date_and_time_format(date_component, time_component, separator = " ")
80
+ "#{date_component}#{separator}#{time_component}"
81
+ end
82
+
83
+ end
84
+ end