voom-presenters 2.1.0 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/semantic-release.yml +1 -0
- data/.releaserc +14 -7
- data/CHANGELOG.md +24 -20
- data/Gemfile.lock +5 -5
- data/README.md +6 -8
- data/app/demo/components/date_fields.pom +10 -0
- data/app/demo/events/halted.pom +23 -0
- data/app/demo/events/nav/drawer.pom +1 -1
- data/app/demo/index.pom +1 -1
- data/lib/voom/presenters/dsl/components/date_field.rb +13 -0
- data/lib/voom/presenters/dsl/components/datetime_base.rb +2 -1
- data/lib/voom/presenters/version.rb +1 -1
- data/public/bundle.css +8 -8
- data/public/bundle.js +393 -298
- data/public/wc.js +406 -311
- data/views/mdc/assets/js/components/datetime.js +101 -18
- data/views/mdc/assets/js/components/events/posts.js +12 -11
- data/views/mdc/assets/js/utils/form-data.js +12 -0
- data/views/mdc/components/datetime.erb +7 -4
- data/views/mdc/package-lock.json +18 -18
- data/views/mdc/package.json +1 -1
- metadata +4 -2
@@ -7,6 +7,7 @@ import appConfig from '../config';
|
|
7
7
|
export function initDateTime(e) {
|
8
8
|
console.debug('\tDateTime');
|
9
9
|
hookupComponents(e, '.v-datetime', VDateTime, MDCTextField);
|
10
|
+
hookupComponents(e, '.v-date-text', VDateText, MDCTextField);
|
10
11
|
}
|
11
12
|
|
12
13
|
export class VDateTime extends VTextField {
|
@@ -71,33 +72,115 @@ export class VDateTime extends VTextField {
|
|
71
72
|
this.fp.toggle();
|
72
73
|
}
|
73
74
|
|
74
|
-
// checkDefaults() {
|
75
|
-
// if(this.fp.config.mode = 'range'){
|
76
|
-
// if(this.fp.selectedDates[1]){
|
77
|
-
// // If we are in range mode and the endDate is defined as the beginning of the day, default it to be the
|
78
|
-
// // end of the day.
|
79
|
-
// let endDate = this.fp.selectedDates[1];
|
80
|
-
// if(endDate.getHours() == 0 && endDate.getMinutes() == 0 && endDate.getSeconds() == 0 && endDate.getMilliseconds() == 0){
|
81
|
-
// endDate.setHours(23);
|
82
|
-
// endDate.setMinutes(59);
|
83
|
-
// endDate.setSeconds(59);
|
84
|
-
// endDate.getMilliseconds(9999);
|
85
|
-
// this.fp.setDate(this.fp.selectedDates)
|
86
|
-
// }
|
87
|
-
// }
|
88
|
-
// }
|
89
|
-
// }
|
90
|
-
|
91
75
|
isDirty() {
|
92
76
|
if (!this.dirtyable) {
|
93
77
|
return false;
|
94
78
|
}
|
95
|
-
|
96
79
|
const currVal = new Date(this.fp.input.value);
|
97
80
|
const prevVal = new Date(this.originalValue);
|
81
|
+
return currVal.getTime() !== prevVal.getTime();
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
export class VDateText extends VTextField {
|
86
|
+
constructor(element, mdcComponent) {
|
87
|
+
super(element, mdcComponent);
|
88
|
+
element.addEventListener('input', this.createInputHandler(element.vComponent));
|
89
|
+
element.vComponent.input.addEventListener('blur', () => this.validate(null));
|
90
|
+
}
|
91
|
+
|
92
|
+
createInputHandler(component) {
|
93
|
+
return function(e) {
|
94
|
+
let input = component.value();
|
95
|
+
|
96
|
+
// Add a leading zero if input is like 1/ or 01 / 1/
|
97
|
+
if (/^\d\/$/.test(input)) input = '0' + input;
|
98
|
+
if (/^\d{2}\s\/\s\d\/$/.test(input)) input = input.slice(0,4) + '0' + input.slice(5,6);
|
99
|
+
|
100
|
+
// Parse and format input
|
101
|
+
if (/\D\/$/.test(input)) input = input.substr(0, input.length - 3);
|
102
|
+
let values = input.split('/').map(function(v) {
|
103
|
+
return v.replace(/\D/g, '')
|
104
|
+
});
|
105
|
+
if (values[0]) values[0] = checkValue(values[0], 12);
|
106
|
+
if (values[1]) values[1] = checkValue(values[1], 31);
|
107
|
+
const output = values.map(function(v, i) {
|
108
|
+
return v.length === 2 && i < 2 ? v + ' / ' : v;
|
109
|
+
});
|
110
|
+
component.setValue(output.join('').substr(0, 14));
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
validate(formData) {
|
115
|
+
const input = this.element.vComponent.value();
|
116
|
+
if (this.isValidDate(input)) {
|
117
|
+
if (this.origHelperText !== '') {
|
118
|
+
this.helperDisplay.innerHTML = this.origHelperText;
|
119
|
+
this.helperDisplay.classList.remove('mdc-text-field-helper-text--validation-msg');
|
120
|
+
this.element.classList.remove('mdc-text-field--invalid');
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
this.helperDisplay.classList.add('v-hidden');
|
124
|
+
}
|
125
|
+
return true;
|
126
|
+
}
|
127
|
+
|
128
|
+
const message = this.helperDisplay.dataset.validationError ?
|
129
|
+
this.helperDisplay.dataset.validationError :
|
130
|
+
this.input.validationMessage;
|
131
|
+
|
132
|
+
this.helperDisplay.innerHTML = message;
|
133
|
+
this.helperDisplay.classList.add('mdc-text-field-helper-text--validation-msg');
|
134
|
+
this.element.classList.add('mdc-text-field--invalid');
|
135
|
+
|
136
|
+
const errorMessage = {};
|
137
|
+
errorMessage[this.element.id] = [message];
|
138
|
+
return errorMessage;
|
139
|
+
}
|
140
|
+
|
141
|
+
isValidDate(dateString) {
|
142
|
+
dateString = dateString.replace(/\s+/g, '');
|
143
|
+
if (dateString === '' && !this.input.required) {
|
144
|
+
return true
|
145
|
+
}
|
146
|
+
if(!/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(dateString)) {
|
147
|
+
return false;
|
148
|
+
}
|
149
|
+
|
150
|
+
const parts = dateString.split("/");
|
151
|
+
const day = parseInt(parts[1], 10);
|
152
|
+
const month = parseInt(parts[0], 10);
|
153
|
+
const year = parseInt(parts[2], 10);
|
154
|
+
|
155
|
+
if (year < 1000 || year > 3000 || month === 0 || month > 12) {
|
156
|
+
return false;
|
157
|
+
}
|
158
|
+
|
159
|
+
const monthLength = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
|
160
|
+
if(year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
|
161
|
+
monthLength[1] = 29;
|
162
|
+
}
|
163
|
+
|
164
|
+
return day > 0 && day <= monthLength[month - 1];
|
165
|
+
};
|
98
166
|
|
167
|
+
isDirty() {
|
168
|
+
if (!this.dirtyable) {
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
const currVal = new Date(this.fp.input.value);
|
172
|
+
const prevVal = new Date(this.originalValue);
|
99
173
|
return currVal.getTime() !== prevVal.getTime();
|
100
174
|
}
|
101
175
|
}
|
102
176
|
|
177
|
+
function checkValue(str, max) {
|
178
|
+
if (str.charAt(0) !== '0' || str === '00') {
|
179
|
+
let num = parseInt(str);
|
180
|
+
if (isNaN(num) || num <= 0 || num > max) num = 1;
|
181
|
+
str = num > parseInt(max.toString().charAt(0)) && num.toString().length === 1 ? '0' + num : num.toString();
|
182
|
+
}
|
183
|
+
return str;
|
184
|
+
}
|
185
|
+
|
103
186
|
|
@@ -3,6 +3,7 @@ import appConfig from '../../config';
|
|
3
3
|
import {expandParams} from './action_parameter';
|
4
4
|
import {encode} from './encode';
|
5
5
|
import {getEventTarget} from '../get_event_target';
|
6
|
+
import {buildFormData} from '../../utils/form-data'
|
6
7
|
|
7
8
|
// Replaces a given element with the contents of the call to the url.
|
8
9
|
// parameters are appended.
|
@@ -41,9 +42,7 @@ export class VPosts extends VBase {
|
|
41
42
|
}
|
42
43
|
|
43
44
|
if (eventParams){
|
44
|
-
|
45
|
-
formData.append(name, value);
|
46
|
-
}
|
45
|
+
buildFormData(formData, eventParams);
|
47
46
|
}
|
48
47
|
|
49
48
|
// Add CSRF authenticity token if present
|
@@ -60,18 +59,13 @@ export class VPosts extends VBase {
|
|
60
59
|
formData.append(name, encode(value));
|
61
60
|
}
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
if (paramCount < 1) {
|
62
|
+
if (this.paramCount(formData) < 1) {
|
66
63
|
console.warn(
|
67
64
|
'Creating request with no data!'
|
68
|
-
+ ' Are you sure you\'ve hooked everything up correctly?'
|
69
|
-
);
|
65
|
+
+ ' Are you sure you\'ve hooked everything up correctly?');
|
70
66
|
}
|
71
67
|
|
72
68
|
let errors = this.validate(formData);
|
73
|
-
console.log('Validation errors');
|
74
|
-
console.dir(errors);
|
75
69
|
if (errors.length > 0) {
|
76
70
|
return new Promise(function(_, reject) {
|
77
71
|
results.push({
|
@@ -188,10 +182,17 @@ export class VPosts extends VBase {
|
|
188
182
|
}
|
189
183
|
|
190
184
|
// Send our FormData object; HTTP headers are set automatically
|
191
|
-
|
185
|
+
// Rack 2.2 will throw an exception https://github.com/rack/rack/issues/1603
|
186
|
+
// if we set the header as multi-part form data with no data in the body
|
187
|
+
// So we set the body to null in this case.
|
188
|
+
httpRequest.send(this.paramCount(formData) < 1 ? null : formData);
|
192
189
|
});
|
193
190
|
}
|
194
191
|
|
192
|
+
paramCount(formData){
|
193
|
+
return Array.from(formData).length;
|
194
|
+
}
|
195
|
+
|
195
196
|
isForm() {
|
196
197
|
var parentElement = this.parentElement();
|
197
198
|
return parentElement && parentElement.elements;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
// Turns an Object into FormData. Note that a nested array will come out as a hash with numeric keys
|
2
|
+
// and will need to be handled accordingly server-side.
|
3
|
+
export function buildFormData(formData, data, parentKey) {
|
4
|
+
if (data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File) && !(data instanceof Blob)) {
|
5
|
+
Object.keys(data).forEach(key => {
|
6
|
+
buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
|
7
|
+
});
|
8
|
+
} else {
|
9
|
+
const value = data == null ? '' : data;
|
10
|
+
formData.append(parentKey, value);
|
11
|
+
}
|
12
|
+
}
|
@@ -1,10 +1,11 @@
|
|
1
1
|
<%
|
2
2
|
time_val = comp.value ? Array([comp.value]).join(', ') : nil
|
3
|
+
type_class = comp.picker ? 'v-datetime' : 'v-date-text'
|
3
4
|
%>
|
4
5
|
<div id="<%= comp.id %>"
|
5
6
|
<% if comp.tag %>data-input-tag="<%= comp.tag %>"<% end %>
|
6
7
|
<% if comp.dirtyable %>data-dirtyable<% end %>
|
7
|
-
class="v-input
|
8
|
+
class="v-input <%= type_class %> mdc-text-field mdc-text-field--outlined
|
8
9
|
<%= 'mdc-text-field--with-trailing-icon' if comp.clear_icon %>
|
9
10
|
<%= 'mdc-text-field--disabled' if comp.disabled %>"
|
10
11
|
data-config='<%= snake_to_camel(to_hash(comp.config), except: %i(time_24hr)).to_json %>'
|
@@ -21,10 +22,12 @@
|
|
21
22
|
<%= "pattern='#{comp.pattern}'" if comp.pattern %>
|
22
23
|
list="<%= comp.id %>-list"
|
23
24
|
<%= erb :"components/event", :locals => {comp: comp, events: comp.events, parent_id: "#{comp.id}-input"} %>>
|
24
|
-
<%= erb :"components/icon", :locals => {comp: comp.clear_icon, class_name: 'mdc-text-field__icon', parent_id: "#{comp.id}-input"} %>
|
25
|
+
<%= erb :"components/icon", :locals => {comp: comp.clear_icon, class_name: 'mdc-text-field__icon', parent_id: "#{comp.id}-input"} if comp.picker %>
|
25
26
|
<%= erb :"components/shared/input_label", :locals => {comp: comp} %>
|
26
|
-
|
27
|
-
|
27
|
+
<% if comp.picker %>
|
28
|
+
<datalist id="<%= comp.id %>-list">
|
29
|
+
</datalist>
|
30
|
+
<% end %>
|
28
31
|
</div>
|
29
32
|
<%= erb :"components/shared/hint_error_display", :locals => {comp: comp} %>
|
30
33
|
<%= erb :"components/tooltip", :locals => {comp: comp.tooltip, parent_id: comp.id} %>
|
data/views/mdc/package-lock.json
CHANGED
@@ -3656,9 +3656,9 @@
|
|
3656
3656
|
"dev": true
|
3657
3657
|
},
|
3658
3658
|
"dns-packet": {
|
3659
|
-
"version": "1.3.
|
3660
|
-
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.
|
3661
|
-
"integrity": "sha512-
|
3659
|
+
"version": "1.3.4",
|
3660
|
+
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz",
|
3661
|
+
"integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==",
|
3662
3662
|
"dev": true,
|
3663
3663
|
"requires": {
|
3664
3664
|
"ip": "^1.1.0",
|
@@ -5524,9 +5524,9 @@
|
|
5524
5524
|
"dev": true
|
5525
5525
|
},
|
5526
5526
|
"handlebars": {
|
5527
|
-
"version": "4.7.
|
5528
|
-
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.
|
5529
|
-
"integrity": "sha512-
|
5527
|
+
"version": "4.7.7",
|
5528
|
+
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
5529
|
+
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
5530
5530
|
"dev": true,
|
5531
5531
|
"requires": {
|
5532
5532
|
"minimist": "^1.2.5",
|
@@ -7969,9 +7969,9 @@
|
|
7969
7969
|
}
|
7970
7970
|
},
|
7971
7971
|
"lodash": {
|
7972
|
-
"version": "4.17.
|
7973
|
-
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.
|
7974
|
-
"integrity": "sha512-
|
7972
|
+
"version": "4.17.21",
|
7973
|
+
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
7974
|
+
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
7975
7975
|
"dev": true
|
7976
7976
|
},
|
7977
7977
|
"lodash.camelcase": {
|
@@ -13066,9 +13066,9 @@
|
|
13066
13066
|
"dev": true
|
13067
13067
|
},
|
13068
13068
|
"querystringify": {
|
13069
|
-
"version": "2.
|
13070
|
-
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.
|
13071
|
-
"integrity": "sha512-
|
13069
|
+
"version": "2.2.0",
|
13070
|
+
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
13071
|
+
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
|
13072
13072
|
},
|
13073
13073
|
"quill": {
|
13074
13074
|
"version": "1.3.7",
|
@@ -14206,7 +14206,7 @@
|
|
14206
14206
|
},
|
14207
14207
|
"os-locale": {
|
14208
14208
|
"version": "1.4.0",
|
14209
|
-
"resolved": "
|
14209
|
+
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
14210
14210
|
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
|
14211
14211
|
"dev": true,
|
14212
14212
|
"requires": {
|
@@ -14235,7 +14235,7 @@
|
|
14235
14235
|
},
|
14236
14236
|
"pify": {
|
14237
14237
|
"version": "2.3.0",
|
14238
|
-
"resolved": "
|
14238
|
+
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
14239
14239
|
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
14240
14240
|
"dev": true
|
14241
14241
|
},
|
@@ -15687,11 +15687,11 @@
|
|
15687
15687
|
}
|
15688
15688
|
},
|
15689
15689
|
"url-parse": {
|
15690
|
-
"version": "1.
|
15691
|
-
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.
|
15692
|
-
"integrity": "sha512
|
15690
|
+
"version": "1.5.0",
|
15691
|
+
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.0.tgz",
|
15692
|
+
"integrity": "sha512-9iT6N4s93SMfzunOyDPe4vo4nLcSu1yq0IQK1gURmjm8tQNlM6loiuCRrKG1hHGXfB2EWd6H4cGi7tGdaygMFw==",
|
15693
15693
|
"requires": {
|
15694
|
-
"querystringify": "^2.
|
15694
|
+
"querystringify": "^2.1.1",
|
15695
15695
|
"requires-port": "^1.0.0"
|
15696
15696
|
}
|
15697
15697
|
},
|
data/views/mdc/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: voom-presenters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Russell Edens
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ice_nine
|
@@ -391,6 +391,7 @@ files:
|
|
391
391
|
- app/demo/events/content_as_form.pom
|
392
392
|
- app/demo/events/field_level.pom
|
393
393
|
- app/demo/events/form_level.pom
|
394
|
+
- app/demo/events/halted.pom
|
394
395
|
- app/demo/events/nav/drawer.pom
|
395
396
|
- app/demo/events/parallel.pom
|
396
397
|
- app/demo/events/tagged_input.pom
|
@@ -712,6 +713,7 @@ files:
|
|
712
713
|
- views/mdc/assets/js/utils/compatibility.js
|
713
714
|
- views/mdc/assets/js/utils/config.js
|
714
715
|
- views/mdc/assets/js/utils/config.test.js
|
716
|
+
- views/mdc/assets/js/utils/form-data.js
|
715
717
|
- views/mdc/assets/js/utils/urls.js
|
716
718
|
- views/mdc/assets/js/wc.js
|
717
719
|
- views/mdc/assets/scss/app.scss
|