Files
MoonPro.net/MP-Site/scripts/jintervals.js
T
Samuele E. Locatelli a3bff998e7 incluso MP-Site...
2016-11-14 12:40:04 +01:00

356 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* jintervals -- JavaScript library for interval formatting
*
* jintervals is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* jintervals is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with jintervals. If not, see
* <http://www.gnu.org/licenses/>.
*
* Copyright (c) 2009 Rene Saarsoo <http://code.google.com/p/jintervals/>
*
*/
var jintervals = (function() {
function jintervals(seconds, format) {
return Interpreter.evaluate(new Time(seconds), Parser.parse(format));
};
/**
* Parses format string into data structure,
* that can be interpreted later.
*/
var Parser = {
parse: function(format) {
var unparsed = format;
var result = [];
while ( unparsed.length > 0 ) {
// leave plain text untouched
var textMatch = /^([^\\{]+)([\\{].*|)$/.exec(unparsed);
if (textMatch) {
result.push(textMatch[1]);
unparsed = textMatch[2];
}
// parse jintervals {Code} separately
var match = /^([{].*?(?:[}]|$))(.*)$/i.exec(unparsed);
if (match) {
result.push(this.parseCode(match[1]));
unparsed = match[2];
}
// backslash escapes next character
// transform \{ --> {
// transform \\ --> \
if (unparsed.charAt(0) === "\\") {
result.push(unparsed.charAt(1));
unparsed = unparsed.slice(2);
}
}
return result;
},
// parses single {Code} in format string
// Returns object representing the code or false when incorrect format string
parseCode: function(code) {
var re = /^[{]([smhdg])([smhdg]*)?(ays?|ours?|inutes?|econds?|reatests?|\.)?(\?(.*))?[}]$/i;
var matches = re.exec(code);
if (!matches) {
return false;
}
return {
// single-letter uppercase name of the type
type: matches[1].toUpperCase(),
// when code begins with lowercase letter, then set showing limited amount to true
limited: (matches[1].toLowerCase() == matches[1]),
paddingLength: (matches[2] || "").length + 1,
format: (matches[3]||"") == "" ? false : (matches[3] == "." ? "letter" : "full"),
optional: !!matches[4],
optionalSuffix: matches[5] || ""
};
}
};
/**
* Evaluates parse tree in the context of given time object
*/
var Interpreter = {
evaluate: function(time, parseTree) {
var smallestUnit = this.smallestUnit(parseTree);
var result = "";
while ( parseTree.length > 0 ) {
var code = parseTree.shift();
// leave plain text untouched
if (typeof code === "string") {
result += code;
}
// evaluate the code
else if (typeof code === "object") {
var unit = (code.type == "G") ? time.getGreatestUnit() : code.type;
var smallest = (code.type == "G") ? unit : smallestUnit;
var value = time.get(unit, code.limited, smallest);
var suffix = code.format ? Localization.translate(code.format, unit, value) : "";
// show when not optional or totalvalue is non-zero
if (!code.optional || time.get(unit) != 0) {
result += this.zeropad(value, code.paddingLength) + suffix + code.optionalSuffix;
}
}
// otherwise we have error
else {
result += "?";
}
}
return result;
},
/**
* Finds the smallest unit from parse tree.
*
* For example when parse tree contains "d", "m", "h" then returns "m"
*/
smallestUnit: function(parseTree) {
var unitOrder = {
"S": 0,
"M": 1,
"H": 2,
"D": 3
};
var smallest = "D";
for (var i = 0; i < parseTree.length; i++) {
if (typeof parseTree[i] === "object") {
var type = parseTree[i].type;
if (type !== "G" && unitOrder[type] < unitOrder[smallest]) {
smallest = type;
}
}
}
return smallest;
},
// utility function to pad number with leading zeros
zeropad: function(nr, decimals) {
var padLength = decimals - (""+nr).length;
return (padLength > 0) ? this.repeat("0", padLength) + nr : nr;
},
// utility function to repeat string
repeat: function(string, times) {
var result = "";
for (var i=0; i < times; i++) {
result += string;
}
return result;
}
};
/**
* Time class that deals with the actual computation of time units.
*/
var Time = function(s) {
this.seconds = s;
};
Time.prototype = {
nextUnit: {D: "H", H: "M", M: "S", S: "S"},
/**
* Returns the value of time in given unit
*
* @param {String} unit Either "S", "M", "H" or "D"
* @param {Boolean} limited When true 67 seconds will become just 7 seconds (defaults to false)
* @param {String} smallest The name of smallest unit. Defaults to next unit.
* For example for "D" it will be "H", for "H" it will be "M" and so on...
*/
get: function(unit, limited, smallest) {
if (!this[unit]) {
return "?";
}
smallest = smallest || this.nextUnit[unit];
return this[unit](limited, smallest);
},
// functions for each unit
S: function(limited, smallest) {
return limited ? this.seconds - this.M(false, smallest) * 60 : this.seconds;
},
M: function(limited, smallest) {
var minutes = this.seconds / 60;
minutes = (smallest === "M") ? Math.round(minutes): Math.floor(minutes);
if (limited) {
minutes = minutes - this.H(false, smallest) * 60;
}
return minutes;
},
H: function(limited, smallest) {
var hours = this.M(false, smallest) / 60;
hours = (smallest === "H") ? Math.round(hours): Math.floor(hours);
if (limited) {
hours = hours - this.D(false, smallest) * 24;
}
return hours;
},
D: function(limited, smallest) {
var days = this.H(false, smallest) / 24;
return (smallest === "D") ? Math.round(days): Math.floor(days);
},
/**
* Returns the name of greatest time unit.
*
* For example when we have 2 hours, 30 minutes, and 7 seconds,
* then the greatest unit is hour and "H" is returned.
*/
getGreatestUnit: function() {
if (this.seconds < 60) {
return "S";
}
else if (this.M(false, "M") < 60) {
return "M";
}
else if (this.H(false, "H") < 24) {
return "H";
}
else {
return "D";
}
}
};
var Localization = {
translate: function(format, lcType, value) {
var loc = this.locales[this.currentLocale];
var translation = loc[format][lcType];
if (typeof translation === "string") {
return translation;
}
else {
return translation[loc.plural(value)];
}
},
locale: function(loc) {
if (loc) {
this.currentLocale = loc;
}
return this.currentLocale;
},
currentLocale: "en_US",
locales: {
en_US: {
letter: {
D: "d",
H: "h",
M: "m",
S: "s"
},
full: {
D: [" day", " days"],
H: [" hour", " hours"],
M: [" minute", " minutes"],
S: [" second", " seconds"]
},
plural: function(nr) {
return (nr == 1) ? 0 : 1;
}
},
et_EE: {
letter: {
D: "p",
H: "h",
M: "m",
S: "s"
},
full: {
D: [" p\u00E4ev", " p\u00E4eva"],
H: [" tund", " tundi"],
M: [" minut", " minutit"],
S: [" sekund", " sekundit"]
},
plural: function(nr) {
return (nr == 1) ? 0 : 1;
}
},
lt_LT: {
letter: {
D: "d",
H: "h",
M: "m",
S: "s"
},
full: {
D: [" dieną", " dienas", " dienų"],
H: [" valandą", " valandas", " valandų"],
M: [" minutę", " minutes", " minučių"],
S: [" sekundę", " sekundes", " sekundžų"]
},
plural: function(n) {
return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);
}
},
ru_RU: {
letter: {
D: "д",
H: "ч",
M: "м",
S: "с"
},
full: {
D: [" день", " дня", " дней"],
H: [" час", " часа", " часов"],
M: [" минута", " минуты", " минут"],
S: [" секунда", " секунды", " секунд"]
},
plural: function(n) {
return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
}
},
fi_FI: {
letter: {
D: "p",
H: "h",
M: "m",
S: "s"
},
full: {
D: [" päivä", " päivää"],
H: [" tunti", " tuntia"],
M: [" minuutti", " minuuttia"],
S: [" sekunti", " sekunttia"]
},
plural: function(nr) {
return (nr == 1) ? 0 : 1;
}
}
}
};
// Changing and getting current locale
jintervals.locale = function(loc) {
return Localization.locale(loc);
};
jintervals.Time = Time;
return jintervals;
})();