recurring_select 3.0.1 → 4.0.0.rc1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 823b393395bb4608d998ea0a5b8f9b38b985ae8ee91107523d5383aaa94a97ae
4
- data.tar.gz: ecf294db986e90ea87ba5d2c6481053fbd466267a18949915201cdb04501774e
3
+ metadata.gz: 31e198de02d94e75927a32460fe0a56601c1da1f52b9df05d878ea7c2857d637
4
+ data.tar.gz: 351c9d4727459ffb8e5c58eb523a08123ca49b51de8d63fe1e66c13e85d04d87
5
5
  SHA512:
6
- metadata.gz: 4870f4d76cc947ee2f20cdf3c917e05ddb804acae5a2852d4f0faf4576019f7f0656d8b70c7608b2a22b7487902da908f4c0d3d174cf768b42e0c4ab6f68314a
7
- data.tar.gz: 3006029c17dab3353f0f89ba025996d280978e4e7fdf6cdf764dd67f930eac23f62f0da1877769df5d3adc5aa4616aa3f07dd15e67d4d4b750d794ea25bdde2a
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
- ```coffeescript
103
- $.fn.recurring_select.texts = {
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
- ```coffeescript
129
- $.fn.recurring_select.options = {
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/Gemfile.rails-4.0.x bundle install
155
- BUNDLE_GEMFILE=spec/gemfiles/Gemfile.rails-4.0.x bundle exec rspec spec
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
- $.fn.recurring_select.texts = {
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