Skip to content

Commit

Permalink
#64 SuperDatePicker seems to work with server-side pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
vaadin-miki committed May 28, 2020
1 parent 8d21102 commit a7eec0f
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.JsModule;
import org.slf4j.LoggerFactory;
import org.vaadin.miki.markers.HasLabel;
import org.vaadin.miki.markers.HasLocale;
import org.vaadin.miki.markers.HasPlaceholder;
Expand Down Expand Up @@ -108,25 +107,20 @@ public final void setLocale(Locale locale) {
protected String formatDate(int year, int month, int day) {
if(this.getDatePattern() == null)
throw new IllegalStateException("formatDate() called when there is no date pattern set");
LoggerFactory.getLogger(this.getClass()).warn("formatting date {}-{}-{}", year, month, day);
String result = this.getDatePattern().formatDate(LocalDate.of(year, month, day));
LoggerFactory.getLogger(this.getClass()).warn("formatted date {}", result);
return result;
return this.getDatePattern().formatDate(LocalDate.of(year, month, day));
}

/**
* Parses the date.
* @param formattedDate The date in whatever format was output by {@link #formatDate(int, int, int)} or entered by the user.
* @return String formatted as {@code YYYY-MM-DD}, using exactly four digits for year, exactly two digits for month ({@code 1} for January, {@code 12} for December) and exactly two digits for day.
* @return String formatted as {@code YYYY-MM-DD}, using exactly four digits for year, exactly two digits for month ({@code 1} for January, {@code 12} for December) and exactly two digits for day; or an empty string if parsing resulted in an error.
* @throws IllegalStateException when {@link #getDatePattern()} is {@code null}.
*/
@ClientCallable
protected String parseDate(String formattedDate) {
if(this.getDatePattern() == null)
throw new IllegalStateException("parseDate() called when there is no date pattern set");
LoggerFactory.getLogger(this.getClass()).warn("parsing date {}", formattedDate);
final LocalDate result = this.getDatePattern().parseDate(formattedDate);
LoggerFactory.getLogger(this.getClass()).warn("parsed as {}", result);
if(result == null)
return "";
else return String.format("%04d-%02d-%02d", result.getYear(), result.getMonthValue(), result.getDayOfMonth());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,56 @@ export class DatePatternMixin {
hasServer = datepicker;
}
console.log('SDP: MAIN - set display pattern');
if (displayPattern === null) {
console.log("SDP: clearing date display pattern");
let wasServer = (datepicker.i18n.dateDisplayPattern === '$server');
datepicker.i18n.dateDisplayPattern = '';
if (datepicker.noPatternParseAndFormat) {
datepicker.set('i18n.parseDate', datepicker.noPatternParseAndFormat[0]);
datepicker.set('i18n.formatDate', datepicker.noPatternParseAndFormat[1]);
// explicitly update the pattern when server callback was used
// no idea why it is needed, but probably because of some async stuff?
if (wasServer) {
datepicker.shadowRoot.querySelector('#input').value = datepicker.noPatternParseAndFormat[1](datepicker._parseDate(datepicker.value));
}
delete datepicker.noPatternParseAndFormat;
}
}
// needs server callback
// there is some magic here, because server callbacks are asynchronous (return promises)
// and of course the rest of the code is totally synchronous
// this solution is probably far from ideal, but it seems to work :)
else if (displayPattern === '$server') {
let parseOnServer;
let formatOnServer;
formatOnServer = function(date) {
datepicker.set('i18n.parseDate', d => date);
console.log('SDP: querying server for formatting date');
hasServer.$server.formatDate(date.year, date.month+1, date.day).then(formatted => {
console.log('SDP: value formatted as '+formatted);
datepicker.shadowRoot.querySelector('#input').value = formatted;
datepicker.value = date;
datepicker.set('i18n.parseDate', parseOnServer);
});
return datepicker._formatISO(date);
}

parseOnServer = function(text) {
console.log('SDP: querying server for parsing date from <'+text+'>');
if (text !== undefined && text !== null && text.length > 0) {
datepicker.set('i18n.formatDate', t => text);
hasServer.$server.parseDate(text).then(parsed => {
datepicker.value = parsed;
datepicker.set('i18n.formatDate', formatOnServer);
});
}
return null;
}

datepicker.set('i18n.formatDate', formatOnServer);
datepicker.set('i18n.parseDate', parseOnServer);
}
// no callback needed:
// pattern is a string, first character is a separator
// next six characters define, in groups of 2, the order and what should be displayed
// 0d or _d - (zero prefixed) day
Expand All @@ -44,15 +94,7 @@ export class DatePatternMixin {
// + or - - corresponds to previous century in short year (+ when true, - when false)
// XX - number corresponding to the default century in short years: MUST BE TWO DIGITS
// YY - number corresponding to the boundary year: MUST BE TWO DIGITS
if (displayPattern === null) {
console.log("SDP: clearing date display pattern");
datepicker.i18n.dateDisplayPattern = '';
if (datepicker.noPatternParseAndFormat) {
datepicker.set('i18n.parseDate', datepicker.noPatternParseAndFormat[0]);
datepicker.set('i18n.formatDate', datepicker.noPatternParseAndFormat[1]);
delete datepicker.noPatternParseAndFormat;
}
} else {
else {
console.log('SDP: setting date display pattern to <' + displayPattern + '>');
datepicker.i18n.dateDisplayPattern = displayPattern;
if (!datepicker.noPatternParseAndFormat) {
Expand All @@ -61,93 +103,58 @@ export class DatePatternMixin {
datepicker.set('i18n.formatDate', date => {
// debugger;
const ddp = datepicker.i18n.dateDisplayPattern;
if (ddp === '$server') {
console.log('SDP: server-side formatting requested for ['+JSON.stringify(date)+']');
if (datepicker.serverFormattingDate === undefined) {
datepicker.serverFormattingDate = date;
return hasServer.$server.formatDate(date.year, date.month + 1, date.day).then(fromServer => {
console.log('SDP: server-side formatting returned ' + fromServer + ' with date ' + JSON.stringify(date));
datepicker.shadowRoot.querySelector('#input').value = fromServer;
datepicker.serverParsingDate = fromServer;
datepicker.value = date;
delete datepicker.serverFormattingDate;
});
}
else {
return datepicker.noPatternParseAndFormat[1](date);
console.log('SDP: custom formatting for ' + ddp + ' and date <'+ JSON.stringify(date) + '>');
return [ddp.substr(1, 2), ddp.substr(3, 2), ddp.substr(5, 2)].map(part => {
if (part === '0d') {
return String(date.day).padStart(2, '0')
} else if (part === '_d') {
return String(date.day)
} else if (part === '0M') {
return String(date.month + 1).padStart(2, '0')
} else if (part === '_M') {
return String(date.month + 1)
} else if (part === '0y') {
return date.year < 10 ? '0' + String(date.year) : String(date.year).substr(-2)
} else if (part === '_y') {
return String(date.year)
}
}
else {
console.log('SDP: custom formatting for ' + ddp + ' and date <'+ JSON.stringify(date) + '>');
return [ddp.substr(1, 2), ddp.substr(3, 2), ddp.substr(5, 2)].map(part => {
if (part === '0d') {
return String(date.day).padStart(2, '0')
} else if (part === '_d') {
return String(date.day)
} else if (part === '0M') {
return String(date.month + 1).padStart(2, '0')
} else if (part === '_M') {
return String(date.month + 1)
} else if (part === '0y') {
return date.year < 10 ? '0' + String(date.year) : String(date.year).substr(-2)
} else if (part === '_y') {
return String(date.year)
}
}).join(ddp[0]);
}
}).join(ddp[0]);
});
datepicker.set('i18n.parseDate', text => {
// debugger;
const ddp = datepicker.i18n.dateDisplayPattern;
if (ddp === '$server') {
// store text to prevent loops
if (datepicker.serverParsingDate === undefined) {
datepicker.serverParsingDate = text;
if (text !== undefined && text !== null && text.length > 0) {
console.log('SDP: server-side parsing required for <' + text + '>');
hasServer.$server.parseDate(text).then(fromServer => {
console.log('SDP: server-side returned ' + fromServer);
delete datepicker.serverParsingDate;
datepicker.value = fromServer;
});
console.log('SDP: custom parsing for ' + ddp + ' and text <' + text + '>');
const today = new Date();
let date, month = today.getMonth(), year = today.getFullYear();
const parts = text.split(ddp[0]);
if (parts.length === 3) {
// d, M, y can be at index 2, 4 or 6 in the pattern
year = parseInt(parts[(ddp.indexOf('y') / 2) - 1]);
month = parseInt(parts[(ddp.indexOf('M') / 2) - 1]) - 1;
date = parseInt(parts[(ddp.indexOf('d') / 2) - 1]);
// now, if short year is used
if (ddp.indexOf('0y') !== -1) {
const boundaryYear = parseInt(ddp.substr(-2));
const defaultCentury = parseInt(ddp.substr(-4, 2));
if (year < boundaryYear) {
year += (ddp[7] === '+' ? defaultCentury - 2 : defaultCentury - 1) * 100;
} else if (year < 100) {
year += (ddp[7] === '+' ? defaultCentury - 2 : defaultCentury - 1) * 100;
}
}
return datepicker.noPatternParseAndFormat[0](text);
}
else {
console.log('SDP: custom parsing for ' + ddp + ' and text <' + text + '>');
const today = new Date();
let date, month = today.getMonth(), year = today.getFullYear();
const parts = text.split(ddp[0]);
if (parts.length === 3) {
// d, M, y can be at index 2, 4 or 6 in the pattern
year = parseInt(parts[(ddp.indexOf('y') / 2) - 1]);
month = parseInt(parts[(ddp.indexOf('M') / 2) - 1]) - 1;
date = parseInt(parts[(ddp.indexOf('d') / 2) - 1]);
// now, if short year is used
if (ddp.indexOf('0y') !== -1) {
const boundaryYear = parseInt(ddp.substr(-2));
const defaultCentury = parseInt(ddp.substr(-4, 2));
if (year < boundaryYear) {
year += (ddp[7] === '+' ? defaultCentury - 2 : defaultCentury - 1) * 100;
} else if (year < 100) {
year += (ddp[7] === '+' ? defaultCentury - 2 : defaultCentury - 1) * 100;
}
}
} else if (parts.length === 2) {
if (ddp.indexOf('d') < ddp.indexOf('M')) {
date = parseInt(parts[0]);
month = parseInt(parts[1]) - 1;
} else {
date = parseInt(parts[1]);
month = parseInt(parts[0]) - 1;
}
} else if (parts.length === 1) {
} else if (parts.length === 2) {
if (ddp.indexOf('d') < ddp.indexOf('M')) {
date = parseInt(parts[0]);
month = parseInt(parts[1]) - 1;
} else {
date = parseInt(parts[1]);
month = parseInt(parts[0]) - 1;
}
if (date !== undefined) {
return {day: date, month, year};
}
} else if (parts.length === 1) {
date = parseInt(parts[0]);
}
if (date !== undefined) {
return {day: date, month, year};
}
});
}
Expand Down

0 comments on commit a7eec0f

Please sign in to comment.