opening_hours
Version:
Library to parse and process opening_hours tag from OpenStreetMap data
245 lines (201 loc) • 10.2 kB
JavaScript
var OpeningHoursTable = {
// JS functions for generating the table {{{
// In English. Localization is done somewhere else (above).
months: ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'],
weekdays: ['su','mo','tu','we','th','fr','sa'],
formatdate: function (now, nextchange, from) {
var now_daystart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
var nextdays = (nextchange.getTime() - now_daystart.getTime()) / 1000 / 60 / 60 / 24;
var timediff = '';
var delta = Math.floor((nextchange.getTime() - now.getTime()) / 1000 / 60); // delta is minutes
if (delta < 60)
timediff = i18next.t("words.in duration") +' '+ delta + ' ' + this.plural(delta, 'words.time.minute');
var deltaminutes = delta % 60;
delta = Math.floor(delta / 60); // delta is now hours
if (delta < 48 && timediff === '')
timediff = i18next.t("words.in duration") +' '+ delta + ' ' + this.plural(delta, 'words.time.hour')
+' '+ i18next.t('words.time.hours minutes sep') + this.pad(deltaminutes) + ' ' + this.plural(deltaminutes, 'words.time.minute');
var deltahours = delta % 24;
delta = Math.floor(delta / 24); // delta is now days
if (delta < 14 && timediff === '')
timediff = i18next.t("words.in duration") +' '+ delta + ' ' + this.plural(delta, 'words.time.day')
+ ' ' + deltahours + ' ' + this.plural(deltahours, 'words.time.hour')
else if (timediff === '')
timediff = i18next.t("words.in duration") +' '+ delta + ' ' + this.plural(delta, 'words.time.day');
var atday = '';
if (from ? (nextdays < 1) : (nextdays <= 1))
atday = i18next.t('words.today');
else if (from ? (nextdays < 2) : (nextdays <= 2))
atday = i18next.t('words.tomorrow');
else if (from ? (nextdays < 7) : (nextdays <= 7)) {
if (i18next.exists('weekdays.days next week.' + this.weekdays[nextchange.getDay()])) {
atday = i18next.t('weekdays.days next week.' + this.weekdays[nextchange.getDay()], {
day: nextchange.toLocaleString(i18next.language, {weekday: 'long'})
});
} else {
atday = i18next.t('weekdays.day next week', {
day: nextchange.toLocaleString(i18next.language, {weekday: 'long'})
});
}
}
var month_name = nextchange.toLocaleString(i18next.language, {month: 'long'});
var month_name_match = month_name.match(/\(([^|]+?)\|.*\)/);
if (month_name_match && typeof month_name_match[1] === 'string') {
/* The language has multiple words for the month (nominative, subjective).
* Use the first one.
* https://github.com/opening-hours/opening_hours_map/issues/41
*/
month_name = month_name_match[1];
}
var atdate = nextchange.getDate() + ' ' + month_name;
var res = [];
if (atday !== '') res.push(atday);
if (atdate !== '') res.push(atdate);
if (timediff !== '') res.push(timediff);
return res.join(', ');
},
pad: function (n) { return n < 10 ? '0'+n : n; },
plural: function (n, trans_base) {
return i18next.t(trans_base, {count: n}); // Correct i18next plural function call
/*if (n === 1) {
return i18next.t(trans_base); // singular form
} else if (n < 2) { // FIXME: Is this correct for Russian?
return i18next.t(trans_base + ' many');
} else {
return i18next.t(trans_base + '_plural');
}*/
},
printDate: function (date) {
// return date.toLocaleDateString('en-CA');
return date.getFullYear()+'-'
+ this.pad(date.getMonth()+1)+'-'
+ this.pad(date.getDate());
},
printTime: function (date) {
// return date.toLocaleTimeString('de');
return this.pad(date.getHours())+':'
+ this.pad(date.getMinutes())+':'
+ this.pad(date.getSeconds());
},
drawTable: function (it, date_today, has_next_change) {
var date_today = new Date(date_today);
date_today.setHours(0, 0, 0, 0);
var date = new Date(date_today);
// date.setDate(date.getDate() - date.getDay() + 7);
date.setDate(date.getDate() - date.getDay() - 1); // start at begin of the week
var table = [];
for (var row = 0; row < 7; row++) {
date.setDate(date.getDate()+1);
// if (date.getDay() === date_today.getDay()) {
// date.setDate(date.getDate()-7);
// }
it.setDate(date);
var is_open = it.getState();
var unknown = it.getUnknown();
var state_string = it.getStateString(false);
var prevdate = date;
var curdate = date;
// console.log(state_string, is_open, unknown, date.toString());
table[row] = {
date: new Date(date),
times: '',
text: []
};
while (has_next_change && it.advance() && curdate.getTime() - date.getTime() < 24*60*60*1000) {
curdate = it.getDate();
var fr = prevdate.getTime() - date.getTime();
var to = curdate.getTime() - date.getTime();
if (to > 24*60*60*1000)
to = 24*60*60*1000;
fr *= 100/1000/60/60/24;
to *= 100/1000/60/60/24;
table[row].times += '<div class="timebar ' + (is_open ? 'open' : (unknown ? 'unknown' : 'closed'))
+ '" style="width:' + (to-fr) + '%"></div>';
if (is_open || unknown) {
var text = i18next.t('words.' + state_string) + ' ' +
i18next.t('words.from') + ' ' + this.printTime(prevdate) +
' ' + i18next.t('words.to') + ' ';
if (prevdate.getDay() !== curdate.getDay())
text += '24:00';
else
text += this.printTime(curdate);
table[row].text.push(text);
}
prevdate = curdate;
is_open = it.getState();
unknown = it.getUnknown();
state_string = it.getStateString(false);
}
if (!has_next_change && table[row].text.length === 0) { // 24/7
table[row].times += '<div class="timebar ' + (is_open ? 'open' : (unknown ? 'unknown' : 'closed'))
+ '" style="width:100%"></div>';
if (is_open)
table[row].text.push(i18next.t('words.open') + ' 00:00 ' + i18next.t('words.to') + ' 24:00');
}
}
var output = '';
output += '<table>';
for (var row in table) {
var today = table[row].date.getDay() === date_today.getDay();
var endweek = ((table[row].date.getDay() + 1) % 7) === date_today.getDay();
var cl = today ? ' class="today"' : (endweek ? ' class="endweek"' : '');
// if (today && date_today.getDay() !== 1)
// output += '<tr class="separator"><td colspan="3"></td></tr>';
output += '<tr' + cl + '><td class="day ' + (table[row].date.getDay() % 6 === 0 ? 'weekend' : 'workday') + '">';
output += this.printDate(table[row].date);
output += '</td><td class="times">';
output += table[row].times;
output += '</td><td>';
output += table[row].text.join(', ') || ' ';
output += '</td></tr>';
}
output += '</table>';
return output;
},
getReadableState: function (startString, endString, oh, past) {
if (past === true) past = 'd';
else past = '';
var output = '';
return startString + output + endString + '.';
},
drawTableAndComments: function (oh, it, value) {
var prevdate = it.getDate();
var is_open = it.getState();
var unknown = it.getUnknown();
var state_string = it.getStateString(false);
var state_string_past = it.getStateString(true);
var comment = it.getComment();
var has_next_change = it.advance();
var output = '';
output += '<p class="' + state_string_past + '">'
+ i18next.t('texts.' + state_string_past+ ' ' + (has_next_change ? 'now' : 'always'));
if (typeof comment !== 'undefined') {
if (unknown) {
output += i18next.t('texts.depends on', { comment: '"' + comment + '"' });
} else {
output += ', ' + i18next.t('words.comment') + ': "' + comment + '"';
}
}
output += '</p>';
if (has_next_change) {
var time_diff = it.getDate().getTime() - prevdate.getTime();
time_diff = (time_diff) / 1000;
time_diff += 60; // go one second after
output += '<p class="' + it.getStateString(true) + '">'
+ i18next.t('texts.will ' + it.getStateString(false), {
timestring: this.formatdate(prevdate, it.getDate(), true),
href: 'javascript:Evaluate(' + time_diff + ', false, \'' + value + '\')',
comment: ((typeof it.getComment() === 'string' || typeof comment === 'string')
? ', ' + i18next.t('words.comment') + ': ' + ((typeof it.getComment() === 'string') ? '"' + it.getComment() + '"' : i18next.t('words.undefined'))
: ''),
}) + '</p>';
}
output += this.drawTable(it, prevdate, has_next_change);
if (oh.isWeekStable())
output += '<p><b>'+ i18next.t('texts.week stable') +'</b></p>';
else
output += '<p><b>'+ i18next.t('texts.not week stable') +'</b></p>';
return output;
},
// }}}
}