mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-07-15 01:11:15 +08:00
229 lines
6.0 KiB
JavaScript
229 lines
6.0 KiB
JavaScript
|
|
// Single Date Formatting
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
|
|
// call this if you want Moment's original format method to be used
|
|
function momentFormat(mom, formatStr) {
|
|
return moment.fn.format.call(mom, formatStr);
|
|
}
|
|
|
|
|
|
// Formats `date` with a Moment formatting string, but allow our non-zero areas and
|
|
// additional token.
|
|
function formatDate(date, formatStr) {
|
|
return formatDateWithChunks(date, getFormatStringChunks(formatStr));
|
|
}
|
|
|
|
|
|
function formatDateWithChunks(date, chunks) {
|
|
var s = '';
|
|
var i;
|
|
|
|
for (i=0; i<chunks.length; i++) {
|
|
s += formatDateWithChunk(date, chunks[i]);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
// addition formatting tokens we want recognized
|
|
var tokenOverrides = {
|
|
t: function(date) { // "a" or "p"
|
|
return momentFormat(date, 'a').charAt(0);
|
|
},
|
|
T: function(date) { // "A" or "P"
|
|
return momentFormat(date, 'A').charAt(0);
|
|
}
|
|
};
|
|
|
|
|
|
function formatDateWithChunk(date, chunk) {
|
|
var token;
|
|
var maybeStr;
|
|
|
|
if (typeof chunk === 'string') { // a literal string
|
|
return chunk;
|
|
}
|
|
else if ((token = chunk.token)) { // a token, like "YYYY"
|
|
if (tokenOverrides[token]) {
|
|
return tokenOverrides[token](date); // use our custom token
|
|
}
|
|
return momentFormat(date, token);
|
|
}
|
|
else if (chunk.maybe) { // a grouping of other chunks that must be non-zero
|
|
maybeStr = formatDateWithChunks(date, chunk.maybe);
|
|
if (maybeStr.match(/[1-9]/)) {
|
|
return maybeStr;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
|
|
// Date Range Formatting
|
|
// -------------------------------------------------------------------------------------------------
|
|
// TODO: make it work with timezone offset
|
|
|
|
// Using a formatting string meant for a single date, generate a range string, like
|
|
// "Sep 2 - 9 2013", that intelligently inserts a separator where the dates differ.
|
|
// If the dates are the same as far as the format string is concerned, just return a single
|
|
// rendering of one date, without any separator.
|
|
function formatRange(date1, date2, formatStr, separator, isRTL) {
|
|
var localeData;
|
|
|
|
date1 = fc.moment.parseZone(date1);
|
|
date2 = fc.moment.parseZone(date2);
|
|
|
|
localeData = (date1.localeData || date1.lang).call(date1); // works with moment-pre-2.8
|
|
|
|
// Expand localized format strings, like "LL" -> "MMMM D YYYY"
|
|
formatStr = localeData.longDateFormat(formatStr) || formatStr;
|
|
// BTW, this is not important for `formatDate` because it is impossible to put custom tokens
|
|
// or non-zero areas in Moment's localized format strings.
|
|
|
|
separator = separator || ' - ';
|
|
|
|
return formatRangeWithChunks(
|
|
date1,
|
|
date2,
|
|
getFormatStringChunks(formatStr),
|
|
separator,
|
|
isRTL
|
|
);
|
|
}
|
|
fc.formatRange = formatRange; // expose
|
|
|
|
|
|
function formatRangeWithChunks(date1, date2, chunks, separator, isRTL) {
|
|
var chunkStr; // the rendering of the chunk
|
|
var leftI;
|
|
var leftStr = '';
|
|
var rightI;
|
|
var rightStr = '';
|
|
var middleI;
|
|
var middleStr1 = '';
|
|
var middleStr2 = '';
|
|
var middleStr = '';
|
|
|
|
// Start at the leftmost side of the formatting string and continue until you hit a token
|
|
// that is not the same between dates.
|
|
for (leftI=0; leftI<chunks.length; leftI++) {
|
|
chunkStr = formatSimilarChunk(date1, date2, chunks[leftI]);
|
|
if (chunkStr === false) {
|
|
break;
|
|
}
|
|
leftStr += chunkStr;
|
|
}
|
|
|
|
// Similarly, start at the rightmost side of the formatting string and move left
|
|
for (rightI=chunks.length-1; rightI>leftI; rightI--) {
|
|
chunkStr = formatSimilarChunk(date1, date2, chunks[rightI]);
|
|
if (chunkStr === false) {
|
|
break;
|
|
}
|
|
rightStr = chunkStr + rightStr;
|
|
}
|
|
|
|
// The area in the middle is different for both of the dates.
|
|
// Collect them distinctly so we can jam them together later.
|
|
for (middleI=leftI; middleI<=rightI; middleI++) {
|
|
middleStr1 += formatDateWithChunk(date1, chunks[middleI]);
|
|
middleStr2 += formatDateWithChunk(date2, chunks[middleI]);
|
|
}
|
|
|
|
if (middleStr1 || middleStr2) {
|
|
if (isRTL) {
|
|
middleStr = middleStr2 + separator + middleStr1;
|
|
}
|
|
else {
|
|
middleStr = middleStr1 + separator + middleStr2;
|
|
}
|
|
}
|
|
|
|
return leftStr + middleStr + rightStr;
|
|
}
|
|
|
|
|
|
var similarUnitMap = {
|
|
Y: 'year',
|
|
M: 'month',
|
|
D: 'day', // day of month
|
|
d: 'day', // day of week
|
|
// prevents a separator between anything time-related...
|
|
A: 'second', // AM/PM
|
|
a: 'second', // am/pm
|
|
T: 'second', // A/P
|
|
t: 'second', // a/p
|
|
H: 'second', // hour (24)
|
|
h: 'second', // hour (12)
|
|
m: 'second', // minute
|
|
s: 'second' // second
|
|
};
|
|
// TODO: week maybe?
|
|
|
|
|
|
// Given a formatting chunk, and given that both dates are similar in the regard the
|
|
// formatting chunk is concerned, format date1 against `chunk`. Otherwise, return `false`.
|
|
function formatSimilarChunk(date1, date2, chunk) {
|
|
var token;
|
|
var unit;
|
|
|
|
if (typeof chunk === 'string') { // a literal string
|
|
return chunk;
|
|
}
|
|
else if ((token = chunk.token)) {
|
|
unit = similarUnitMap[token.charAt(0)];
|
|
// are the dates the same for this unit of measurement?
|
|
if (unit && date1.isSame(date2, unit)) {
|
|
return momentFormat(date1, token); // would be the same if we used `date2`
|
|
// BTW, don't support custom tokens
|
|
}
|
|
}
|
|
|
|
return false; // the chunk is NOT the same for the two dates
|
|
// BTW, don't support splitting on non-zero areas
|
|
}
|
|
|
|
|
|
// Chunking Utils
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
|
|
var formatStringChunkCache = {};
|
|
|
|
|
|
function getFormatStringChunks(formatStr) {
|
|
if (formatStr in formatStringChunkCache) {
|
|
return formatStringChunkCache[formatStr];
|
|
}
|
|
return (formatStringChunkCache[formatStr] = chunkFormatString(formatStr));
|
|
}
|
|
|
|
|
|
// Break the formatting string into an array of chunks
|
|
function chunkFormatString(formatStr) {
|
|
var chunks = [];
|
|
var chunker = /\[([^\]]*)\]|\(([^\)]*)\)|(LT|(\w)\4*o?)|([^\w\[\(]+)/g; // TODO: more descrimination
|
|
var match;
|
|
|
|
while ((match = chunker.exec(formatStr))) {
|
|
if (match[1]) { // a literal string inside [ ... ]
|
|
chunks.push(match[1]);
|
|
}
|
|
else if (match[2]) { // non-zero formatting inside ( ... )
|
|
chunks.push({ maybe: chunkFormatString(match[2]) });
|
|
}
|
|
else if (match[3]) { // a formatting token
|
|
chunks.push({ token: match[3] });
|
|
}
|
|
else if (match[5]) { // an unenclosed literal string
|
|
chunks.push(match[5]);
|
|
}
|
|
}
|
|
|
|
return chunks;
|
|
}
|