voom-presenters 2.1.0 → 2.1.2
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 +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
|