AjxText.js
Summary
No overview generated for 'AjxText.js'
function AjxFormat(pattern) {
this._pattern = pattern;
this._segments = [];
}
AjxFormat.prototype.toString = function() {
var s = [];
s.push("pattern=\"",this._pattern,'"');
if (this._segments.length > 0) {
s.push(", segments={ ");
for (var i = 0; i < this._segments.length; i++) {
if (i > 0) { s.push(", "); }
s.push(String(this._segments[i]));
}
s.push(" }");
}
return s.join("");
};
// Data
AjxFormat.prototype._pattern;
AjxFormat.prototype._segments;
// Public methods
/**
* This method does <em>not</em> need to be overridden unless
* the subclass doesn't use format segments and takes complete
* responsibility for formatting.
*/
AjxFormat.prototype.format = function(object) {
var s = [];
for (var i = 0; i < this._segments.length; i++) {
s.push(this._segments[i].format(object));
}
return s.join("");
};
AjxFormat.prototype.parse = function(s) {
var object = this._createParseObject();
var index = 0;
for (var i = 0; i < this._segments.length; i++) {
var segment = this._segments[i];
index = segment.parse(object, s, index);
}
if (index < s.length) {
throw new AjxFormat.ParsingException(this, null, "input too long");
}
return object;
};
AjxFormat.prototype.getSegments = function() {
return this._segments;
};
AjxFormat.prototype.toPattern = function() {
return this._pattern;
};
AjxFormat.prototype.clone = function() {
return new this.constructor(this._pattern);
};
AjxFormat.prototype._createParseObject = function(s) {
throw new AjxFormat.ParsingException(this, null, "not implemented");
};
AjxFormat._zeroPad = function(s, length, zeroChar, rightSide) {
s = typeof s == "string" ? s : String(s);
if (s.length >= length) return s;
zeroChar = zeroChar || '0';
var a = [];
for (var i = s.length; i < length; i++) {
a.push(zeroChar);
}
a[rightSide ? "unshift" : "push"](s);
return a.join("");
};
AjxFormat.FormatException = function(format, message) {
this._format = format;
this._message = message;
};
AjxFormat.FormatException.prototype.toString = function() {
return this._message;
};
AjxFormat.FormatException.prototype._format;
AjxFormat.FormatException.prototype._message;
AjxFormat.FormattingException = function(format, segment, message) {
AjxFormat.FormatException.call(this, format, message);
this._segment = segment;
};
AjxFormat.FormattingException.prototype = new AjxFormat.FormatException;
AjxFormat.FormattingException.prototype.constructor = AjxFormat.FormattingException;
AjxFormat.FormattingException.prototype._segment;
AjxFormat.ParsingException = function(format, segment, message) {
AjxFormat.FormatException.call(this, format, message);
this._segment = segment;
};
AjxFormat.ParsingException.prototype = new AjxFormat.FormatException;
AjxFormat.ParsingException.prototype.constructor = AjxFormat.ParsingException;
AjxFormat.ParsingException.prototype._segment;
AjxFormat.Segment = function(format, s) {
this._parent = format;
this._s = s;
};
AjxFormat.Segment.prototype.toString = function() {
return "segment: \""+this._s+'"';
};
// Data
AjxFormat.Segment.prototype._parent;
AjxFormat.Segment.prototype._s;
// Public methods
AjxFormat.Segment.prototype.format = function(o) {
return this._s;
};
/**
* Parses the string at the given index, initializes the parse object
* (as appropriate), and returns the new index within the string for
* the next parsing step.
* <p>
* <strong>Note:</strong>
* This method must be implemented by sub-classes.
*
* @param o [object] The parse object to be initialized.
* @param s [string] The input string to be parsed.
* @param index [number] The index within the string to start parsing.
*/
AjxFormat.Segment.prototype.parse = function(o, s, i) {
throw new AjxFormat.ParsingException(this._parent, this, "not implemented"); // I18n
};
// Protected static methods
AjxFormat.Segment._parseLiteral = function(literal, s, index) {
if (s.length - index < literal.length) {
throw new AjxFormat.ParsingException(this._parent, this, "input too short"); // I18n
}
for (var i = 0; i < literal.length; i++) {
if (literal.charAt(i) != s.charAt(index + i)) {
throw new AjxFormat.ParsingException(this._parent, this, "input doesn't match"); // I18n
}
}
return index + literal.length;
};
AjxFormat.Segment._parseLiterals = function(literals, s, index) {
for (var i = 0; i < literals.length; i++) {
try {
var literal = literals[i];
return AjxFormat.Segment._parseLiteral(literal, s, index);
}
catch (e) {
// ignore. keep trying to find a match
}
}
return -1;
};
/**
* Parses an integer at the offset of the given string and calls a
* method on the specified object.
*
* @param o [object] The target object.
* @param f [function] The method to call on the target object.
* @param adjust [number] The numeric adjustment to make on the
* value before calling the object method.
* @param s [string] The string to parse.
* @param index [number] The index within the string to start parsing.
* @param fixedlen [number] If specified, specifies the required number
* of digits to be parsed.
*/
AjxFormat.Segment._parseInt = function(o, f, adjust, s, index, fixedlen) {
var len = fixedlen || s.length - index;
var head = index;
for (var i = 0; i < len; i++) {
if (!s.charAt(index++).match(/\d/)) {
index--;
break;
}
}
var tail = index;
if (head == tail) {
throw new AjxFormat.ParsingException(this._parent, this, "number not present"); // I18n
}
if (fixedlen && tail - head != fixedlen) {
throw new AjxFormat.ParsingException(this._parent, this, "number too short"); // I18n
}
var value = parseInt(s.substring(head, tail), 10);
if (f) {
var target = o || window;
f.call(target, value + adjust);
}
return tail;
};
//
// Date format class
//
/**
* The AjxDateFormat class formats Date objects according to a specified
* pattern. The patterns are defined the same as the SimpleDateFormat
* class in the Java libraries. <strong>Note:</strong> <em>Only the
* Gregorian Calendar is supported at this time.</em> Supporting other
* calendars would require a lot more information downloaded to the
* client. Limiting dates to the Gregorian calendar is a trade-off.
* <p>
* <strong>Note:</strong>
* The date format differs from the Java patterns a few ways: the pattern
* "EEEEE" (5 'E's) denotes a <em>short</em> weekday and the pattern "MMMMM"
* (5 'M's) denotes a <em>short</em> month name. This matches the extended
* pattern found in the Common Locale Data Repository (CLDR) found at:
* http://www.unicode.org/cldr/.
*/
function AjxDateFormat(pattern) {
AjxFormat.call(this, pattern);
if (typeof pattern == "number") {
switch (pattern) {
case AjxDateFormat.SHORT: pattern = I18nMsg.formatDateShort; break;
case AjxDateFormat.MEDIUM: pattern = I18nMsg.formatDateMedium; break;
case AjxDateFormat.LONG: pattern = I18nMsg.formatDateLong; break;
case AjxDateFormat.FULL: pattern = I18nMsg.formatDateFull; break;
}
}
for (var i = 0; i < pattern.length; i++) {
// literal
var c = pattern.charAt(i);
if (c == "'") {
var head = i + 1;
for (i++ ; i < pattern.length; i++) {
var c = pattern.charAt(i);
if (c == "'") {
if (i + 1 < pattern.length && pattern.charAt(i + 1) == "'") {
pattern = pattern.substr(0, i) + pattern.substr(i + 1);
}
else {
break;
}
}
}
if (i == pattern.length) {
// TODO: i18n
throw new FormatException(this, "unterminated string literal");
}
var tail = i;
var segment = new AjxFormat.TextSegment(this, pattern.substring(head, tail));
this._segments.push(segment);
continue;
}
// non-meta chars
var head = i;
while(i < pattern.length) {
c = pattern.charAt(i);
if (AjxDateFormat._META_CHARS.indexOf(c) != -1 || c == "'") {
break;
}
i++;
}
var tail = i;
if (head != tail) {
var segment = new AjxFormat.TextSegment(this, pattern.substring(head, tail));
this._segments.push(segment);
i--;
continue;
}
// meta char
var head = i;
while(++i < pattern.length) {
if (pattern.charAt(i) != c) {
break;
}
}
var tail = i--;
var count = tail - head;
var field = pattern.substr(head, count);
var segment = null;
switch (c) {
case 'G': segment = new AjxDateFormat.EraSegment(this, field); break;
case 'y': segment = new AjxDateFormat.YearSegment(this, field); break;
case 'M': segment = new AjxDateFormat.MonthSegment(this, field); break;
case 'w': segment = new AjxDateFormat.WeekSegment(this, field); break;
case 'W': segment = new AjxDateFormat.WeekSegment(this, field); break;
case 'D': segment = new AjxDateFormat.DaySegment(this, field); break;
case 'd': segment = new AjxDateFormat.DaySegment(this, field); break;
case 'F': segment = new AjxDateFormat.WeekdaySegment(this, field); break;
case 'E': segment = new AjxDateFormat.WeekdaySegment(this, field); break;
case 'a': segment = new AjxDateFormat.AmPmSegment(this, field); break;
case 'H': segment = new AjxDateFormat.HourSegment(this, field); break;
case 'k': segment = new AjxDateFormat.HourSegment(this, field); break;
case 'K': segment = new AjxDateFormat.HourSegment(this, field); break;
case 'h': segment = new AjxDateFormat.HourSegment(this, field); break;
case 'm': segment = new AjxDateFormat.MinuteSegment(this, field); break;
case 's': segment = new AjxDateFormat.SecondSegment(this, field); break;
case 'S': segment = new AjxDateFormat.SecondSegment(this, field); break;
case 'z': segment = new AjxDateFormat.TimezoneSegment(this, field); break;
case 'Z': segment = new AjxDateFormat.TimezoneSegment(this, field); break;
}
if (segment != null) {
segment._index = this._segments.length;
this._segments.push(segment);
}
}
}
AjxDateFormat.prototype = new AjxFormat;
AjxDateFormat.prototype.constructor = AjxDateFormat;
AjxDateFormat.prototype.toString = function() {
return "[AjxDateFormat: "+AjxFormat.prototype.toString.call(this)+"]";
};
// Constants
AjxDateFormat.SHORT = 0;
AjxDateFormat.MEDIUM = 1;
AjxDateFormat.LONG = 2;
AjxDateFormat.FULL = 3;
AjxDateFormat.DEFAULT = AjxDateFormat.MEDIUM;
AjxDateFormat._META_CHARS = "GyMwWDdFEaHkKhmsSzZ";
AjxDateFormat._dateFormats = [
I18nMsg.formatDateShort, I18nMsg.formatDateMedium,
I18nMsg.formatDateLong, I18nMsg.formatDateFull
];
AjxDateFormat._timeFormats = [
I18nMsg.formatTimeShort, I18nMsg.formatTimeMedium,
I18nMsg.formatTimeLong, I18nMsg.formatTimeFull
];
AjxDateFormat._DATE_FORMATTERS = {};
AjxDateFormat._TIME_FORMATTERS = {};
AjxDateFormat._DATETIME_FORMATTERS = {};
// Static methods
AjxDateFormat.getDateInstance = function(style) {
// lazily create formatters
style = style != null ? style : AjxDateFormat.DEFAULT;
if (!AjxDateFormat._DATE_FORMATTERS[style]) {
AjxDateFormat._DATE_FORMATTERS[style] = new AjxDateFormat(AjxDateFormat._dateFormats[style]);
}
return AjxDateFormat._DATE_FORMATTERS[style];
};
AjxDateFormat.getTimeInstance = function(style) {
// lazily create formatters
style = style != null ? style : AjxDateFormat.DEFAULT;
if (!AjxDateFormat._TIME_FORMATTERS[style]) {
AjxDateFormat._TIME_FORMATTERS[style] = new AjxDateFormat(AjxDateFormat._timeFormats[style]);
}
return AjxDateFormat._TIME_FORMATTERS[style];
};
AjxDateFormat.getDateTimeInstance = function(dateStyle, timeStyle) {
// lazily create formatters
dateStyle = dateStyle != null ? dateStyle : AjxDateFormat.DEFAULT;
timeStyle = timeStyle != null ? timeStyle : AjxDateFormat.DEFAULT;
var style = dateStyle * 10 + timeStyle;
if (!AjxDateFormat._DATETIME_FORMATTERS[style]) {
var pattern = I18nMsg.formatDateTime;
var params = [ AjxDateFormat._dateFormats[dateStyle], AjxDateFormat._timeFormats[timeStyle] ];
var dateTimePattern = AjxMessageFormat.format(pattern, params);
AjxDateFormat._DATETIME_FORMATTERS[style] = new AjxDateFormat(dateTimePattern);
}
return AjxDateFormat._DATETIME_FORMATTERS[style];
};
AjxDateFormat.format = function(pattern, date) {
return new AjxDateFormat(pattern).format(date);
};
AjxDateFormat.parse = function(pattern, dateStr) {
return new AjxDateFormat(pattern).parse(dateStr);
};
// Public methods
/**
* Parses the given string and returns a date. If the string cannot be
* parsed as a date, <code>null</code> is returned.
*/
AjxDateFormat.prototype.parse = function(s) {
var object = null;
try {
object = AjxFormat.prototype.parse.call(this, s);
}
catch (e) {
// do nothing
}
return object;
};
// Protected methods
AjxDateFormat.prototype._createParseObject = function() {
return new Date(0, 0, 1, 0, 0, 0, 0);
};
//
// Text segment class
//
AjxFormat.TextSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxFormat.TextSegment.prototype = new AjxFormat.Segment;
AjxFormat.TextSegment.prototype.constructor = AjxFormat.TextSegment;
AjxFormat.TextSegment.prototype.toString = function() {
return "text: \""+this._s+'"';
};
AjxFormat.TextSegment.prototype.parse = function(o, s, index) {
return AjxFormat.Segment._parseLiteral(this._s, s, index);
};
AjxDateFormat.DateSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
}
AjxDateFormat.DateSegment.prototype = new AjxFormat.Segment;
AjxDateFormat.DateSegment.prototype.constructor = AjxDateFormat.DateSegment;
AjxDateFormat.DateSegment.prototype._getFixedLength = function() {
var fixedlen;
if (this._index + 1 < this._parent._segments.length) {
var nextSegment = this._parent._segments[this._index + 1];
if (!(nextSegment instanceof AjxFormat.TextSegment)) {
fixedlen = this._s.length;
}
}
return fixedlen;
};
AjxDateFormat.EraSegment = function(format, s) {
AjxDateFormat.DateSegment.call(this, format, s);
};
AjxDateFormat.EraSegment.prototype = new AjxDateFormat.DateSegment;
AjxDateFormat.EraSegment.prototype.constructor = AjxDateFormat.EraSegment;
AjxDateFormat.EraSegment.prototype.toString = function() {
return "dateEra: \""+this._s+'"';
};
// Public methods
AjxDateFormat.EraSegment.prototype.format = function(date) {
// TODO: Only support current era at the moment...
return I18nMsg.eraAD;
};
//
// Date year segment class
//
AjxDateFormat.YearSegment = function(format, s) {
AjxDateFormat.DateSegment.call(this, format, s);
};
AjxDateFormat.YearSegment.prototype = new AjxDateFormat.DateSegment;
AjxDateFormat.YearSegment.prototype.constructor = AjxDateFormat.YearSegment;
AjxDateFormat.YearSegment.prototype.toString = function() {
return "dateYear: \""+this._s+'"';
};
// Public methods
AjxDateFormat.YearSegment.prototype.format = function(date) {
var year = String(date.getFullYear());
return this._s.length < 4 ? year.substr(year.length - 2) : AjxFormat._zeroPad(year, this._s.length);
};
AjxDateFormat.YearSegment.prototype.parse = function(date, s, index) {
var fixedlen = this._getFixedLength();
var nindex = AjxFormat.Segment._parseInt(date, date.setFullYear, 0, s, index, fixedlen);
// adjust 2-digit years
if (nindex - index == 2) {
if (!AjxDateFormat._2digitStartYear) {
AjxDateFormat._2digitStartYear = parseInt(AjxMsg.dateParsing2DigitStartYear);
}
var syear = AjxDateFormat._2digitStartYear;
var pyear = parseInt(s.substr(index,2));
var century = (Math.floor(syear / 100) + (pyear < (syear % 100) ? 1 : 0)) * 100;
var year = century + pyear;
date.setFullYear(year);
}
return nindex;
};
//
// Date month segment class
//
AjxDateFormat.MonthSegment = function(format, s) {
AjxDateFormat.DateSegment.call(this, format, s);
};
AjxDateFormat.MonthSegment.prototype = new AjxDateFormat.DateSegment;
AjxDateFormat.MonthSegment.prototype.constructor = AjxDateFormat.MonthSegment;
AjxDateFormat.MonthSegment.prototype.toString = function() {
return "dateMonth: \""+this._s+'"';
};
AjxDateFormat.MonthSegment.MONTHS = {};
AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.SHORT] = [
AjxMsg.monthJanShort, AjxMsg.monthFebShort, AjxMsg.monthMarShort,
AjxMsg.monthAprShort, AjxMsg.monthMayShort, AjxMsg.monthJunShort,
AjxMsg.monthJulShort, AjxMsg.monthAugShort, AjxMsg.monthSepShort,
AjxMsg.monthOctShort, AjxMsg.monthNovShort, AjxMsg.monthDecShort
];
AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.MEDIUM] = [
I18nMsg.monthJanMedium, I18nMsg.monthFebMedium, I18nMsg.monthMarMedium,
I18nMsg.monthAprMedium, I18nMsg.monthMayMedium, I18nMsg.monthJunMedium,
I18nMsg.monthJulMedium, I18nMsg.monthAugMedium, I18nMsg.monthSepMedium,
I18nMsg.monthOctMedium, I18nMsg.monthNovMedium, I18nMsg.monthDecMedium
];
AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.LONG] = [
I18nMsg.monthJanLong, I18nMsg.monthFebLong, I18nMsg.monthMarLong,
I18nMsg.monthAprLong, I18nMsg.monthMayLong, I18nMsg.monthJunLong,
I18nMsg.monthJulLong, I18nMsg.monthAugLong, I18nMsg.monthSepLong,
I18nMsg.monthOctLong, I18nMsg.monthNovLong, I18nMsg.monthDecLong
];
AjxDateFormat.MonthSegment.prototype.format = function(date) {
var month = date.getMonth();
switch (this._s.length) {
case 1: return String(month + 1);
case 2: return AjxFormat._zeroPad(month + 1, 2);
case 3: return AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.MEDIUM][month];
case 5: return AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.SHORT][month];
}
return AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.LONG][month];
};
AjxDateFormat.MonthSegment.prototype.parse = function(date, s, index) {
var months;
switch (this._s.length) {
case 3:
months = AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.SHORT];
case 4:
months = months || AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.MEDIUM];
case 5: {
months = months || AjxDateFormat.MonthSegment.MONTHS[AjxDateFormat.LONG];
var nindex = AjxFormat.Segment._parseLiterals(months, s, index);
if (nindex != -1) {
return nindex;
}
throw new AjxFormat.ParsingException(this._parent, this, "no match");
}
}
var fixedlen = this._getFixedLength();
return AjxFormat.Segment._parseInt(date, date.setMonth, -1, s, index, fixedlen);
};
AjxDateFormat.WeekSegment = function(format, s) {
AjxDateFormat.DateSegment.call(this, format, s);
};
AjxDateFormat.WeekSegment.prototype = new AjxDateFormat.DateSegment;
AjxDateFormat.WeekSegment.prototype.constructor = AjxDateFormat.WeekSegment;
AjxDateFormat.WeekSegment.prototype.toString = function() {
return "weekMonth: \""+this._s+'"';
};
// Public methods
AjxDateFormat.WeekSegment.prototype.format = function(date) {
var year = date.getYear();
var month = date.getMonth();
var day = date.getDate();
var ofYear = /w/.test(this._s);
var date2 = new Date(year, ofYear ? 0 : month, 1);
var week = 0;
while (true) {
week++;
if (date2.getMonth() > month || (date2.getMonth() == month && date2.getDate() >= day)) {
break;
}
date2.setDate(date2.getDate() + 7);
}
return AjxFormat._zeroPad(week, this._s.length);
};
//
// Date day segment class
//
AjxDateFormat.DaySegment = function(format, s) {
AjxDateFormat.DateSegment.call(this, format, s);
};
AjxDateFormat.DaySegment.prototype = new AjxDateFormat.DateSegment;
AjxDateFormat.DaySegment.prototype.constructor = AjxDateFormat.DaySegment;
AjxDateFormat.DaySegment.prototype.toString = function() {
return "dateDay: \""+this._s+'"';
};
// Public methods
AjxDateFormat.DaySegment.prototype.format = function(date) {
var month = date.getMonth();
var day = date.getDate();
if (/D/.test(this._s) && month > 0) {
var year = date.getYear();
do {
// set date to first day of month and then go back one day
var date2 = new Date(year, month, 1);
date2.setDate(0);
day += date2.getDate();
month--;
} while (month > 0);
}
return AjxFormat._zeroPad(day, this._s.length);
};
AjxDateFormat.DaySegment.prototype.parse = function(date, s, index) {
if (/D/.test(this._s)) {
date.setMonth(0);
}
var fixedlen = this._getFixedLength();
return AjxFormat.Segment._parseInt(date, date.setDate, 0, s, index, fixedlen);
};
//
// Date weekday segment class
//
AjxDateFormat.WeekdaySegment = function(format, s) {
AjxDateFormat.DateSegment.call(this, format, s);
};
AjxDateFormat.WeekdaySegment.prototype = new AjxDateFormat.DateSegment;
AjxDateFormat.WeekdaySegment.prototype.constructor = AjxDateFormat.WeekdaySegment;
AjxDateFormat.DaySegment.prototype.toString = function() {
return "dateDay: \""+this._s+'"';
};
AjxDateFormat.WeekdaySegment.WEEKDAYS = {};
AjxDateFormat.WeekdaySegment.WEEKDAYS[AjxDateFormat.SHORT] = [
AjxMsg.weekdaySunShort, AjxMsg.weekdayMonShort, AjxMsg.weekdayTueShort,
AjxMsg.weekdayWedShort, AjxMsg.weekdayThuShort, AjxMsg.weekdayFriShort,
AjxMsg.weekdaySatShort
];
AjxDateFormat.WeekdaySegment.WEEKDAYS[AjxDateFormat.MEDIUM] = [
I18nMsg.weekdaySunMedium, I18nMsg.weekdayMonMedium, I18nMsg.weekdayTueMedium,
I18nMsg.weekdayWedMedium, I18nMsg.weekdayThuMedium, I18nMsg.weekdayFriMedium,
I18nMsg.weekdaySatMedium
];
AjxDateFormat.WeekdaySegment.WEEKDAYS[AjxDateFormat.LONG] = [
I18nMsg.weekdaySunLong, I18nMsg.weekdayMonLong, I18nMsg.weekdayTueLong,
I18nMsg.weekdayWedLong, I18nMsg.weekdayThuLong, I18nMsg.weekdayFriLong,
I18nMsg.weekdaySatLong
];
AjxDateFormat.WeekdaySegment.prototype.format = function(date) {
var weekday = date.getDay();
if (/E/.test(this._s)) {
var style;
switch (this._s.length) {
case 4: style = AjxDateFormat.LONG; break;
case 5: style = AjxDateFormat.SHORT; break;
default: style = AjxDateFormat.MEDIUM;
}
return AjxDateFormat.WeekdaySegment.WEEKDAYS[style][weekday];
}
return AjxFormat._zeroPad(weekday, this._s.length);
};
AjxDateFormat.TimeSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxDateFormat.TimeSegment.prototype = new AjxFormat.Segment;
AjxDateFormat.TimeSegment.prototype.constructor = AjxDateFormat.TimeSegment;
AjxDateFormat.HourSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxDateFormat.HourSegment.prototype = new AjxDateFormat.TimeSegment;
AjxDateFormat.HourSegment.prototype.constructor = AjxDateFormat.HourSegment;
AjxDateFormat.HourSegment.prototype.toString = function() {
return "timeHour: \""+this._s+'"';
};
// Public methods
AjxDateFormat.HourSegment.prototype.format = function(date) {
var hours = date.getHours();
if (hours > 12 && /[hK]/.test(this._s)) {
hours -= 12;
}
/***
// NOTE: This is commented out to match the Java formatter output
// but from the comments for these meta-chars, it doesn't
if (/[Hk]/.test(this._s)) {
hours--;
}
return AjxFormat._zeroPad(hours, this._s.length);
};
AjxDateFormat.MinuteSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxDateFormat.MinuteSegment.prototype = new AjxDateFormat.TimeSegment;
AjxDateFormat.MinuteSegment.prototype.constructor = AjxDateFormat.MinuteSegment;
AjxDateFormat.MinuteSegment.prototype.toString = function() {
return "timeMinute: \""+this._s+'"';
};
// Public methods
AjxDateFormat.MinuteSegment.prototype.format = function(date) {
var minutes = date.getMinutes();
return AjxFormat._zeroPad(minutes, this._s.length);
};
//
// Time second segment class
//
AjxDateFormat.SecondSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxDateFormat.SecondSegment.prototype = new AjxDateFormat.TimeSegment;
AjxDateFormat.SecondSegment.prototype.constructor = AjxDateFormat.SecondSegment;
AjxDateFormat.SecondSegment.prototype.toString = function() {
return "timeSecond: \""+this._s+'"';
};
// Public methods
AjxDateFormat.SecondSegment.prototype.format = function(date) {
var minutes = /s/.test(this._s) ? date.getSeconds() : date.getMilliseconds();
return AjxFormat._zeroPad(minutes, this._s.length);
};
//
// Time am/pm segment class
//
AjxDateFormat.AmPmSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxDateFormat.AmPmSegment.prototype = new AjxDateFormat.TimeSegment;
AjxDateFormat.AmPmSegment.prototype.constructor = AjxDateFormat.AmPmSegment;
AjxDateFormat.AmPmSegment.prototype.toString = function() {
return "timeAmPm: \""+this._s+'"';
};
AjxDateFormat.AmPmSegment.prototype.format = function(date) {
var hours = date.getHours();
return hours < 12 ? I18nMsg.periodAm : I18nMsg.periodPm;
};
AjxDateFormat.TimezoneSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxDateFormat.TimezoneSegment.prototype = new AjxDateFormat.TimeSegment;
AjxDateFormat.TimezoneSegment.prototype.constructor = AjxDateFormat.TimezoneSegment;
AjxDateFormat.TimezoneSegment.prototype.toString = function() {
return "timeTimezone: \""+this._s+'"';
};
// Public methods
AjxDateFormat.TimezoneSegment.prototype.format = function(date) {
var clientId = date.timezone || AjxTimezone.DEFAULT;
if (/Z/.test(this._s)) {
return AjxTimezone.getShortName(clientId);
}
return this._s.length < 4 ? AjxTimezone.getMediumName(clientId) : AjxTimezone.getLongName(clientId);
};
//
// Message format class
//
function AjxMessageFormat(pattern) {
AjxFormat.call(this, pattern);
for (var i = 0; i < pattern.length; i++) {
// literal
var c = pattern.charAt(i);
if (c == "'") {
if (i + 1 < pattern.length && pattern.charAt(i + 1) == "'") {
var segment = new AjxFormat.TextSegment(this, "'");
this._segments.push(segment);
i++;
continue;
}
var head = i + 1;
for (i++ ; i < pattern.length; i++) {
var c = pattern.charAt(i);
if (c == "'") {
if (i + 1 < pattern.length && pattern.charAt(i + 1) == "'") {
pattern = pattern.substr(0, i) + pattern.substr(i + 1);
}
else {
break;
}
}
}
if (i == pattern.length) {
// TODO: i18n
throw new AjxFormat.FormatException(this, "unterminated string literal");
}
var tail = i;
var segment = new AjxFormat.TextSegment(this, pattern.substring(head, tail));
this._segments.push(segment);
continue;
}
// non-meta chars
var head = i;
while(i < pattern.length) {
c = pattern.charAt(i);
if (c == '{' || c == "'") {
break;
}
i++;
}
var tail = i;
if (head != tail) {
var segment = new AjxFormat.TextSegment(this, pattern.substring(head, tail));
this._segments.push(segment);
i--;
continue;
}
// meta char
var head = i + 1;
while(++i < pattern.length) {
if (pattern.charAt(i) == '}') {
break;
}
}
var tail = i;
var count = tail - head;
var field = pattern.substr(head, count);
var segment = new AjxMessageFormat.MessageSegment(this, field);
if (segment != null) {
this._segments.push(segment);
}
}
}
AjxMessageFormat.prototype = new AjxFormat;
AjxMessageFormat.prototype.constructor = AjxMessageFormat;
AjxMessageFormat.prototype.toString = function() {
return "[AjxMessageFormat: "+AjxFormat.prototype.toString.call(this)+"]";
};
// Static methods
AjxMessageFormat.format = function(pattern, params) {
return new AjxMessageFormat(pattern).format(params);
};
// Public methods
AjxMessageFormat.prototype.format = function(params) {
if (!(params instanceof Array)) {
params = [ params ];
}
return AjxFormat.prototype.format.call(this, params);
};
//
// AjxMessageFormat.MessageSegment class
//
AjxMessageFormat.MessageSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
var parts = s.split(',');
this._index = Number(parts[0]);
this._type = parts[1] || "string";
this._style = parts[2];
switch (this._type) {
case "number": {
switch (this._style) {
case "integer": this._formatter = AjxNumberFormat.getIntegerInstance(); break;
case "currency": this._formatter = AjxNumberFormat.getCurrencyInstance(); break;
case "percent": this._formatter = AjxNumberFormat.getPercentInstance(); break;
default: this._formatter = this._style == null ? AjxNumberFormat.getInstance() : new AjxNumberFormat(this._style);
}
break;
}
case "date": case "time": {
var func = this._type == "date" ? AjxDateFormat.getDateInstance : AjxDateFormat.getTimeInstance;
switch (this._style) {
case "short": this._formatter = func(AjxDateFormat.SHORT); break;
case "medium": this._formatter = func(AjxDateFormat.MEDIUM); break;
case "long": this._formatter = func(AjxDateFormat.LONG); break;
case "full": this._formatter = func(AjxDateFormat.FULL); break;
default: this._formatter = this._style == null ? func(AjxDateFormat.DEFAULT) : new AjxDateFormat(this._style);
}
break;
}
case "choice": /*TODO*/ break;
}
};
AjxMessageFormat.MessageSegment.prototype = new AjxFormat.Segment;
AjxMessageFormat.MessageSegment.prototype.constructor = AjxMessageFormat.MessageSegment;
AjxMessageFormat.MessageSegment.prototype.toString = function() {
var a = [ "message: \"", this._s, "\", index: ", this.index ];
if (this._type) a.push(", type: ", this._type);
if (this._style) a.push(", style: ", this._style);
if (this._formatter) a.push(", formatter: ", this._formatter.toString());
return a.join("");
};
// Data
AjxMessageFormat.MessageSegment.prototype._index;
AjxMessageFormat.MessageSegment.prototype._type;
AjxMessageFormat.MessageSegment.prototype._style;
AjxMessageFormat.MessageSegment.prototype._formatter;
// Public methods
AjxMessageFormat.MessageSegment.prototype.format = function(args) {
var object = args[this._index];
return this._formatter ? this._formatter.format(object) : String(object);
};
//
// AjxNumberFormat class
//
/**
* @param pattern The number pattern.
* @param skipNegFormat Specifies whether to skip the generation of this
* format's negative value formatter.
* <p>
* <strong>Note:</strong>
* This parameter is only used by the implementation
* and should not be passed by application code
* instantiating a custom number format.
*/
function AjxNumberFormat(pattern, skipNegFormat) {
AjxFormat.call(this, pattern);
if (pattern == "") return;
var patterns = pattern.split(/;/);
var pattern = patterns[0];
var i = 0;
var results = this.__parseStatic(pattern, i);
i = results.offset;
var hasPrefix = results.text != "";
if (hasPrefix) {
this._segments.push(new AjxFormat.TextSegment(this, results.text));
}
var start = i;
while (i < pattern.length &&
AjxNumberFormat._META_CHARS.indexOf(pattern.charAt(i)) != -1) {
i++;
}
var end = i;
var numPattern = pattern.substring(start, end);
var e = numPattern.indexOf('E');
var expon = e != -1 ? numPattern.substring(e + 1) : null;
if (expon) {
numPattern = numPattern.substring(0, e);
this._showExponent = true;
}
var dot = numPattern.indexOf('.');
var whole = dot != -1 ? numPattern.substring(0, dot) : numPattern;
if (whole) {
var comma = whole.lastIndexOf(',');
if (comma != -1) {
this._groupingOffset = whole.length - comma - 1;
}
whole = whole.replace(/[^#0]/g,"");
var zero = whole.indexOf('0');
if (zero != -1) {
this._minIntDigits = whole.length - zero;
}
this._maxIntDigits = whole.length;
}
var fract = dot != -1 ? numPattern.substring(dot + 1) : null;
if (fract) {
var zero = fract.lastIndexOf('0');
if (zero != -1) {
this._minFracDigits = zero + 1;
}
this._maxFracDigits = fract.replace(/[^#0]/g,"").length;
}
this._segments.push(new AjxNumberFormat.NumberSegment(this, numPattern));
var results = this.__parseStatic(pattern, i);
i = results.offset;
if (results.text != "") {
this._segments.push(new AjxFormat.TextSegment(this, results.text));
}
if (skipNegFormat) return;
if (patterns.length > 1) {
var pattern = patterns[1];
this._negativeFormatter = new AjxNumberFormat(pattern, true);
}
else {
var formatter = new AjxNumberFormat("");
formatter._segments = formatter._segments.concat(this._segments);
var index = hasPrefix ? 1 : 0;
var minus = new AjxFormat.TextSegment(formatter, I18nMsg.numberSignMinus);
formatter._segments.splice(index, 0, minus);
this._negativeFormatter = formatter;
}
}
AjxNumberFormat.prototype = new AjxFormat;
AjxNumberFormat.prototype.constructor = AjxNumberFormat;
AjxNumberFormat.prototype.toString = function() {
var array = [
"[AjxNumberFormat: ",
"formatter=", AjxFormat.prototype.toString.call(this)
];
if (this._negativeFormatter) {
array.push(", negativeFormatter=", this._negativeFormatter.toString());
}
array.push(']');
return array.join("");
};
AjxNumberFormat._NUMBER = "number";
AjxNumberFormat._INTEGER = "integer";
AjxNumberFormat._CURRENCY = "currency";
AjxNumberFormat._PERCENT = "percent";
AjxNumberFormat._META_CHARS = "0#.,E";
AjxNumberFormat._FORMATTERS = {};
AjxNumberFormat.prototype._groupingOffset = Number.MAX_VALUE;
AjxNumberFormat.prototype._maxIntDigits;
AjxNumberFormat.prototype._minIntDigits = 1;
AjxNumberFormat.prototype._maxFracDigits;
AjxNumberFormat.prototype._minFracDigits;
AjxNumberFormat.prototype._isCurrency = false;
AjxNumberFormat.prototype._isPercent = false;
AjxNumberFormat.prototype._isPerMille = false;
AjxNumberFormat.prototype._showExponent = false;
AjxNumberFormat.prototype._negativeFormatter;
AjxNumberFormat.getInstance = function() {
if (!AjxNumberFormat._FORMATTERS[AjxNumberFormat._NUMBER]) {
AjxNumberFormat._FORMATTERS[AjxNumberFormat._NUMBER] = new AjxNumberFormat(I18nMsg.formatNumber);
}
return AjxNumberFormat._FORMATTERS[AjxNumberFormat._NUMBER];
};
AjxNumberFormat.getNumberInstance = AjxNumberFormat.getInstance;
AjxNumberFormat.getCurrencyInstance = function() {
if (!AjxNumberFormat._FORMATTERS[AjxNumberFormat._CURRENCY]) {
AjxNumberFormat._FORMATTERS[AjxNumberFormat._CURRENCY] = new AjxNumberFormat(I18nMsg.formatNumberCurrency);
}
return AjxNumberFormat._FORMATTERS[AjxNumberFormat._CURRENCY];
};
AjxNumberFormat.getIntegerInstance = function() {
if (!AjxNumberFormat._FORMATTERS[AjxNumberFormat._INTEGER]) {
AjxNumberFormat._FORMATTERS[AjxNumberFormat._INTEGER] = new AjxNumberFormat(I18nMsg.formatNumberInteger);
}
return AjxNumberFormat._FORMATTERS[AjxNumberFormat._INTEGER];
};
AjxNumberFormat.getPercentInstance = function() {
if (!AjxNumberFormat._FORMATTERS[AjxNumberFormat._PERCENT]) {
AjxNumberFormat._FORMATTERS[AjxNumberFormat._PERCENT] = new AjxNumberFormat(I18nMsg.formatNumberPercent);
}
return AjxNumberFormat._FORMATTERS[AjxNumberFormat._PERCENT];
};
AjxNumberFormat.format = function(pattern, number) {
return new AjxNumberFormat(pattern).format(number);
};
AjxNumberFormat.prototype.format = function(number) {
if (number < 0 && this._negativeFormatter) {
return this._negativeFormatter.format(number);
}
return AjxFormat.prototype.format.call(this, number);
};
AjxNumberFormat.prototype.__parseStatic = function(s, i) {
var data = [];
while (i < s.length) {
var c = s.charAt(i++);
if (AjxNumberFormat._META_CHARS.indexOf(c) != -1) {
i--;
break;
}
switch (c) {
case "'": {
var start = i;
while (i < s.length && s.charAt(i++) != "'") {
}
var end = i;
c = end - start == 0 ? "'" : s.substring(start, end);
break;
}
case '%': {
c = I18nMsg.numberSignPercent;
this._isPercent = true;
break;
}
case '\u2030': {
c = I18nMsg.numberSignPerMill;
this._isPerMille = true;
break;
}
case '\u00a4': {
c = s.charAt(i) == '\u00a4'
? I18nMsg.currencyCode : I18nMsg.currencySymbol;
this._isCurrency = true;
break;
}
}
data.push(c);
}
return { text: data.join(""), offset: i };
};
AjxNumberFormat.NumberSegment = function(format, s) {
AjxFormat.Segment.call(this, format, s);
};
AjxNumberFormat.NumberSegment.prototype = new AjxFormat.Segment;
AjxNumberFormat.NumberSegment.prototype.constructor = AjxNumberFormat.NumberSegment;
AjxNumberFormat.NumberSegment.prototype.toString = function() {
return "number: \""+this._s+"\"";
};
AjxNumberFormat.NumberSegment.prototype.format = function(number) {
if (isNaN(number)) return I18nMsg.numberNaN;
if (number === Number.NEGATIVE_INFINITY || number === Number.POSITIVE_INFINITY) {
return I18nMsg.numberInfinity;
}
if (typeof number != "number") number = Number(number);
number = Math.abs(number);
if (this._parent._isPercent) number *= 100;
else if (this._parent._isPerMille) number *= 1000;
var s = this._parent._showExponent
? number.toExponential(this._parent._maxFracDigits).toUpperCase().replace(/E\+/,"E")
: number.toFixed(this._parent._maxFracDigits);
s = this._normalize(s);
return s;
};
AjxNumberFormat.NumberSegment.prototype._normalize = function(s) {
var match = s.split(/([\.Ee])/);
var whole = match.shift();
if (whole.length < this._parent._minIntDigits) {
whole = AjxFormat._zeroPad(whole, this._parent._minIntDigits, I18nMsg.numberZero);
}
if (whole.length > this._parent._groupingOffset) {
var a = [];
var i = whole.length - this._parent._groupingOffset;
while (i > 0) {
a.unshift(whole.substr(i, this._parent._groupingOffset));
a.unshift(I18nMsg.numberSeparatorGrouping);
i -= this._parent._groupingOffset;
}
a.unshift(whole.substring(0, i + this._parent._groupingOffset));
whole = a.join("");
}
var fract = '0';
var expon;
while (match.length > 0) {
switch (match.shift()) {
case '.': fract = match.shift(); break;
case 'E': case 'e': expon = match.shift(); break;
default:
}
}
fract = fract.replace(/0+$/,"");
if (fract.length < this._parent._minFracDigits) {
fract = AjxFormat._zeroPad(fract, this._parent._minFracDigits, I18nMsg.numberZero, true);
}
var a = [ whole ];
if (fract.length > 0) {
var decimal = this._parent._isCurrency
? I18nMsg.numberSeparatorMoneyDecimal
: I18nMsg.numberSeparatorDecimal;
a.push(decimal, fract);
}
if (expon) {
a.push('E', expon.replace(/^\+/,""));
}
return a.join("");
};
function AjxChoiceFormat(pattern) {
AjxFormat.call(this, pattern);
var choices = pattern.split("|");
if (arguments.length == 1) {
this._limits = new Array(choices.length);
this._lessThan = new Array(choices.length);
this._formats = new Array(choices.length);
var regex = new RegExp("^([^#<\u2264]+)([#<\u2264])(.*)$");
for (var i = 0; i < choices.length; i++) {
var choice = choices[i];
var results = regex.exec(choice);
var limit = results[1];
var separator = results[2];
var message = results[3];
if (limit == '\u221E') {
this._limits[i] = Number.POSITIVE_INFINITY;
}
else if (limit == '-\u221E') {
this._limits[i] = Number.NEGATIVE_INFINITY;
}
else {
this._limits[i] = parseFloat(limit);
}
this._lessThan[i] = separator == '#' || separator == '\u2264';
this._formats[i] = new AjxMessageFormat(message);
}
}
else {
this._limits = arguments[0];
this._lessThan = new Array(arguments[0].length);
this._formats = arguments[1];
this._pattern = [];
for (var i = 0; i < this._formats.length; i++) {
if (i > 0) {
this._pattern.push("|");
}
this._pattern.push(this._limits[i], '#', this._formats[i]);
this._lessThan[i] = false;
this._formats[i] = new AjxMessageFormat(this._formats[i]);
}
this._pattern = this._pattern.join("");
}
}
AjxChoiceFormat.prototype = new AjxFormat;
AjxChoiceFormat.prototype.constructor = AjxChoiceFormat;
AjxChoiceFormat.prototype.toString = function() {
return [
"[AjxChoiceFormat: ",
"limits={ ", this._limits.join(", "), " }, ",
"formats={ ", this._formats.join(", "), " }, ",
"lessThan={ ", this._lessThan.join(", "), " }]"
].join("");
};
AjxChoiceFormat.prototype._limits;
AjxChoiceFormat.prototype._lessThan;
AjxChoiceFormat.prototype._formats;
AjxChoiceFormat.prototype.getLimits = function() {
return this._limits;
};
AjxChoiceFormat.prototype.getFormats = function() {
return this._formats;
};
AjxChoiceFormat.prototype.format = function(number) {
var formatter;
if (isNaN(number) || number < this._limits[0]) {
formatter = this._formats[0];
}
else {
for (var i = 0; i < this._limits.length - 1; i++) {
var a = this._limits[i];
var b = this._limits[i+1];
var aGEb = number >= a;
var aLTb = this._lessThan[i+1] ? number < b : number <= b;
if (aGEb && aLTb) {
formatter = this._formats[i];
break;
}
}
if (!formatter) {
formatter = this._formats[this._formats.length-1];
}
}
return formatter.format(number);
};
Documentation generated by
JSDoc on Thu Apr 27 13:58:41 2006