recurring_select_fix_v1_2_0 1.2.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.
@@ -0,0 +1,33 @@
1
+ /*
2
+ *= require recurring_select
3
+ *= require_self
4
+ */
5
+
6
+ .rs_dialog_holder {padding-left:0px; background-color:#333; background-color:rgba(30,30,30,0.3); font-size:1em; position:absolute;
7
+ .rs_dialog { position:absolute; left:10px; right:10px; margin:0px; display:block; z-index:51;
8
+
9
+
10
+ .rs_dialog_content {
11
+
12
+ label.ui-select { display:inline-block;}
13
+ div.ui-select {display:inline-block;}
14
+
15
+ input.rs_interval {display:inline-block;}
16
+
17
+ .freq_option_section {
18
+ .day_holder {height:36px;
19
+ a {padding:10px 12px;}
20
+ }
21
+
22
+ .rs_calendar { width:225px;
23
+ * { text-shadow: none; }
24
+ a {padding:10px 8px;}
25
+ a.end_of_month { width: 111px; }
26
+ }
27
+ }
28
+
29
+ .rs_summary span { font-size:90%; font-weight:normal; }
30
+ }
31
+
32
+ }
33
+ }
@@ -0,0 +1,101 @@
1
+ @import "utilities.scss";
2
+
3
+ /* -------- resets ---------------*/
4
+
5
+ .rs_dialog_holder { font-size:14px; color:black;
6
+ a {color:black;}
7
+ input[type=button] {
8
+ font: small/normal Arial,sans-serif;
9
+ background: #F5F5F5; color: #444; border: 1px solid #ccc;
10
+ font-size: 11px; font-weight: bold; height: 27px; line-height: 27px; outline: none; padding: 0 8px; text-align: center;
11
+
12
+ @include rounded_corners(2px);
13
+ @include gradiant(#f5f5f5, #f1f1f1);
14
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f5f5f5',EndColorStr='#f1f1f1');
15
+
16
+ &:hover {border-color:#aaa; color:#222; background-color:#f9f9f9; @include shadows(0px, 1px, 2px, rgba(0,0,0,0.2)); }
17
+ &:focus {border-color:#1E90FF;}
18
+ &:active {border-color:#1E90FF;}
19
+ }
20
+ }
21
+
22
+ /*------- defaults ------------ */
23
+ .rs_dialog_holder { font-family:helvetica, arial, 'san-serif'; color:#222; font-size:12px;}
24
+
25
+ /*------- specifics ------------ */
26
+
27
+ select {
28
+ option.bold {font-weight:bold; color:red;}
29
+ }
30
+
31
+ .rs_dialog_holder { position:fixed; left:0px; right:0px; top:0px; bottom:0px; padding-left:50%; background-color:rgba(255,255,255,0.2); z-index:50;
32
+ .rs_dialog { background-color:#f6f6f6; border:1px solid #acacac; @include shadows(1px, 3px, 8px, rgba(0,0,0,0.25)); @include rounded_corners(7px);
33
+ display:inline-block; min-width:200px; margin-left:-125px; overflow:hidden; position:relative;
34
+ .rs_dialog_content { padding:10px;
35
+ h1 { font-size:16px; padding:0px; margin:0 0 10px 0;
36
+ a {float:right; display:inline-block; height:16px; width:16px; background-image:url(<%=asset_path "recurring_select/cancel.png"%>); background-position:center; background-repeat:no-repeat;}
37
+ }
38
+
39
+ p { padding:5px 0; margin:0;
40
+ label {margin-right:10px;}
41
+ }
42
+
43
+ .freq_option_section { display:none;
44
+ label { font-weight: bold; }
45
+ .rs_interval {width:30px; text-align:center;}
46
+
47
+ .day_holder { border-left:1px solid #ccc; position:relative; margin-top:5px; height:26px;
48
+ a {display:block; padding:5px 7px; font-size:14px; border-style:solid; border-color:#ccc; border-width:1px 1px 1px 0px; float:left; text-decoration:none; font-weight:bold; @include inset_shadows(0px, 1px, 2px, rgba(0,0,0,0.1)); background-color:#fff;;
49
+ &.selected {background-color:#89a; color:#fff; @include inset_shadows(1px, 1px, 2px, rgba(0,0,0,0.2)); @include gradiant(#9ab, #789); }
50
+ &:hover { cursor:pointer; background-color:#dde;}
51
+ }
52
+ }
53
+
54
+ .rs_calendar_day, .rs_calendar_week {
55
+ width:155px;
56
+ a {display:inline-block; text-align:center; width:15px; padding:5px 3px; font-size:12px; border-style:solid; border-color:#ccc; border-width:1px 1px 1px 1px; margin:-1px 0 0 -1px; line-height:10px; background-color:#fff; font-weight:bold;
57
+ &.selected {background-color:#89a; color:#fff; @include gradiant(#9ab, #789); @include inset_shadows(0px, 1px, 2px, rgba(0,0,0,0.2)); text-shadow:0 1px 1px #333;}
58
+ &:hover { cursor:pointer; background-color:#dde;}
59
+ }
60
+ a.end_of_month { width: 81px; }
61
+ }
62
+ .rs_calendar_week {
63
+ width: 191px;
64
+ span {
65
+ display: inline-block;
66
+ width: 35px;
67
+ }
68
+ }
69
+
70
+ .monthly_rule_type {
71
+ span {
72
+ margin-right: 15px;
73
+ }
74
+ }
75
+ }
76
+
77
+
78
+ .rs_summary { padding:0px; margin-top:15px; border-top:1px solid #ccc;
79
+ span {font-weight:bold; border-top:1px solid #fff; display:block; padding:10px 0 5px 0;}
80
+ &.fetching {color:#999;
81
+ span {background-image:url(<%=asset_path "recurring_select/throbber_13x13.gif" %>); background-position:center; background-repeat:no-repeat; display:inline-block; height:13px; width:13px; margin-top:-4px; padding-right:5px;}
82
+ }
83
+ label {font-weight:normal;}
84
+ }
85
+
86
+ .controls { padding:10px 0px 5px 0px; min-width:170px; text-align:center;
87
+ input[type=button] { margin:0px 5px; width:70px;
88
+ &.rs_save {color:#333; }
89
+ &.rs_cancel {color:#666;}
90
+ &.disabled {color:#aaa; }
91
+ }
92
+ }
93
+ }
94
+
95
+ &.animated {
96
+ .controls {position:absolute; bottom:10px; left:10px;}
97
+ .rs_summary, .freq_option_section {display:none;}
98
+ }
99
+
100
+ }
101
+ }
@@ -0,0 +1,26 @@
1
+ @mixin shadows($x_offset: 0px, $y_offset: 1px, $size: 8px, $color: rgba(0, 0, 0, 0.5)) {
2
+ -webkit-box-shadow: $x_offset $y_offset $size $color;
3
+ -moz-box-shadow: $x_offset $y_offset $size $color;
4
+ -ms-box-shadow: $x_offset $y_offset $size $color;
5
+ -o-box-shadow: $x_offset $y_offset $size $color;
6
+ box-shadow: $x_offset $y_offset $size $color;
7
+ }
8
+
9
+ @mixin inset_shadows($x_offset: 0px, $y_offset: 1px, $size: 8px, $color: rgba(0, 0, 0, 0.5)) {
10
+ -webkit-box-shadow: $x_offset $y_offset $size $color inset;
11
+ -moz-box-shadow: $x_offset $y_offset $size $color inset;
12
+ -ms-box-shadow: $x_offset $y_offset $size $color inset;
13
+ -o-box-shadow: $x_offset $y_offset $size $color inset;
14
+ box-shadow: $x_offset $y_offset $size $color inset;
15
+ }
16
+
17
+ @mixin rounded_corners($radius: 5px) { -moz-border-radius: $radius; -webkit-border-radius: $radius; border-radius: $radius;}
18
+
19
+ @mixin gradiant ($color_a:#aaa, $color_b:#bbb) {
20
+ position:relative;
21
+ background-image: -webkit-linear-gradient(top, $color_a, $color_b); /* Chrome 10+, Saf5.1+ */
22
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from($color_a), to($color_b)); /* Saf4+, Chrome */
23
+ background-image: -moz-linear-gradient(top,$color_a,$color_b); /* FF3.6 */
24
+ background-image: -ms-linear-gradient(top, $color_a, $color_b); /* IE10 */
25
+ background-image: -o-linear-gradient(top, $color_a, $color_b); /* Opera 11.10+ */
26
+ }
@@ -0,0 +1,27 @@
1
+ require "ice_cube"
2
+ require_relative "utilities/form_options_ext"
3
+ require_relative "utilities/tag_ext"
4
+
5
+ module RecurringSelectHelper
6
+ module FormHelper
7
+ def select_recurring(object, method, default_schedules = nil, options = {}, html_options = {})
8
+ if defined?(RecurringSelectHelper::RecurringSelectTag)
9
+ # === Rails 4
10
+ RecurringSelectTag.new(object, method, self, default_schedules, options, html_options).render
11
+ elsif defined?(RecurringSelectHelper::InstanceTag)
12
+ # === Rails 3
13
+ InstanceTag.new(object, method, self, options.delete(:object)).to_recurring_select_tag(default_schedules, options, html_options)
14
+ end
15
+ end
16
+ end
17
+
18
+ module FormBuilder
19
+ def select_recurring(method, default_schedules = nil, options = {}, html_options = {})
20
+ if !@template.respond_to?(:select_recurring)
21
+ @template.class.send(:include, RecurringSelectHelper::FormHelper)
22
+ end
23
+
24
+ @template.select_recurring(@object_name, method, default_schedules, options.merge(:object => @object), html_options)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ module RecurringSelectHelper
2
+ module FormOptionsHelper
3
+ def recurring_options_for_select(currently_selected_rule = nil, default_schedules = nil, options = {})
4
+
5
+ options_array = []
6
+ blank_option_label = options[:blank_label] || I18n.t("recurring_select.not_recurring")
7
+ blank_option = [blank_option_label, "null"]
8
+ separator = [I18n.t("recurring_select.or"), {:disabled => true}]
9
+
10
+ if default_schedules.blank?
11
+ if currently_selected_rule
12
+ options_array << blank_option if options[:allow_blank]
13
+ options_array << ice_cube_rule_to_option(currently_selected_rule)
14
+ options_array << separator
15
+ options_array << [I18n.t("recurring_select.change_schedule"), "custom"]
16
+ else
17
+ options_array << blank_option
18
+ options_array << [I18n.t("recurring_select.set_schedule"), "custom"]
19
+ end
20
+ else
21
+ options_array << blank_option if options[:allow_blank]
22
+
23
+ options_array += default_schedules.collect{|dc|
24
+ ice_cube_rule_to_option(dc)
25
+ }
26
+
27
+ if currently_selected_rule and not current_rule_in_defaults?(currently_selected_rule, default_schedules)
28
+ options_array << ice_cube_rule_to_option(currently_selected_rule, true)
29
+ custom_label = [I18n.t("recurring_select.new_custom_schedule"), "custom"]
30
+ else
31
+ custom_label = [I18n.t("recurring_select.custom_schedule"), "custom"]
32
+ end
33
+
34
+ options_array << separator
35
+ options_array << custom_label
36
+ end
37
+
38
+ options_for_select(options_array, currently_selected_rule.to_json)
39
+ end
40
+
41
+ private
42
+
43
+ def ice_cube_rule_to_option(supplied_rule, custom = false)
44
+ return supplied_rule unless RecurringSelect.is_valid_rule?(supplied_rule)
45
+
46
+ rule = RecurringSelect.dirty_hash_to_rule(supplied_rule)
47
+ ar = [rule.to_s, rule.to_hash.to_json]
48
+
49
+ if custom
50
+ ar[0] << "*"
51
+ ar << {"data-custom" => true}
52
+ end
53
+
54
+ ar
55
+ end
56
+
57
+ def current_rule_in_defaults?(currently_selected_rule, default_schedules)
58
+ default_schedules.any?{|option|
59
+ option == currently_selected_rule or
60
+ (option.is_a?(Array) and option[1] == currently_selected_rule)
61
+ }
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,53 @@
1
+ module RecurringSelectHelper
2
+ module SelectHTMLOptions
3
+ private
4
+
5
+ def recurring_select_html_options(html_options)
6
+ html_options = html_options.stringify_keys
7
+ html_options["class"] = (html_options["class"].to_s.split + ["recurring_select"]).join(" ")
8
+ html_options
9
+ end
10
+ end
11
+
12
+ if defined?(ActionView::Helpers::Tags::Base)
13
+ # === Rails 4
14
+ class RecurringSelectTag < ActionView::Helpers::Tags::Base
15
+ include RecurringSelectHelper::FormOptionsHelper
16
+ include SelectHTMLOptions
17
+
18
+ def initialize(object, method, template_object, default_schedules = nil, options = {}, html_options = {})
19
+ @default_schedules = default_schedules
20
+ @choices = @choices.to_a if @choices.is_a?(Range)
21
+ @method_name = method.to_s
22
+ @object_name = object.to_s
23
+ @html_options = recurring_select_html_options(html_options)
24
+ add_default_name_and_id(@html_options)
25
+
26
+ super(object, method, template_object, options)
27
+ end
28
+
29
+ def render
30
+ option_tags = add_options(recurring_options_for_select(value(object), @default_schedules, @options), @options, value(object))
31
+ select_content_tag(option_tags, @options, @html_options)
32
+ end
33
+ end
34
+
35
+ elsif defined?(ActionView::Helpers::InstanceTag)
36
+ # === Rails 3
37
+ class InstanceTag < ActionView::Helpers::InstanceTag
38
+ include RecurringSelectHelper::FormOptionsHelper
39
+ include SelectHTMLOptions
40
+
41
+ def to_recurring_select_tag(default_schedules, options, html_options)
42
+ html_options = recurring_select_html_options(html_options)
43
+ add_default_name_and_id(html_options)
44
+ value = value(object)
45
+ options = add_options(
46
+ recurring_options_for_select(value, default_schedules, options),
47
+ options, value
48
+ )
49
+ content_tag("select", options, html_options)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,26 @@
1
+ require "ice_cube"
2
+
3
+ class RecurringSelectMiddleware
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if env["PATH_INFO"] =~ /^\/recurring_select\/translate/
11
+ request = Rack::Request.new(env)
12
+ params = request.params
13
+ params.symbolize_keys!
14
+
15
+ if params and params[:rule_type]
16
+ rule = RecurringSelect.dirty_hash_to_rule(params)
17
+ [200, {"Content-Type" => "text/html"}, [rule.to_s]]
18
+ else
19
+ [200, {"Content-Type" => "text/html"}, [""]]
20
+ end
21
+ else
22
+ @app.call(env)
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,8 @@
1
+ en:
2
+ recurring_select:
3
+ not_recurring: "- not recurring -"
4
+ change_schedule: "Change schedule..."
5
+ set_schedule: "Set schedule..."
6
+ new_custom_schedule: "New custom schedule..."
7
+ custom_schedule: "Custom schedule..."
8
+ or: or
@@ -0,0 +1,8 @@
1
+ fr:
2
+ recurring_select:
3
+ not_recurring: "- non récurrent -"
4
+ change_schedule: "Modifier la récurrence..."
5
+ set_schedule: "Définir la récurrence..."
6
+ new_custom_schedule: "Nouvelle récurrence..."
7
+ custom_schedule: "Récurrence personnalisée..."
8
+ or: ou
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,82 @@
1
+ require "recurring_select/engine"
2
+ require "ice_cube"
3
+
4
+ module RecurringSelect
5
+
6
+ def self.dirty_hash_to_rule(params)
7
+ if params.is_a? IceCube::Rule
8
+ params
9
+ else
10
+ if params.is_a?(String)
11
+ params = JSON.parse(params)
12
+ end
13
+
14
+ params.symbolize_keys!
15
+ rules_hash = filter_params(params)
16
+
17
+ IceCube::Rule.from_hash(rules_hash)
18
+ end
19
+ end
20
+
21
+ def self.is_valid_rule?(possible_rule)
22
+ return true if possible_rule.is_a?(IceCube::Rule)
23
+ return false if possible_rule.blank?
24
+
25
+ if possible_rule.is_a?(String)
26
+ begin
27
+ JSON.parse(possible_rule)
28
+ return true
29
+ rescue JSON::ParserError
30
+ return false
31
+ end
32
+ end
33
+
34
+ # TODO: this should really have an extra step where it tries to perform the final parsing
35
+ return true if possible_rule.is_a?(Hash)
36
+
37
+ false #only a hash or a string of a hash can be valid
38
+ end
39
+
40
+ private
41
+
42
+ def self.filter_params(params)
43
+ params.reject!{|key, value| value.blank? || value=="null" }
44
+
45
+ params[:interval] = params[:interval].to_i if params[:interval]
46
+ params[:week_start] = params[:week_start].to_i if params[:week_start]
47
+
48
+ params[:validations] ||= {}
49
+ params[:validations].symbolize_keys!
50
+
51
+ if params[:validations][:day]
52
+ params[:validations][:day] = params[:validations][:day].collect(&:to_i)
53
+ end
54
+
55
+ if params[:validations][:day_of_month]
56
+ params[:validations][:day_of_month] = params[:validations][:day_of_month].collect(&:to_i)
57
+ end
58
+
59
+ # this is soooooo ugly
60
+ if params[:validations][:day_of_week]
61
+ params[:validations][:day_of_week] ||= {}
62
+ if params[:validations][:day_of_week].length > 0 and not params[:validations][:day_of_week].keys.first =~ /\d/
63
+ params[:validations][:day_of_week].symbolize_keys!
64
+ else
65
+ originals = params[:validations][:day_of_week].dup
66
+ params[:validations][:day_of_week] = {}
67
+ originals.each{|key, value|
68
+ params[:validations][:day_of_week][key.to_i] = value
69
+ }
70
+ end
71
+ params[:validations][:day_of_week].each{|key, value|
72
+ params[:validations][:day_of_week][key] = value.collect(&:to_i)
73
+ }
74
+ end
75
+
76
+ if params[:validations][:day_of_year]
77
+ params[:validations][:day_of_year] = params[:validations][:day_of_year].collect(&:to_i)
78
+ end
79
+
80
+ params
81
+ end
82
+ end