recurring_select 3.0.1 → 4.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -13
- data/app/assets/javascripts/defaults.js +31 -0
- data/app/assets/javascripts/jquery-mobile-rs.js +20 -0
- data/app/assets/javascripts/recurring_select/{fr.js.coffee → fr.js} +2 -2
- data/app/assets/javascripts/recurring_select.js +96 -0
- data/app/assets/javascripts/recurring_select_dialog.js.erb +447 -0
- data/app/assets/javascripts/utils.js +70 -0
- data/app/assets/stylesheets/recurring_select.scss +37 -9
- data/lib/helpers/recurring_select_helper.rb +11 -10
- data/lib/recurring_select/engine.rb +1 -0
- data/lib/recurring_select/version.rb +1 -1
- data/lib/recurring_select.rb +1 -1
- metadata +16 -42
- data/app/assets/javascripts/jquery-mobile-rs.js.coffee +0 -15
- data/app/assets/javascripts/recurring_select.js.coffee +0 -105
- data/app/assets/javascripts/recurring_select_dialog.js.coffee.erb +0 -372
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31e198de02d94e75927a32460fe0a56601c1da1f52b9df05d878ea7c2857d637
|
4
|
+
data.tar.gz: 351c9d4727459ffb8e5c58eb523a08123ca49b51de8d63fe1e66c13e85d04d87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ba0419fbb294618ab4846ed4ce767c057e1574201852b8e61923bcf9889c493cd078db6ab08ea413bb117d92c525c05f39f35d8fe8c1978d8e7104673acda44
|
7
|
+
data.tar.gz: '093da6c4eaf8a91da28dce5ce12878670cd3455d2098e5b7ad50c8641dbf69936bd33cc7c0b47386220489ab3350f0ef66b3e30457e3bdbe86cd5722bd65253e'
|
data/README.md
CHANGED
@@ -26,6 +26,7 @@ gem 'recurring_select'
|
|
26
26
|
- application.css: `//= require recurring_select`
|
27
27
|
|
28
28
|
#### jQuery Mobile Interface:
|
29
|
+
- application.js: `//= require jquery`
|
29
30
|
- application.js: `//= require jquery-mobile-rs`
|
30
31
|
- application.css: `//= require jquery-mobile-rs`
|
31
32
|
|
@@ -99,8 +100,8 @@ You have to translate JavaScript texts too by including the locale file in your
|
|
99
100
|
|
100
101
|
For other languages include a JavaScript file like this:
|
101
102
|
|
102
|
-
```
|
103
|
-
|
103
|
+
```js
|
104
|
+
RecurringSelectDialog.config.texts = {
|
104
105
|
locale_iso_code: "fr"
|
105
106
|
repeat: "Repeat"
|
106
107
|
frequency: "Frequency"
|
@@ -125,8 +126,8 @@ $.fn.recurring_select.texts = {
|
|
125
126
|
|
126
127
|
Options include:
|
127
128
|
|
128
|
-
```
|
129
|
-
|
129
|
+
```js
|
130
|
+
RecurringSelectDialog.config.options = {
|
130
131
|
monthly: {
|
131
132
|
show_week: [true, true, true, true, false, false] //display week 1, 2 .... Last
|
132
133
|
}
|
@@ -135,13 +136,6 @@ $.fn.recurring_select.options = {
|
|
135
136
|
|
136
137
|
## Testing and Development
|
137
138
|
|
138
|
-
The dummy app uses a [Postgres](http://postgresapp.com/) database `recurring_select_development`. To get setup:
|
139
|
-
|
140
|
-
```console
|
141
|
-
bundle
|
142
|
-
rake db:create
|
143
|
-
```
|
144
|
-
|
145
139
|
Start the dummy server for clicking around the interface:
|
146
140
|
|
147
141
|
```console
|
@@ -151,8 +145,8 @@ rails s
|
|
151
145
|
Tests can be ran against different versions of Rails like so:
|
152
146
|
|
153
147
|
```
|
154
|
-
BUNDLE_GEMFILE=spec/gemfiles/
|
155
|
-
BUNDLE_GEMFILE=spec/gemfiles/
|
148
|
+
BUNDLE_GEMFILE=spec/gemfiles/rails-7 bundle install
|
149
|
+
BUNDLE_GEMFILE=spec/gemfiles/rails-7 bundle exec rspec spec
|
156
150
|
```
|
157
151
|
|
158
152
|
Feel free to open issues or send pull requests.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
const defaultConfig = {
|
2
|
+
options: {
|
3
|
+
monthly: {
|
4
|
+
show_week: [true, true, true, true, false, false]
|
5
|
+
}
|
6
|
+
},
|
7
|
+
texts: {
|
8
|
+
locale_iso_code: "en",
|
9
|
+
repeat: "Repeat",
|
10
|
+
last_day: "Last Day",
|
11
|
+
frequency: "Frequency",
|
12
|
+
daily: "Daily",
|
13
|
+
weekly: "Weekly",
|
14
|
+
monthly: "Monthly",
|
15
|
+
yearly: "Yearly",
|
16
|
+
every: "Every",
|
17
|
+
days: "day(s)",
|
18
|
+
weeks_on: "week(s) on",
|
19
|
+
months: "month(s)",
|
20
|
+
years: "year(s)",
|
21
|
+
day_of_month: "Day of month",
|
22
|
+
day_of_week: "Day of week",
|
23
|
+
cancel: "Cancel",
|
24
|
+
ok: "OK",
|
25
|
+
summary: "Summary",
|
26
|
+
first_day_of_week: 0,
|
27
|
+
days_first_letter: ["S", "M", "T", "W", "T", "F", "S" ],
|
28
|
+
order: ["1st", "2nd", "3rd", "4th", "5th", "Last"],
|
29
|
+
show_week: [true, true, true, true, false, false]
|
30
|
+
}
|
31
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
//= require recurring_select
|
2
|
+
//= require_self
|
3
|
+
|
4
|
+
const $ = jQuery
|
5
|
+
|
6
|
+
$(function() {
|
7
|
+
$(document).on("recurring_select:cancel recurring_select:save", ".recurring_select", function() {
|
8
|
+
$(this).selectmenu('refresh');
|
9
|
+
});
|
10
|
+
|
11
|
+
$(document).on("recurring_select:dialog_opened", ".rs_dialog_holder", function() {
|
12
|
+
$(this).find("select").attr("data-theme", $('.recurring_select').data("theme")).attr("data-mini", true).selectmenu();
|
13
|
+
$(this).find("input[type=text]").textinput();
|
14
|
+
|
15
|
+
$(this).on("recurring_select:dialog_positioned", ".rs_dialog", function() {
|
16
|
+
$(this).css({
|
17
|
+
"top" : $(window).scrollTop()+"px"});
|
18
|
+
});
|
19
|
+
});
|
20
|
+
});
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
RecurringSelectDialog.config.texts = {
|
2
2
|
locale_iso_code: "fr"
|
3
3
|
repeat: "Récurrence"
|
4
4
|
last_day: "Dernier jour"
|
@@ -21,4 +21,4 @@ $.fn.recurring_select.texts = {
|
|
21
21
|
days_first_letter: ["D", "L", "M", "M", "J", "V", "S" ]
|
22
22
|
order: ["1er", "2ème", "3ème", "4ème", "5ème", "Dernier"]
|
23
23
|
show_week: [true, true, true, true, false, false]
|
24
|
-
}
|
24
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
//= require recurring_select_dialog
|
2
|
+
//= require_self
|
3
|
+
|
4
|
+
document.addEventListener("DOMContentLoaded", () => {
|
5
|
+
document.addEventListener("focusin", (e) => {
|
6
|
+
if (e.target.matches(".recurring_select")) {
|
7
|
+
recurring_select.call(e.target, "set_initial_values")
|
8
|
+
}
|
9
|
+
})
|
10
|
+
|
11
|
+
document.addEventListener("input", (e) => {
|
12
|
+
if (e.target.matches(".recurring_select")) {
|
13
|
+
recurring_select.call(e.target, "changed")
|
14
|
+
}
|
15
|
+
})
|
16
|
+
})
|
17
|
+
|
18
|
+
const methods = {
|
19
|
+
set_initial_values() {
|
20
|
+
const str = this.querySelectorAll('option')[this.selectedIndex].textContent
|
21
|
+
this.setAttribute('data-initial-value-hash', this.value);
|
22
|
+
this.setAttribute('data-initial-value-str', str);
|
23
|
+
},
|
24
|
+
|
25
|
+
changed() {
|
26
|
+
if (this.value == "custom") {
|
27
|
+
methods.open.call(this);
|
28
|
+
} else {
|
29
|
+
methods.set_initial_values.call(this);
|
30
|
+
}
|
31
|
+
},
|
32
|
+
|
33
|
+
open() {
|
34
|
+
this.setAttribute("data-recurring-select-active", true);
|
35
|
+
new RecurringSelectDialog(this);
|
36
|
+
this.blur();
|
37
|
+
},
|
38
|
+
|
39
|
+
save(new_rule) {
|
40
|
+
this.querySelectorAll("option[data-custom]").forEach((el) => el.parentNode.removeChild(el) )
|
41
|
+
const new_json_val = JSON.stringify(new_rule.hash)
|
42
|
+
|
43
|
+
// TODO: check for matching name, and replace that value if found
|
44
|
+
|
45
|
+
const options = Array.from(this.querySelectorAll("option")).map(() => this.value)
|
46
|
+
if (!options.includes(new_json_val)) {
|
47
|
+
methods.insert_option.apply(this, [new_rule.str, new_json_val])
|
48
|
+
}
|
49
|
+
|
50
|
+
this.value = new_json_val
|
51
|
+
methods.set_initial_values.apply(this)
|
52
|
+
this.dispatchEvent(new CustomEvent("recurring_select:save"))
|
53
|
+
},
|
54
|
+
|
55
|
+
current_rule() {
|
56
|
+
return {
|
57
|
+
str: this.getAttribute("data-initial-value-str"),
|
58
|
+
hash: JSON.parse(this.getAttribute("data-initial-value-hash"))
|
59
|
+
};
|
60
|
+
},
|
61
|
+
|
62
|
+
cancel() {
|
63
|
+
this.value = this.getAttribute("data-initial-value-hash")
|
64
|
+
this.setAttribute("data-recurring-select-active", false);
|
65
|
+
this.dispatchEvent(new CustomEvent("recurring_select:cancel"))
|
66
|
+
},
|
67
|
+
|
68
|
+
|
69
|
+
insert_option(new_rule_str, new_rule_json) {
|
70
|
+
let separator = this.querySelectorAll("option[disabled]");
|
71
|
+
if (separator.length === 0) {
|
72
|
+
separator = this.querySelectorAll("option");
|
73
|
+
}
|
74
|
+
separator = separator[separator.length-1]
|
75
|
+
|
76
|
+
const new_option = document.createElement("option")
|
77
|
+
new_option.setAttribute("data-custom", true);
|
78
|
+
|
79
|
+
if (new_rule_str.substr(new_rule_str.length - 1) !== "*") {
|
80
|
+
new_rule_str+="*";
|
81
|
+
}
|
82
|
+
|
83
|
+
new_option.textContent = new_rule_str
|
84
|
+
new_option.value = new_rule_json
|
85
|
+
separator.parentNode.insertBefore(new_option, separator)
|
86
|
+
}
|
87
|
+
};
|
88
|
+
|
89
|
+
function recurring_select(method) {
|
90
|
+
this['recurring_select'] = this['recurring_select'] || recurring_select.bind(this)
|
91
|
+
if (method in methods) {
|
92
|
+
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
|
93
|
+
} else {
|
94
|
+
throw new Error( `Method ${method} does not exist on recurring_select` );
|
95
|
+
}
|
96
|
+
}
|
@@ -0,0 +1,447 @@
|
|
1
|
+
//= require utils
|
2
|
+
//= require defaults
|
3
|
+
|
4
|
+
class RecurringSelectDialog {
|
5
|
+
constructor(recurring_selector) {
|
6
|
+
this.config = this.constructor.config
|
7
|
+
this.cancel = this.cancel.bind(this);
|
8
|
+
this.outerCancel = this.outerCancel.bind(this);
|
9
|
+
this.save = this.save.bind(this);
|
10
|
+
this.summaryUpdate = this.summaryUpdate.bind(this);
|
11
|
+
this.summaryFetchSuccess = this.summaryFetchSuccess.bind(this);
|
12
|
+
this.init_calendar_days = this.init_calendar_days.bind(this);
|
13
|
+
this.init_calendar_weeks = this.init_calendar_weeks.bind(this);
|
14
|
+
this.toggle_month_view = this.toggle_month_view.bind(this);
|
15
|
+
this.freqChanged = this.freqChanged.bind(this);
|
16
|
+
this.intervalChanged = this.intervalChanged.bind(this);
|
17
|
+
this.daysChanged = this.daysChanged.bind(this);
|
18
|
+
this.dateOfMonthChanged = this.dateOfMonthChanged.bind(this);
|
19
|
+
this.weekOfMonthChanged = this.weekOfMonthChanged.bind(this);
|
20
|
+
this.recurring_selector = recurring_selector;
|
21
|
+
this.current_rule = this.recurring_selector.recurring_select('current_rule');
|
22
|
+
this.initDialogBox();
|
23
|
+
if ((this.current_rule.hash == null) || (this.current_rule.hash.rule_type == null)) {
|
24
|
+
this.freqChanged();
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
initDialogBox() {
|
29
|
+
document.querySelectorAll(".rs_dialog_holder").forEach(el => el.parentNode.removeChild(el))
|
30
|
+
|
31
|
+
const uiPage = document.querySelector('.ui-page-active')
|
32
|
+
const anchor = uiPage ? uiPage : document.body
|
33
|
+
|
34
|
+
const div = document.createElement("div")
|
35
|
+
div.innerHTML = this.template()
|
36
|
+
anchor.appendChild(div.children[0])
|
37
|
+
|
38
|
+
this.outer_holder = document.querySelector(".rs_dialog_holder");
|
39
|
+
this.inner_holder = this.outer_holder.querySelector(".rs_dialog");
|
40
|
+
this.content = this.outer_holder.querySelector(".rs_dialog_content");
|
41
|
+
|
42
|
+
this.mainEventInit();
|
43
|
+
this.freqInit();
|
44
|
+
this.summaryInit();
|
45
|
+
trigger(this.outer_holder, "recurring_select:dialog_opened");
|
46
|
+
this.freq_select.focus();
|
47
|
+
}
|
48
|
+
|
49
|
+
cancel() {
|
50
|
+
this.outer_holder.remove();
|
51
|
+
this.recurring_selector.recurring_select('cancel');
|
52
|
+
}
|
53
|
+
|
54
|
+
outerCancel(event) {
|
55
|
+
if (event.target.classList.contains("rs_dialog_holder")) {
|
56
|
+
this.cancel();
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
save() {
|
61
|
+
if ((this.current_rule.str == null)) { return; }
|
62
|
+
this.outer_holder.remove();
|
63
|
+
this.recurring_selector.recurring_select('save', this.current_rule);
|
64
|
+
}
|
65
|
+
|
66
|
+
// ========================= Init Methods ===============================
|
67
|
+
|
68
|
+
mainEventInit() {
|
69
|
+
// Tap hooks are for jQueryMobile
|
70
|
+
on(this.outer_holder, 'click tap', this.outerCancel);
|
71
|
+
on(this.content, 'click tap', 'h1 a', this.cancel);
|
72
|
+
this.save_button = this.content.querySelector('input.rs_save')
|
73
|
+
on(this.save_button, "click tap", this.save)
|
74
|
+
on(this.content.querySelector('input.rs_cancel'), "click tap", this.cancel)
|
75
|
+
}
|
76
|
+
|
77
|
+
freqInit() {
|
78
|
+
this.freq_select = this.outer_holder.querySelector(".rs_frequency");
|
79
|
+
const rule_type = this.current_rule.hash && this.current_rule.hash.rule_type
|
80
|
+
if (this.current_rule.hash != null && rule_type != null) {
|
81
|
+
if (rule_type.search(/Weekly/) !== -1) {
|
82
|
+
this.freq_select.selectedIndex = 1
|
83
|
+
this.initWeeklyOptions();
|
84
|
+
} else if (rule_type.search(/Monthly/) !== -1) {
|
85
|
+
this.freq_select.selectedIndex = 2
|
86
|
+
this.initMonthlyOptions();
|
87
|
+
} else if (rule_type.search(/Yearly/) !== -1) {
|
88
|
+
this.freq_select.selectedIndex = 3
|
89
|
+
this.initYearlyOptions();
|
90
|
+
} else {
|
91
|
+
this.initDailyOptions();
|
92
|
+
}
|
93
|
+
}
|
94
|
+
on(this.freq_select, "change", this.freqChanged);
|
95
|
+
}
|
96
|
+
|
97
|
+
initDailyOptions() {
|
98
|
+
const section = this.content.querySelector('.daily_options')
|
99
|
+
const interval_input = section.querySelector('.rs_daily_interval')
|
100
|
+
interval_input.value = this.current_rule.hash.interval
|
101
|
+
on(interval_input, "change keyup", this.intervalChanged);
|
102
|
+
section.style.display = 'block'
|
103
|
+
}
|
104
|
+
|
105
|
+
initWeeklyOptions() {
|
106
|
+
const section = this.content.querySelector('.weekly_options');
|
107
|
+
|
108
|
+
// connect the interval field
|
109
|
+
const interval_input = section.querySelector('.rs_weekly_interval');
|
110
|
+
interval_input.value = this.current_rule.hash.interval
|
111
|
+
on(interval_input, "change keyup", this.intervalChanged);
|
112
|
+
|
113
|
+
// clear selected days
|
114
|
+
section.querySelectorAll(".day_holder a").forEach(el =>
|
115
|
+
el.classList.remove("selected")
|
116
|
+
)
|
117
|
+
|
118
|
+
// connect the day fields
|
119
|
+
if ((this.current_rule.hash.validations != null) && (this.current_rule.hash.validations.day != null)) {
|
120
|
+
Array.from(this.current_rule.hash.validations.day).forEach((val) =>
|
121
|
+
section.querySelector(".day_holder a[data-value='"+val+"']").classList.add("selected")
|
122
|
+
)
|
123
|
+
}
|
124
|
+
|
125
|
+
off(section, "click")
|
126
|
+
on(section, "click", ".day_holder a", this.daysChanged)
|
127
|
+
|
128
|
+
section.style.display = 'block'
|
129
|
+
}
|
130
|
+
|
131
|
+
initMonthlyOptions() {
|
132
|
+
const section = this.content.querySelector('.monthly_options')
|
133
|
+
const interval_input = section.querySelector('.rs_monthly_interval')
|
134
|
+
interval_input.value = this.current_rule.hash.interval
|
135
|
+
on(interval_input, "change keyup", this.intervalChanged)
|
136
|
+
|
137
|
+
if (!this.current_rule.hash.validations) { this.current_rule.hash.validations = {} };
|
138
|
+
if (!this.current_rule.hash.validations.day_of_month) { this.current_rule.hash.validations.day_of_month = [] };
|
139
|
+
if (!this.current_rule.hash.validations.day_of_week) { this.current_rule.hash.validations.day_of_week = {} };
|
140
|
+
this.init_calendar_days(section);
|
141
|
+
this.init_calendar_weeks(section);
|
142
|
+
|
143
|
+
const in_week_mode = Object.keys(this.current_rule.hash.validations.day_of_week).length > 0;
|
144
|
+
section.querySelector(".monthly_rule_type_week").checked = in_week_mode
|
145
|
+
section.querySelector(".monthly_rule_type_day").checked = !in_week_mode;
|
146
|
+
this.toggle_month_view();
|
147
|
+
section.querySelectorAll("input[name=monthly_rule_type]").forEach((el) => on(el, "change", this.toggle_month_view))
|
148
|
+
section.style.display = 'block'
|
149
|
+
}
|
150
|
+
|
151
|
+
initYearlyOptions() {
|
152
|
+
const section = this.content.querySelector('.yearly_options');
|
153
|
+
const interval_input = section.querySelector('.rs_yearly_interval');
|
154
|
+
interval_input.value = this.current_rule.hash.interval
|
155
|
+
on(interval_input, "change keyup", this.intervalChanged)
|
156
|
+
section.style.display = 'block'
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
summaryInit() {
|
161
|
+
this.summary = this.outer_holder.querySelector(".rs_summary");
|
162
|
+
this.summaryUpdate();
|
163
|
+
}
|
164
|
+
|
165
|
+
// ========================= render methods ===============================
|
166
|
+
|
167
|
+
summaryUpdate(new_string) {
|
168
|
+
// this.summary.style.width = `${this.content.getBoundingClientRect().width}px`;
|
169
|
+
if ((this.current_rule.hash != null) && (this.current_rule.str != null)) {
|
170
|
+
this.summary.classList.remove("fetching");
|
171
|
+
this.save_button.classList.remove("disabled");
|
172
|
+
let rule_str = this.current_rule.str.replace("*", "");
|
173
|
+
if (rule_str.length < 20) {
|
174
|
+
rule_str = `${this.config.texts["summary"]}: `+rule_str;
|
175
|
+
}
|
176
|
+
this.summary.querySelector("span").textContent = rule_str
|
177
|
+
} else {
|
178
|
+
this.summary.classList.add("fetching");
|
179
|
+
this.save_button.classList.add("disabled");
|
180
|
+
this.summary.querySelector("span").textContent = ""
|
181
|
+
this.summaryFetch();
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
summaryFetch() {
|
186
|
+
if (!(this.current_rule.hash != null && this.current_rule.hash.rule_type != null)) { return; }
|
187
|
+
this.current_rule.hash['week_start'] = this.config.texts["first_day_of_week"];
|
188
|
+
|
189
|
+
const url = `<%= Rails.application.config.action_controller.relative_url_root %>/recurring_select/translate/${this.config.texts["locale_iso_code"]}`
|
190
|
+
const headers = { 'X-Requested-With' : 'XMLHttpRequest', 'Content-Type' : 'application/x-www-form-urlencoded' }
|
191
|
+
const body = serialize(this.current_rule.hash)
|
192
|
+
console.log(this.current_rule.hash, body)
|
193
|
+
|
194
|
+
fetch(url, { method: "POST", body, headers })
|
195
|
+
.then(r => r.text())
|
196
|
+
.then(this.summaryFetchSuccess)
|
197
|
+
}
|
198
|
+
|
199
|
+
summaryFetchSuccess(data) {
|
200
|
+
this.current_rule.str = data
|
201
|
+
this.summaryUpdate()
|
202
|
+
css(this.content, { width: "auto" })
|
203
|
+
}
|
204
|
+
|
205
|
+
init_calendar_days(section) {
|
206
|
+
const monthly_calendar = section.querySelector(".rs_calendar_day");
|
207
|
+
monthly_calendar.innerHTML = "";
|
208
|
+
for (let num = 1; num <= 31; num++) {
|
209
|
+
const day_link = document.createElement("a")
|
210
|
+
day_link.innerText = num
|
211
|
+
monthly_calendar.appendChild(day_link)
|
212
|
+
if (Array.from(this.current_rule.hash.validations.day_of_month).includes(num)) {
|
213
|
+
day_link.classList.add("selected");
|
214
|
+
}
|
215
|
+
};
|
216
|
+
|
217
|
+
// add last day of month button
|
218
|
+
const end_of_month_link = document.createElement("a")
|
219
|
+
end_of_month_link.innerText = this.config.texts["last_day"]
|
220
|
+
monthly_calendar.appendChild(end_of_month_link);
|
221
|
+
end_of_month_link.classList.add("end_of_month");
|
222
|
+
if (Array.from(this.current_rule.hash.validations.day_of_month).includes(-1)) {
|
223
|
+
end_of_month_link.classList.add("selected");
|
224
|
+
}
|
225
|
+
|
226
|
+
off(monthly_calendar, "click tap")
|
227
|
+
on(monthly_calendar, "click tap", "a", this.dateOfMonthChanged)
|
228
|
+
}
|
229
|
+
|
230
|
+
init_calendar_weeks(section) {
|
231
|
+
const monthly_calendar = section.querySelector(".rs_calendar_week")
|
232
|
+
monthly_calendar.innerHTML = ""
|
233
|
+
const row_labels = this.config.texts["order"];
|
234
|
+
const show_row = this.config.options["monthly"]["show_week"];
|
235
|
+
const cell_str = this.config.texts["days_first_letter"];
|
236
|
+
|
237
|
+
const iterable = [1, 2, 3, 4, 5, -1]
|
238
|
+
for (let index = 0; index < iterable.length; index++) {
|
239
|
+
const num = iterable[index];
|
240
|
+
if (show_row[index]) {
|
241
|
+
const el = document.createElement("span")
|
242
|
+
el.innerText = row_labels[index]
|
243
|
+
monthly_calendar.appendChild(el);
|
244
|
+
for (let i = this.config.texts["first_day_of_week"], day_of_week = i, end = 7 + this.config.texts["first_day_of_week"], asc = this.config.texts["first_day_of_week"] <= end; asc ? i < end : i > end; asc ? i++ : i--, day_of_week = i) {
|
245
|
+
day_of_week = day_of_week % 7;
|
246
|
+
const day_link = document.createElement("a")
|
247
|
+
day_link.innerText = cell_str[day_of_week]
|
248
|
+
day_link.setAttribute("day", day_of_week);
|
249
|
+
day_link.setAttribute("instance", num);
|
250
|
+
monthly_calendar.appendChild(day_link);
|
251
|
+
};
|
252
|
+
}
|
253
|
+
};
|
254
|
+
|
255
|
+
Object.entries(this.current_rule.hash.validations.day_of_week).forEach(([key, value]) => {
|
256
|
+
Array.from(value).forEach((instance, index) => {
|
257
|
+
section.querySelector(`a[day='${key}'][instance='${instance}']`).classList.add("selected")
|
258
|
+
})
|
259
|
+
})
|
260
|
+
|
261
|
+
off(monthly_calendar, "click tap")
|
262
|
+
on(monthly_calendar, "click tap", "a", this.weekOfMonthChanged)
|
263
|
+
}
|
264
|
+
|
265
|
+
toggle_month_view() {
|
266
|
+
const week_mode = this.content.querySelector(".monthly_rule_type_week").checked
|
267
|
+
if (week_mode) {
|
268
|
+
this.content.querySelector(".rs_calendar_week").style.display = "block"
|
269
|
+
this.content.querySelector(".rs_calendar_day").style.display = "none"
|
270
|
+
} else {
|
271
|
+
this.content.querySelector(".rs_calendar_week").style.display = "none"
|
272
|
+
this.content.querySelector(".rs_calendar_day").style.display = "block"
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
// ========================= Change callbacks ===============================
|
277
|
+
|
278
|
+
freqChanged() {
|
279
|
+
if (!isPlainObject(this.current_rule.hash)) { this.current_rule.hash = null; } // for custom values
|
280
|
+
|
281
|
+
if (!this.current_rule.hash) { this.current_rule.hash = {} };
|
282
|
+
this.current_rule.hash.interval = 1;
|
283
|
+
this.current_rule.hash.until = null;
|
284
|
+
this.current_rule.hash.count = null;
|
285
|
+
this.current_rule.hash.validations = null;
|
286
|
+
this.content.querySelectorAll(".freq_option_section").forEach(el => el.style.display = 'none')
|
287
|
+
this.content.querySelector("input[type=radio], input[type=checkbox]").checked = false
|
288
|
+
switch (this.freq_select.value) {
|
289
|
+
case "Weekly":
|
290
|
+
this.current_rule.hash.rule_type = "IceCube::WeeklyRule";
|
291
|
+
this.current_rule.str = this.config.texts["weekly"];
|
292
|
+
this.initWeeklyOptions();
|
293
|
+
break
|
294
|
+
case "Monthly":
|
295
|
+
this.current_rule.hash.rule_type = "IceCube::MonthlyRule";
|
296
|
+
this.current_rule.str = this.config.texts["monthly"];
|
297
|
+
this.initMonthlyOptions();
|
298
|
+
break
|
299
|
+
case "Yearly":
|
300
|
+
this.current_rule.hash.rule_type = "IceCube::YearlyRule";
|
301
|
+
this.current_rule.str = this.config.texts["yearly"];
|
302
|
+
this.initYearlyOptions();
|
303
|
+
break
|
304
|
+
default:
|
305
|
+
this.current_rule.hash.rule_type = "IceCube::DailyRule";
|
306
|
+
this.current_rule.str = this.config.texts["daily"];
|
307
|
+
this.initDailyOptions();
|
308
|
+
};
|
309
|
+
this.summaryUpdate();
|
310
|
+
}
|
311
|
+
|
312
|
+
intervalChanged(event) {
|
313
|
+
this.current_rule.str = null;
|
314
|
+
if (!this.current_rule.hash) { this.current_rule.hash = {} };
|
315
|
+
this.current_rule.hash.interval = parseInt(event.currentTarget.value);
|
316
|
+
if ((this.current_rule.hash.interval < 1) || isNaN(this.current_rule.hash.interval)) {
|
317
|
+
this.current_rule.hash.interval = 1;
|
318
|
+
}
|
319
|
+
this.summaryUpdate();
|
320
|
+
}
|
321
|
+
|
322
|
+
daysChanged(event) {
|
323
|
+
event.target.classList.toggle("selected");
|
324
|
+
this.current_rule.str = null;
|
325
|
+
if (!this.current_rule.hash) { this.current_rule.hash = {} };
|
326
|
+
this.current_rule.hash.validations = {};
|
327
|
+
const raw_days = Array.from(this.content.querySelectorAll(".day_holder a.selected"))
|
328
|
+
.map(el => parseInt(el.dataset.value))
|
329
|
+
this.current_rule.hash.validations.day = raw_days
|
330
|
+
this.summaryUpdate();
|
331
|
+
return false;
|
332
|
+
}
|
333
|
+
|
334
|
+
dateOfMonthChanged(event) {
|
335
|
+
event.target.classList.toggle("selected");
|
336
|
+
this.current_rule.str = null;
|
337
|
+
if (!this.current_rule.hash) { this.current_rule.hash = {} };
|
338
|
+
this.current_rule.hash.validations = {};
|
339
|
+
const raw_days = Array.from(this.content.querySelectorAll(".monthly_options .rs_calendar_day a.selected"))
|
340
|
+
.map(el => {
|
341
|
+
return el.innerText === this.config.texts["last_day"] ? -1 : parseInt(el.innerText)
|
342
|
+
})
|
343
|
+
this.current_rule.hash.validations.day_of_week = {};
|
344
|
+
this.current_rule.hash.validations.day_of_month = raw_days;
|
345
|
+
this.summaryUpdate();
|
346
|
+
return false;
|
347
|
+
}
|
348
|
+
|
349
|
+
weekOfMonthChanged(event) {
|
350
|
+
event.target.classList.toggle("selected");
|
351
|
+
this.current_rule.str = null;
|
352
|
+
if (!this.current_rule.hash) { this.current_rule.hash = {} };
|
353
|
+
this.current_rule.hash.validations = {};
|
354
|
+
this.current_rule.hash.validations.day_of_month = [];
|
355
|
+
this.current_rule.hash.validations.day_of_week = {};
|
356
|
+
this.content.querySelectorAll(".monthly_options .rs_calendar_week a.selected")
|
357
|
+
.forEach((elm, index) => {
|
358
|
+
const day = parseInt(elm.getAttribute("day"));
|
359
|
+
const instance = parseInt(elm.getAttribute("instance"));
|
360
|
+
if (!this.current_rule.hash.validations.day_of_week[day]) { this.current_rule.hash.validations.day_of_week[day] = [] };
|
361
|
+
return this.current_rule.hash.validations.day_of_week[day].push(instance);
|
362
|
+
})
|
363
|
+
this.summaryUpdate();
|
364
|
+
return false;
|
365
|
+
}
|
366
|
+
|
367
|
+
// ========================= Change callbacks ===============================
|
368
|
+
|
369
|
+
template() {
|
370
|
+
let str = `\
|
371
|
+
<div class='rs_dialog_holder'> \
|
372
|
+
<div class='rs_dialog'> \
|
373
|
+
<div class='rs_dialog_content'> \
|
374
|
+
<h1>${this.config.texts["repeat"]} <a href='javascript:void(0)' title='${this.config.texts["cancel"]}' alt='${this.config.texts["cancel"]}'></a> </h1> \
|
375
|
+
<p class='frequency-select-wrapper'> \
|
376
|
+
<label for='rs_frequency'>${this.config.texts["frequency"]}:</label> \
|
377
|
+
<select data-wrapper-class='ui-recurring-select' id='rs_frequency' class='rs_frequency' name='rs_frequency'> \
|
378
|
+
<option value='Daily'>${this.config.texts["daily"]}</option> \
|
379
|
+
<option value='Weekly'>${this.config.texts["weekly"]}</option> \
|
380
|
+
<option value='Monthly'>${this.config.texts["monthly"]}</option> \
|
381
|
+
<option value='Yearly'>${this.config.texts["yearly"]}</option> \
|
382
|
+
</select> \
|
383
|
+
</p> \
|
384
|
+
\
|
385
|
+
<div class='daily_options freq_option_section'> \
|
386
|
+
<p> \
|
387
|
+
${this.config.texts["every"]} \
|
388
|
+
<input type='text' data-wrapper-class='ui-recurring-select' name='rs_daily_interval' class='rs_daily_interval rs_interval' value='1' size='2' /> \
|
389
|
+
${this.config.texts["days"]} \
|
390
|
+
</p> \
|
391
|
+
</div> \
|
392
|
+
<div class='weekly_options freq_option_section'> \
|
393
|
+
<p> \
|
394
|
+
${this.config.texts["every"]} \
|
395
|
+
<input type='text' data-wrapper-class='ui-recurring-select' name='rs_weekly_interval' class='rs_weekly_interval rs_interval' value='1' size='2' /> \
|
396
|
+
${this.config.texts["weeks_on"]}: \
|
397
|
+
</p> \
|
398
|
+
<div class='day_holder'>\
|
399
|
+
`;
|
400
|
+
for (let i = this.config.texts["first_day_of_week"], day_of_week = i, end = 7 + this.config.texts["first_day_of_week"], asc = this.config.texts["first_day_of_week"] <= end; asc ? i < end : i > end; asc ? i++ : i--, day_of_week = i) {
|
401
|
+
day_of_week = day_of_week % 7;
|
402
|
+
str += `<a href='#' data-value='${day_of_week}'>${this.config.texts["days_first_letter"][day_of_week]}</a>`;
|
403
|
+
};
|
404
|
+
|
405
|
+
str += `\
|
406
|
+
</div> \
|
407
|
+
<span style='clear:both; visibility:hidden; height:1px;'>.</span> \
|
408
|
+
</div> \
|
409
|
+
<div class='monthly_options freq_option_section'> \
|
410
|
+
<p> \
|
411
|
+
${this.config.texts["every"]} \
|
412
|
+
<input type='text' data-wrapper-class='ui-recurring-select' name='rs_monthly_interval' class='rs_monthly_interval rs_interval' value='1' size='2' /> \
|
413
|
+
${this.config.texts["months"]}: \
|
414
|
+
</p> \
|
415
|
+
<p class='monthly_rule_type'> \
|
416
|
+
<span><label for='monthly_rule_type_day'>${this.config.texts["day_of_month"]}</label><input type='radio' class='monthly_rule_type_day' name='monthly_rule_type' id='monthly_rule_type_day' value='true' /></span> \
|
417
|
+
<span><label for='monthly_rule_type_week'>${this.config.texts["day_of_week"]}</label><input type='radio' class='monthly_rule_type_week' name='monthly_rule_type' id='monthly_rule_type_week' value='true' /></span> \
|
418
|
+
</p> \
|
419
|
+
<p class='rs_calendar_day'></p> \
|
420
|
+
<p class='rs_calendar_week'></p> \
|
421
|
+
</div> \
|
422
|
+
<div class='yearly_options freq_option_section'> \
|
423
|
+
<p> \
|
424
|
+
${this.config.texts["every"]} \
|
425
|
+
<input type='text' data-wrapper-class='ui-recurring-select' name='rs_yearly_interval' class='rs_yearly_interval rs_interval' value='1' size='2' /> \
|
426
|
+
${this.config.texts["years"]} \
|
427
|
+
</p> \
|
428
|
+
</div> \
|
429
|
+
<p class='rs_summary'> \
|
430
|
+
<span></span> \
|
431
|
+
</p> \
|
432
|
+
<div class='controls'> \
|
433
|
+
<input type='button' data-wrapper-class='ui-recurring-select' class='rs_save' value='${this.config.texts["ok"]}' /> \
|
434
|
+
<input type='button' data-wrapper-class='ui-recurring-select' class='rs_cancel' value='${this.config.texts["cancel"]}' /> \
|
435
|
+
</div> \
|
436
|
+
</div> \
|
437
|
+
</div> \
|
438
|
+
</div>\
|
439
|
+
`;
|
440
|
+
|
441
|
+
return str;
|
442
|
+
}
|
443
|
+
}
|
444
|
+
|
445
|
+
RecurringSelectDialog.config = defaultConfig
|
446
|
+
|
447
|
+
window.RecurringSelectDialog = RecurringSelectDialog
|