datetimepicker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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