Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adds ordinal method to Number. Adds SC.DateTime#toFormattedString '%o…

…' for the date's day ordinal.
  • Loading branch information...
commit 5018a5c5ecf2ffff53708ef7f5a72bd5a7080a2e 1 parent 5be5d06
@joegaudet joegaudet authored dcporter committed
View
1  .gitignore
@@ -5,6 +5,7 @@
.gitattributes
*.swp
*.swo
+*.iml
themes/sc_ace/resources/slices/
tmp/
bin
View
31 frameworks/core_foundation/system/locale.js
@@ -77,6 +77,13 @@ SC.Locale = SC.Object.extend({
return "SC.Locale["+this.language+"]"+SC.guidFor(this) ;
},
+
+ ordinalForNumber: function(number){
+ var englishFunction = SC.Locale._numberOrdinalFunctions.en,
+ currentFunction = SC.Locale._numberOrdinalFunctions[this.language] || englishFunction;
+ return currentFunction(number);
+ },
+
/**
Returns the localized version of the string or the string if no match
was found.
@@ -226,10 +233,10 @@ SC.Locale.mixin(/** @scope SC.Locale */ {
var autodetect = (String.useAutodetectedLanguage !== undefined) ? String.useAutodetectedLanguage : this.useAutodetectedLanguage;
var preferred = (String.preferredLanguage !== undefined) ? String.preferredLanguage : this.preferredLanguage ;
+
// determine the language
var lang = ((autodetect) ? SC.browser.language : null) || preferred || SC.browser.language || 'en';
lang = SC.Locale.normalizeLanguage(lang) ;
-
// get the locale class. If a class cannot be found, fall back to generic
// language then to english.
var klass = this.localeClassFor(lang) ;
@@ -387,6 +394,24 @@ SC.Locale.mixin(/** @scope SC.Locale */ {
ret.options = SC.Locale.options ;
ret.toString = SC.Locale.toString ;
return ret ;
+ },
+
+ /**
+ * Contains the ordinal functions for each language, these functions are
+ * expected to take a number as the type and return a string
+ *
+ *
+ */
+ _numberOrdinalFunctions: {
+
+ en: function(number) {
+ var d = number % 10;
+ return (~~ (number % 100 / 10) === 1) ? 'th' :
+ (d === 1) ? 'st' :
+ (d === 2) ? 'nd' :
+ (d === 3) ? 'rd' : 'th';
+ }
+
}
}) ;
@@ -404,9 +429,7 @@ SC.Locale.locales = {
de: SC.Locale.extend({ _deprecatedLanguageCodes: ['German'] }),
ja: SC.Locale.extend({ _deprecatedLanguageCodes: ['Japanese', 'jp'] }),
es: SC.Locale.extend({ _deprecatedLanguageCodes: ['Spanish'] })
-} ;
-
-
+};
/**
View
88 frameworks/core_foundation/tests/ext/number_test.js
@@ -0,0 +1,88 @@
+// ==========================================================================
+// Project: SproutCore - JavaScript Application Framework
+// Copyright: ©2006-2011 Strobe Inc. and contributors.
+// Portions ©2008-2011 Apple Inc. All rights reserved.
+// License: Licensed under MIT license (see license.js)
+// ==========================================================================
+/*globals module, test, start, stop, expect, ok, equals*/
+
+module("Number#ordinal");
+
+/**
+ * Admitedly not exhaustive, but tests the numbers from 1-100
+ */
+test("Properly Computes the Ordinal in english", function () {
+
+ equals(SC.Locale.currentLocale.language, 'en');
+
+ var sts = [1, 21, 31, 41, 51, 61, 71, 81, 91, 101],
+ nds = [2, 22, 32, 42, 52, 62, 72, 82, 92, 102],
+ rds = [3, 23, 33, 43, 53, 63, 73, 83, 93, 103];
+ sts.forEach(function (number) {
+ equals(number.ordinal(), 'st');
+ });
+
+ nds.forEach(function (number) {
+ equals(number.ordinal(), 'nd');
+ });
+
+ rds.forEach(function (number) {
+ equals(number.ordinal(), 'rd');
+ });
+
+ var ths = [];
+ for (var i = 0; i < 100; i++) {
+ ths.push(i);
+ }
+
+ ths.removeObjects(sts);
+ ths.removeObjects(nds);
+ ths.removeObjects(rds);
+
+ ths.forEach(function (number) {
+ equals(number.ordinal(), 'th');
+ });
+
+});
+
+/**
+ * Admitedly not exhaustive, but tests the numbers from 1-100
+ */
+test("Properly Computes the Ordinal in a language without an ordinal function using english", function () {
+
+ // force it to japanese
+ String.preferredLanguage = 'jp';
+
+ SC.Locale.currentLocale = SC.Locale.createCurrentLocale();
+
+ equals(SC.Locale.currentLocale.language, 'ja');
+
+ var sts = [1, 21, 31, 41, 51, 61, 71, 81, 91, 101],
+ nds = [2, 22, 32, 42, 52, 62, 72, 82, 92, 102],
+ rds = [3, 23, 33, 43, 53, 63, 73, 83, 93, 103];
+ sts.forEach(function (number) {
+ equals(number.ordinal(), 'st');
+ });
+
+ nds.forEach(function (number) {
+ equals(number.ordinal(), 'nd');
+ });
+
+ rds.forEach(function (number) {
+ equals(number.ordinal(), 'rd');
+ });
+
+ var ths = [];
+ for (var i = 0; i < 100; i++) {
+ ths.push(i);
+ }
+
+ ths.removeObjects(sts);
+ ths.removeObjects(nds);
+ ths.removeObjects(rds);
+
+ ths.forEach(function (number) {
+ equals(number.ordinal(), 'th');
+ });
+
+});
View
13 frameworks/datetime/frameworks/core/system/datetime.js
@@ -421,6 +421,16 @@ SC.DateTime = SC.Object.extend(SC.Freezable, SC.Copyable,
return this.constructor._toFormattedString(SC.DATETIME_ISO8601, this._ms, this.timezone);
},
+ /**
+ Returns the suffix of the date for use in english eg 21st 22nd 22rd
+ speech.
+
+ @return {String}
+ */
+ dayOrdinal: function(){
+ return this.get('day').ordinal();
+ }.property(),
+
/**
@private
@@ -1120,6 +1130,7 @@ SC.DateTime.mixin(SC.Comparable,
case 'j': return this._pad(this._get('dayOfYear'), 3);
case 'm': return this._pad(this._get('month'));
case 'M': return this._pad(this._get('minute'));
+ case 'o': return this._get('day').ordinal();
case 'p': return this._get('hour') > 11 ? this.AMPMNames[1] : this.AMPMNames[0];
case 'S': return this._pad(this._get('second'));
case 's': return this._pad(this._get('millisecond'), 3);
@@ -1152,7 +1163,7 @@ SC.DateTime.mixin(SC.Comparable,
// need to move into local time zone for these calculations
this._setCalcState(start - (timezone * 60000), 0); // so simulate a shifted 'UTC' time
- return format.replace(/\%([aAbBcdeEDhHiIjmMpsSUWwxXyYZ\%])/g, function() {
+ return format.replace(/\%([aAbBcdeEDhHiIjmMopsSUWwxXyYZ\%])/g, function() {
var v = that.__toFormattedString.call(that, arguments, start, timezone);
return v;
});
View
20 frameworks/datetime/frameworks/core/tests/system/datetime.js
@@ -238,6 +238,26 @@ test('Format', function() {
equals(dt.adjust({ timezone: 420 }).toFormattedString('%Y-%m-%d %H:%M:%S %Z'), '1985-06-07 22:00:22 -07:00'); // the previous day
});
+/**
+ * This test only tests english (the default) because Locale is not loaded as
+ * part of this test (bummer)
+ */
+test('Properly Computes day ordinal in toFormattedString', function(){
+ [1, 21, 31].forEach(function(day){
+ equals(SC.DateTime.create({month: 3, day: day}).toFormattedString('%o'), 'st');
+ });
+ [2, 22].forEach(function(day){
+ equals(SC.DateTime.create({month: 3, day: day}).toFormattedString('%o'), 'nd');
+ });
+ [3, 23].forEach(function(day){
+ equals(SC.DateTime.create({month: 3, day: day}).toFormattedString('%o'), 'rd');
+ });
+
+ [4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,25,26,27,28,29,30].forEach(function(day){
+ equals(SC.DateTime.create({month: 3, day: day}).toFormattedString('%o'), 'th');
+ });
+});
+
test('fancy getters', function() {
equals(dt.get('isLeapYear'), NO);
View
34 frameworks/runtime/ext/number.js
@@ -0,0 +1,34 @@
+// ==========================================================================
+// Project: SproutCore - JavaScript Application Framework
+// Copyright: ©2006-2011 Strobe Inc. and contributors.
+// Portions ©2008-2011 Apple Inc. All rights reserved.
+// License: Licensed under MIT license (see license.js)
+// ==========================================================================
+
+SC.supplement(Number.prototype, {
+
+ /**
+ * Returns the oridnal associated for the current number:
+ *
+ * eg: 1 => st, 2 => 2nd
+ *
+ *
+ * If the current Locale exists (which it almost always does except for in
+ * testing) we try and delegate to it. Otherwise we use this inner anonymous
+ * function (to prevent further mucking with the prototype)
+ *
+ */
+ ordinal: function () {
+
+ var _ordinal = function (number) {
+ var d = number % 10;
+ return (~~(number % 100 / 10) === 1) ? 'th' :
+ (d === 1) ? 'st' :
+ (d === 2) ? 'nd' :
+ (d === 3) ? 'rd' : 'th';
+ };
+
+ return SC.Local ? SC.Locale.currentLocale.ordinalForNumber(this) : _ordinal(this);
+ }
+
+});
View
44 frameworks/runtime/tests/ext/number_test.js
@@ -0,0 +1,44 @@
+/*-------------------------------------------------------------------------------------------------
+ - Project: sproutcore -
+ - Copyright: ©2013 Matygo Educational Incorporated operating as Learndot -
+ - Author: Joe Gaudet (joe@learndot.com) and contributors (see contributors.txt) -
+ - License: Licensed under MIT license (see license.js) -
+ -------------------------------------------------------------------------------------------------*/
+/*globals module, test, start, stop, expect, ok, equals*/
+
+module("Number#ordinal");
+
+/**
+ * Admitedly not exhaustive, but tests the numbers from 1-100
+ */
+test("Properly Computes the Ordinal in english", function () {
+ var sts = [1, 21, 31, 41, 51, 61, 71, 81, 91, 101],
+ nds = [2, 22, 32, 42, 52, 62, 72, 82, 92, 102],
+ rds = [3, 23, 33, 43, 53, 63, 73, 83, 93, 103];
+ sts.forEach(function (number) {
+ equals(number.ordinal(), 'st');
+ });
+
+ nds.forEach(function (number) {
+ equals(number.ordinal(), 'nd');
+ });
+
+ rds.forEach(function (number) {
+ equals(number.ordinal(), 'rd');
+ });
+
+ var ths = [];
+ for (var i = 0; i < 100; i++) {
+ ths.push(i);
+ }
+
+ ths.removeObjects(sts);
+ ths.removeObjects(nds);
+ ths.removeObjects(rds);
+
+ ths.forEach(function (number) {
+ equals(number.ordinal(), 'th');
+ });
+
+});
+
Please sign in to comment.
Something went wrong with that request. Please try again.