recurring_select 3.0.0 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,70 @@
1
+ function css(el, styles) {
2
+ for (let rule in styles) {
3
+ el.style[rule] = styles[rule]
4
+ }
5
+ }
6
+
7
+ function trigger(el, eventName) {
8
+ el.dispatchEvent(new CustomEvent(eventName))
9
+ }
10
+
11
+ function isPlainObject(obj) {
12
+ return obj && obj.toString() === "[object Object]"
13
+ }
14
+
15
+ const eventHandlerRefsExpando = '__recurring_select_events'
16
+
17
+ function on(el, events, sel, handler) {
18
+ let eventHandler = sel
19
+ if (handler) {
20
+ eventHandler = (e) => {
21
+ if (e.target.matches(sel)) {
22
+ if (handler.call(this, e) === false) {
23
+ e.preventDefault()
24
+ e.stopPropagation()
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ el[eventHandlerRefsExpando] = el[eventHandlerRefsExpando] || []
31
+
32
+ events.trim().split(/ +/).forEach(type => {
33
+ el[eventHandlerRefsExpando].push([ type, eventHandler ])
34
+ el.addEventListener(type, eventHandler)
35
+ })
36
+ }
37
+
38
+ function off(el, events) {
39
+ const types = events.trim().split(/ +/)
40
+
41
+ el[eventHandlerRefsExpando] = (el[eventHandlerRefsExpando] || [])
42
+ .filter(([t, h], i) => {
43
+ if (types.includes(t)) {
44
+ el.removeEventListener(t, h)
45
+ return false
46
+ }
47
+ return true
48
+ })
49
+ }
50
+
51
+ function serialize(params, prefix) {
52
+ const query = Object.keys(params).map((key) => {
53
+ const value = params[key];
54
+
55
+ if (params.constructor === Array)
56
+ key = `${prefix}[]`;
57
+ else if (params.constructor === Object)
58
+ key = (prefix ? `${prefix}[${key}]` : key);
59
+
60
+ if (value === null)
61
+ return `${key}=`
62
+
63
+ if (typeof value === 'object')
64
+ return serialize(value, key);
65
+ else
66
+ return `${key}=${encodeURIComponent(value)}`;
67
+ });
68
+
69
+ return [].concat.apply([], query).join('&');
70
+ }
@@ -2,7 +2,9 @@
2
2
 
3
3
  /* -------- resets ---------------*/
4
4
 
5
- .rs_dialog_holder { font-size:14px; color:black;
5
+ .rs_dialog_holder {
6
+ font-size:14px;
7
+ color:black;
6
8
  a {color:black;}
7
9
  input[type=button] {
8
10
  font: small/normal Arial,sans-serif;
@@ -28,10 +30,29 @@ select {
28
30
  option.bold {font-weight:bold; color:red;}
29
31
  }
30
32
 
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;
33
+ .rs_dialog_holder {
34
+ display: flex;
35
+ justify-content: center;
36
+ align-items: center;
37
+ position: fixed;
38
+ left:0px;
39
+ right:0px;
40
+ top:0px;
41
+ bottom:0px;
42
+ background-color:rgba(255,255,255,0.2);
43
+ z-index:50;
44
+
45
+ .rs_dialog {
46
+ background-color:#f6f6f6;
47
+ border:1px solid #acacac;
48
+ @include shadows(1px, 3px, 8px, rgba(0,0,0,0.25));
49
+ @include rounded_corners(7px);
50
+ min-width:200px;
51
+ overflow:hidden;
52
+
53
+ .rs_dialog_content {
54
+ padding:10px;
55
+
35
56
  h1 { font-size:16px; padding:0px; margin:0 0 10px 0;
36
57
  a {float:right; display:inline-block; height:16px; width:16px; background-image:image-url("recurring_select/cancel.png"); background-position:center; background-repeat:no-repeat;}
37
58
  }
@@ -42,7 +63,8 @@ select {
42
63
 
43
64
  a { -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; }
44
65
 
45
- .freq_option_section { display:none;
66
+ .freq_option_section {
67
+ display:none;
46
68
  label { font-weight: bold; }
47
69
  .rs_interval {width:30px; text-align:center; display: inline-block;}
48
70
 
@@ -77,7 +99,10 @@ select {
77
99
  }
78
100
 
79
101
 
80
- .rs_summary { padding:0px; margin-top:15px; border-top:1px solid #ccc;
102
+ .rs_summary {
103
+ padding: 0px;
104
+ margin-top: 15px;
105
+ border-top: 1px solid #ccc;
81
106
  span {font-weight:bold; border-top:1px solid #fff; display:block; padding:10px 0 5px 0;}
82
107
  &.fetching {color:#999;
83
108
  span {background-image:image-url("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;}
@@ -85,8 +110,11 @@ select {
85
110
  label {font-weight:normal;}
86
111
  }
87
112
 
88
- .controls { padding:10px 0px 5px 0px; min-width:170px; text-align:center;
89
- input[type=button] { margin:0px 5px; width:70px;
113
+ .controls {
114
+ padding:10px 0px 5px 0px;
115
+ min-width:170px;
116
+ text-align:center;
117
+ input[type=button] { margin:0px 5px;
90
118
  &.rs_save {color:#333; }
91
119
  &.rs_cancel {color:#666;}
92
120
  &.disabled {color:#aaa; }
@@ -6,6 +6,12 @@ module RecurringSelectHelper
6
6
  RecurringSelectTag.new(object, method, self, default_schedules, options, html_options).render
7
7
  end
8
8
  end
9
+
10
+ module FormTagHelper
11
+ def select_recurring_tag(name, default_schedules = nil, options = {}, html_options = {})
12
+ RecurringSelectTag.new(nil, name, self, default_schedules, options, html_options).render
13
+ end
14
+ end
9
15
 
10
16
  module FormBuilder
11
17
  def select_recurring(method, default_schedules = nil, options = {}, html_options = {})
@@ -65,7 +71,7 @@ module RecurringSelectHelper
65
71
  ar = [rule.to_s, rule.to_hash.to_json]
66
72
 
67
73
  if custom
68
- ar[0] << "*"
74
+ ar[0] += "*"
69
75
  ar << {"data-custom" => true}
70
76
  end
71
77
 
@@ -90,19 +96,15 @@ module RecurringSelectHelper
90
96
  end
91
97
  end
92
98
 
93
- class RecurringSelectTag < ActionView::Helpers::Tags::Base
99
+ class RecurringSelectTag < ActionView::Helpers::Tags::Select
94
100
  include RecurringSelectHelper::FormOptionsHelper
95
101
  include SelectHTMLOptions
96
102
 
97
103
  def initialize(object, method, template_object, default_schedules = nil, options = {}, html_options = {})
98
104
  @default_schedules = default_schedules
99
- @choices = @choices.to_a if @choices.is_a?(Range)
100
- @method_name = method.to_s
101
- @object_name = object.to_s
102
- @html_options = recurring_select_html_options(html_options)
103
- add_default_name_and_id(@html_options)
105
+ html_options = recurring_select_html_options(html_options)
104
106
 
105
- super(object, method, template_object, options)
107
+ super(object, method, template_object, @default_schedules, options, html_options)
106
108
  end
107
109
 
108
110
  def render
@@ -6,6 +6,7 @@ module RecurringSelect
6
6
 
7
7
  initializer "recurring_select.extending_form_builder" do |app|
8
8
  ActionView::Helpers::FormHelper.send(:include, RecurringSelectHelper::FormHelper)
9
+ ActionView::Helpers::FormTagHelper.send(:include, RecurringSelectHelper::FormTagHelper)
9
10
  ActionView::Helpers::FormOptionsHelper.send(:include, RecurringSelectHelper::FormOptionsHelper)
10
11
  ActionView::Helpers::FormBuilder.send(:include, RecurringSelectHelper::FormBuilder)
11
12
  end
@@ -1,3 +1,3 @@
1
1
  module RecurringSelect
2
- VERSION = "3.0.0"
2
+ VERSION = "4.0.0.rc1"
3
3
  end
@@ -59,7 +59,7 @@ module RecurringSelect
59
59
  # this is soooooo ugly
60
60
  if params[:validations][:day_of_week]
61
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/
62
+ if params[:validations][:day_of_week].length > 0 and not params[:validations][:day_of_week].keys.first.to_s =~ /\d/
63
63
  params[:validations][:day_of_week].symbolize_keys!
64
64
  else
65
65
  originals = params[:validations][:day_of_week].dup