ssr for valueAsDate bindings

pull/3527/head
Richard Harris 6 years ago
parent 03df401856
commit 8432950f53

@ -585,7 +585,7 @@ export default class Element extends Node {
const type = (check_type_attribute() as string);
const valid_date_inputs = new Set(['date', 'datetime-local', 'time', 'month', 'week']);
const valid_date_inputs = new Set(['date', 'time', 'month', 'week']);
if (!valid_date_inputs.has(type)) {
component.error(binding, {

@ -162,6 +162,11 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
} else if (binding.name === 'value' && node.name === 'textarea') {
const snippet = snip(expression);
node_contents = '${(' + snippet + ') || ""}';
} else if (binding.name === 'valueAsDate') {
const snippet = snip(expression);
const type = node.get_static_attribute_value('type');
const fn = `${type}_input_value`;
opening_tag += '${@add_attribute("value", @' + fn + '(' + snippet + '), 1)}';
} else {
const snippet = snip(expression);
opening_tag += '${@add_attribute("' + name + '", ' + snippet + ', 1)}';

@ -125,22 +125,6 @@ export function to_number(value) {
return value === '' ? undefined : +value;
}
export function value_as_date(value) {
const valueAsDate = new Date(value);
return isNaN(valueAsDate.getTime()) ? undefined : valueAsDate;
}
export function date_as_value(date) {
const validDate = Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime());
if (!validDate) {
return '';
}
const yyyy = date.getUTCFullYear();
const mm = date.getUTCMonth() + 1 < 10 ? `0${date.getUTCMonth() + 1}` : date.getUTCMonth() + 1;
const dd = date.getUTCDate() < 10 ? `0${date.getUTCDate()}` : date.getUTCDate();
return `${yyyy}-${mm}-${dd}`;
}
export function time_ranges_to_array(ranges) {
const array = [];
for (let i = 0; i < ranges.length; i += 1) {
@ -190,9 +174,7 @@ export function set_data(text, data) {
}
export function set_input_value(input, value) {
if (Object.prototype.toString.call(value) === '[object Date]') {
input.value = date_as_value(value);
} else if (value != null || input.value) {
if (value != null || input.value) {
input.value = value;
}
}

@ -127,4 +127,68 @@ export function add_attribute(name, value, boolean) {
export function add_classes(classes) {
return classes ? ` class="${classes}"` : ``;
}
}
function is_date(value) {
return value instanceof Date;
}
function pad(n, len = 2) {
n = String(n);
while (n.length < len) n = `0${n}`;
return n;
}
export function date_input_value(date) {
if (!is_date(date)) return '';
const yyyy = date.getUTCFullYear();
const mm = pad(date.getUTCMonth() + 1);
const dd = pad(date.getUTCDate());
return `${yyyy}-${mm}-${dd}`;
}
export function month_input_value(date) {
if (!is_date(date)) return '';
const yyyy = date.getUTCFullYear();
const mm = pad(date.getUTCMonth() + 1);
return `${yyyy}-${mm}`;
}
export function time_input_value(date) {
if (!is_date(date)) return '';
const HH = pad(date.getHours());
const mm = pad(date.getMinutes());
let str = `${HH}:${mm}`;
let s, S;
if (s = date.getSeconds()) str += `:${pad(s)}`;
if (S = date.getMilliseconds()) str += `:${pad(S, 3)}`;
return str;
}
const ONE_WEEK = 1000 * 60 * 60 * 24 * 7;
const to_day = (date, target) => {
const day = date.getUTCDay() || 7;
date.setDate(date.getDate() - (day - target));
};
export const week_input_value = date => {
date = new Date(date);
to_day(date, 4); // pretend it's Thursday to figure out which year we should use
const year = date.getUTCFullYear();
const start = new Date(year, 0, 4); // week 1 always contains Jan 4
to_day(start, 1); // weeks start on Mondays
const elapsed = Math.floor((date - start.getTime()) / ONE_WEEK);
return `${year}-W${pad(elapsed + 1)}`;
};

@ -0,0 +1,63 @@
const SEP_2019_INPUT_VALUE = '2019-09';
const SEP_2019_DATE_VALUE = new Date(SEP_2019_INPUT_VALUE);
const OCT_2019_INPUT_VALUE = '2019-10';
const OCT_2019_DATE_VALUE = new Date(OCT_2019_INPUT_VALUE);
export default {
props: {
month: SEP_2019_DATE_VALUE
},
html: `
<input type=month>
<p>[object Date] ${SEP_2019_DATE_VALUE}</p>
`,
ssrHtml: `
<input type=month value='${SEP_2019_INPUT_VALUE}'>
<p>[object Date] ${SEP_2019_DATE_VALUE}</p>
`,
async test({ assert, component, target, window }) {
const input = target.querySelector('input');
// https://github.com/jsdom/jsdom/issues/2658
// assert.equal(input.value, SEP_2019_INPUT_VALUE);
assert.equal(component.month.toString(), SEP_2019_DATE_VALUE.toString());
const event = new window.Event('input');
// https://github.com/jsdom/jsdom/issues/2658
// input.value = OCT_2019_INPUT_VALUE;
input.valueAsDate = OCT_2019_DATE_VALUE;
await input.dispatchEvent(event);
assert.equal(component.month.toString(), OCT_2019_DATE_VALUE.toString());
assert.htmlEqual(target.innerHTML, `
<input type='month'>
<p>[object Date] ${OCT_2019_DATE_VALUE}</p>
`);
component.month = SEP_2019_DATE_VALUE;
// https://github.com/jsdom/jsdom/issues/2658
// assert.equal(input.value, SEP_2019_INPUT_VALUE);
assert.equal(input.valueAsDate.toString(), SEP_2019_DATE_VALUE.toString());
assert.htmlEqual(target.innerHTML, `
<input type='month'>
<p>[object Date] ${SEP_2019_DATE_VALUE}</p>
`);
// https://github.com/jsdom/jsdom/issues/2658
// empty string should be treated as undefined
// input.value = '';
input.valueAsDate = null;
await input.dispatchEvent(event);
assert.equal(component.month, null);
assert.htmlEqual(target.innerHTML, `
<input type='month'>
<p>[object Null] null</p>
`);
},
};

@ -0,0 +1,6 @@
<script>
export let month;
</script>
<input type="month" bind:valueAsDate={month}>
<p>{Object.prototype.toString.call(month)} {month}</p>

@ -0,0 +1,48 @@
const LUNCHTIME = new Date(1970, 0, 1, 12, 30);
const TEATIME = new Date(1970, 0, 1, 12, 30);
export default {
props: {
time: LUNCHTIME
},
html: `
<input type=time>
<p>[object Date] ${LUNCHTIME}</p>
`,
ssrHtml: `
<input type=time value='12:30'>
<p>[object Date] ${LUNCHTIME}</p>
`,
async test({ assert, component, target, window }) {
const input = target.querySelector('input');
const event = new window.Event('input');
input.valueAsDate = TEATIME;
await input.dispatchEvent(event);
assert.equal(component.time.toString(), TEATIME.toString());
assert.htmlEqual(target.innerHTML, `
<input type='time'>
<p>[object Date] ${TEATIME}</p>
`);
component.time = LUNCHTIME;
assert.equal(input.valueAsDate.toString(), LUNCHTIME.toString());
assert.htmlEqual(target.innerHTML, `
<input type='time'>
<p>[object Date] ${LUNCHTIME}</p>
`);
input.valueAsDate = null;
await input.dispatchEvent(event);
assert.equal(component.time, null);
assert.htmlEqual(target.innerHTML, `
<input type='time'>
<p>[object Null] null</p>
`);
},
};

@ -0,0 +1,6 @@
<script>
export let time;
</script>
<input type="time" bind:valueAsDate={time}>
<p>{Object.prototype.toString.call(time)} {time}</p>

@ -0,0 +1,63 @@
const SEP_W36_2019_INPUT_VALUE = '2019-W36';
const SEP_W36_2019_DATE_VALUE = new Date('2019-09-03');
const W41_2019_INPUT_VALUE = '2019-10-07';
const W41_2019_DATE_VALUE = new Date(W41_2019_INPUT_VALUE);
export default {
props: {
week: SEP_W36_2019_DATE_VALUE
},
html: `
<input type=week>
<p>[object Date] ${SEP_W36_2019_DATE_VALUE}</p>
`,
ssrHtml: `
<input type=week value='${SEP_W36_2019_INPUT_VALUE}'>
<p>[object Date] ${SEP_W36_2019_DATE_VALUE}</p>
`,
async test({ assert, component, target, window }) {
const input = target.querySelector('input');
// https://github.com/jsdom/jsdom/issues/2658
// assert.equal(input.value, SEP_W36_2019_INPUT_VALUE);
assert.equal(component.week.toString(), SEP_W36_2019_DATE_VALUE.toString());
const event = new window.Event('input');
// https://github.com/jsdom/jsdom/issues/2658
// input.value = W41_2019_INPUT_VALUE;
input.valueAsDate = W41_2019_DATE_VALUE;
await input.dispatchEvent(event);
assert.equal(component.week.toString(), W41_2019_DATE_VALUE.toString());
assert.htmlEqual(target.innerHTML, `
<input type='week'>
<p>[object Date] ${W41_2019_DATE_VALUE}</p>
`);
component.week = SEP_W36_2019_DATE_VALUE;
// https://github.com/jsdom/jsdom/issues/2658
// assert.equal(input.value, SEP_W36_2019_INPUT_VALUE);
assert.equal(input.valueAsDate.toString(), SEP_W36_2019_DATE_VALUE.toString());
assert.htmlEqual(target.innerHTML, `
<input type='week'>
<p>[object Date] ${SEP_W36_2019_DATE_VALUE}</p>
`);
// https://github.com/jsdom/jsdom/issues/2658
// empty string should be treated as undefined
// input.value = '';
input.valueAsDate = null;
await input.dispatchEvent(event);
assert.equal(component.week, null);
assert.htmlEqual(target.innerHTML, `
<input type='week'>
<p>[object Null] null</p>
`);
},
};

@ -0,0 +1,6 @@
<script>
export let week;
</script>
<input type="week" bind:valueAsDate={week}>
<p>{Object.prototype.toString.call(week)} {week}</p>
Loading…
Cancel
Save