From f7d8a1ba570fd620d65b377ebe806eac0b578328 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Fri, 22 Oct 2010 06:16:12 +0200
Subject: Porting old spinner implementation to 1.8, dropping some baggage.
---
demos/spinner/default.html | 65 +++++++++++++++++++++++++++++++++++++
demos/spinner/donation.html | 74 ++++++++++++++++++++++++++++++++++++++++++
demos/spinner/hexadecimal.html | 37 +++++++++++++++++++++
demos/spinner/index.html | 20 ++++++++++++
demos/spinner/latlong.html | 60 ++++++++++++++++++++++++++++++++++
demos/spinner/rtl.html | 36 ++++++++++++++++++++
6 files changed, 292 insertions(+)
create mode 100644 demos/spinner/default.html
create mode 100644 demos/spinner/donation.html
create mode 100644 demos/spinner/hexadecimal.html
create mode 100644 demos/spinner/index.html
create mode 100644 demos/spinner/latlong.html
create mode 100644 demos/spinner/rtl.html
(limited to 'demos/spinner')
diff --git a/demos/spinner/default.html b/demos/spinner/default.html
new file mode 100644
index 000000000..d90b73f6d
--- /dev/null
+++ b/demos/spinner/default.html
@@ -0,0 +1,65 @@
+
+
+
+
+ jQuery UI Spinner - Default functionality
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Select a value:
+
+
+
+Toggle disable/enable
+Toggle widget
+
+
+
+Get value
+Set value to 5
+
+
+
+
+
+
+
+
diff --git a/demos/spinner/donation.html b/demos/spinner/donation.html
new file mode 100644
index 000000000..617570b12
--- /dev/null
+++ b/demos/spinner/donation.html
@@ -0,0 +1,74 @@
+
+
+
+
+ jQuery UI Spinner - Default functionality
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Currency
+
+ US $
+ EUR €
+ YEN ¥
+ Australian $
+ Swiss Franc Fr
+ Russian Ruble RUB
+
+
+
+ Select the amount to donate:
+
+
+
+
+
+
+Example of a donation form, with currency selection and amout spinner.
+
+
+
+
+
diff --git a/demos/spinner/hexadecimal.html b/demos/spinner/hexadecimal.html
new file mode 100644
index 000000000..03952a62d
--- /dev/null
+++ b/demos/spinner/hexadecimal.html
@@ -0,0 +1,37 @@
+
+
+
+
+ jQuery UI Spinner - Hexadecimal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hexadecimal spinner:
+
+
+
+
+
+
+Example of a hexadecimal spinner.
+
+
+
+
+
diff --git a/demos/spinner/index.html b/demos/spinner/index.html
new file mode 100644
index 000000000..6d7b980bd
--- /dev/null
+++ b/demos/spinner/index.html
@@ -0,0 +1,20 @@
+
+
+
+ jQuery UI Spinner Demos
+
+
+
+
+
+
diff --git a/demos/spinner/latlong.html b/demos/spinner/latlong.html
new file mode 100644
index 000000000..6b955ba47
--- /dev/null
+++ b/demos/spinner/latlong.html
@@ -0,0 +1,60 @@
+
+
+
+
+ jQuery UI Spinner - Map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Latitude
+
+
+
Longitude
+
+
+
+
+
+
+
+
+Google Maps integration, using spinners to change latidude and longitude.
+
+
+
+
+
diff --git a/demos/spinner/rtl.html b/demos/spinner/rtl.html
new file mode 100644
index 000000000..52d7b1048
--- /dev/null
+++ b/demos/spinner/rtl.html
@@ -0,0 +1,36 @@
+
+
+
+
+ jQuery UI Spinner - Default functionality
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--
cgit v1.2.3
From bc3d283d2c1547ac3d8b5aeb894b2e6290e2d3c6 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Sat, 23 Oct 2010 01:51:12 +0200
Subject: Replaced hexadecimal demo with decimal demo. Updated that and the
currency demo (previously donation) to use globalization plugin with a select
for three different cultures (probably more to come). Updated spinner widget
to use Globalization when available, replacing all number formatting related
options with a single numberformat option.
---
demos/spinner/currency.html | 62 ++
demos/spinner/decimal.html | 58 ++
demos/spinner/donation.html | 74 ---
demos/spinner/hexadecimal.html | 37 --
demos/spinner/index.html | 4 +-
external/glob.de-DE.js | 55 ++
external/glob.ja-JP.js | 74 +++
external/glob.js | 1333 ++++++++++++++++++++++++++++++++++++++++
ui/jquery.ui.spinner.js | 174 ++----
9 files changed, 1628 insertions(+), 243 deletions(-)
create mode 100644 demos/spinner/currency.html
create mode 100644 demos/spinner/decimal.html
delete mode 100644 demos/spinner/donation.html
delete mode 100644 demos/spinner/hexadecimal.html
create mode 100644 external/glob.de-DE.js
create mode 100644 external/glob.ja-JP.js
create mode 100644 external/glob.js
(limited to 'demos/spinner')
diff --git a/demos/spinner/currency.html b/demos/spinner/currency.html
new file mode 100644
index 000000000..418dca228
--- /dev/null
+++ b/demos/spinner/currency.html
@@ -0,0 +1,62 @@
+
+
+
+
+ jQuery UI Spinner - Default functionality
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Currency to donate
+
+ US $
+ EUR €
+ YEN ¥
+
+
+
+ Amount to donate:
+
+
+
+
+
+
+ Example of a donation form, with currency selection and amout spinner.
+
+
+
+
+
diff --git a/demos/spinner/decimal.html b/demos/spinner/decimal.html
new file mode 100644
index 000000000..82d0fcc20
--- /dev/null
+++ b/demos/spinner/decimal.html
@@ -0,0 +1,58 @@
+
+
+
+
+ jQuery UI Spinner - decimal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Decimal spinner:
+
+
+
+ Select a culture to use for formatting:
+
+ English
+ German
+ Japanese
+
+
+
+
+
+
+ Example of a decimal spinner. Step is set to 0.01.
+ The code handling the culture change reads the current spinner value,
+ then changes the culture, then sets the value again, resulting in an updated
+ formatting, based on the new culture.
+
+
+
+
+
diff --git a/demos/spinner/donation.html b/demos/spinner/donation.html
deleted file mode 100644
index 617570b12..000000000
--- a/demos/spinner/donation.html
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
- jQuery UI Spinner - Default functionality
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Currency
-
- US $
- EUR €
- YEN ¥
- Australian $
- Swiss Franc Fr
- Russian Ruble RUB
-
-
-
- Select the amount to donate:
-
-
-
-
-
-
-Example of a donation form, with currency selection and amout spinner.
-
-
-
-
-
diff --git a/demos/spinner/hexadecimal.html b/demos/spinner/hexadecimal.html
deleted file mode 100644
index 03952a62d..000000000
--- a/demos/spinner/hexadecimal.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
- jQuery UI Spinner - Hexadecimal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Hexadecimal spinner:
-
-
-
-
-
-
-Example of a hexadecimal spinner.
-
-
-
-
-
diff --git a/demos/spinner/index.html b/demos/spinner/index.html
index 6d7b980bd..68716ac99 100644
--- a/demos/spinner/index.html
+++ b/demos/spinner/index.html
@@ -9,8 +9,8 @@
Examples
Default functionality
- Donation
- Hexadecimal
+ Decimal
+ Currency
Map
Mousewheel Disabled
RTL
diff --git a/external/glob.de-DE.js b/external/glob.de-DE.js
new file mode 100644
index 000000000..d68b84cc8
--- /dev/null
+++ b/external/glob.de-DE.js
@@ -0,0 +1,55 @@
+(function($) {
+ var cultures = $.cultures,
+ en = cultures.en,
+ standard = en.calendars.standard,
+ culture = cultures["de-DE"] = $.extend(true, {}, en, {
+ name: "de-DE",
+ englishName: "German (Germany)",
+ nativeName: "Deutsch (Deutschland)",
+ language: "de",
+ numberFormat: {
+ ',': ".",
+ '.': ",",
+ percent: {
+ pattern: ["-n%","n%"],
+ ',': ".",
+ '.': ","
+ },
+ currency: {
+ pattern: ["-n $","n $"],
+ ',': ".",
+ '.': ",",
+ symbol: "€"
+ }
+ },
+ calendars: {
+ standard: $.extend(true, {}, standard, {
+ '/': ".",
+ firstDay: 1,
+ days: {
+ names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],
+ namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"],
+ namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"]
+ },
+ months: {
+ names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""],
+ namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""]
+ },
+ AM: null,
+ PM: null,
+ eras: [{"name":"n. Chr.","start":null,"offset":0}],
+ patterns: {
+ d: "dd.MM.yyyy",
+ D: "dddd, d. MMMM yyyy",
+ t: "HH:mm",
+ T: "HH:mm:ss",
+ f: "dddd, d. MMMM yyyy HH:mm",
+ F: "dddd, d. MMMM yyyy HH:mm:ss",
+ M: "dd MMMM",
+ Y: "MMMM yyyy"
+ }
+ })
+ }
+ }, cultures["de-DE"]);
+ culture.calendar = culture.calendars.standard;
+})(Globalization);
\ No newline at end of file
diff --git a/external/glob.ja-JP.js b/external/glob.ja-JP.js
new file mode 100644
index 000000000..454d478cb
--- /dev/null
+++ b/external/glob.ja-JP.js
@@ -0,0 +1,74 @@
+(function($) {
+ var cultures = $.cultures,
+ en = cultures.en,
+ standard = en.calendars.standard,
+ culture = cultures["ja-JP"] = $.extend(true, {}, en, {
+ name: "ja-JP",
+ englishName: "Japanese (Japan)",
+ nativeName: "日本語 (日本)",
+ language: "ja",
+ numberFormat: {
+ percent: {
+ pattern: ["-n%","n%"]
+ },
+ currency: {
+ pattern: ["-$n","$n"],
+ decimals: 0,
+ symbol: "¥"
+ }
+ },
+ calendars: {
+ standard: $.extend(true, {}, standard, {
+ days: {
+ names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],
+ namesAbbr: ["日","月","火","水","木","金","土"],
+ namesShort: ["日","月","火","水","木","金","土"]
+ },
+ months: {
+ names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""],
+ namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""]
+ },
+ AM: ["午前","午前","午前"],
+ PM: ["午後","午後","午後"],
+ eras: [{"name":"西暦","start":null,"offset":0}],
+ patterns: {
+ d: "yyyy/MM/dd",
+ D: "yyyy'年'M'月'd'日'",
+ t: "H:mm",
+ T: "H:mm:ss",
+ f: "yyyy'年'M'月'd'日' H:mm",
+ F: "yyyy'年'M'月'd'日' H:mm:ss",
+ M: "M'月'd'日'",
+ Y: "yyyy'年'M'月'"
+ }
+ }),
+ Japanese: $.extend(true, {}, standard, {
+ name: "Japanese",
+ days: {
+ names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],
+ namesAbbr: ["日","月","火","水","木","金","土"],
+ namesShort: ["日","月","火","水","木","金","土"]
+ },
+ months: {
+ names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""],
+ namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""]
+ },
+ AM: ["午前","午前","午前"],
+ PM: ["午後","午後","午後"],
+ eras: [{"name":"平成","start":null,"offset":1867},{"name":"昭和","start":-1812153600000,"offset":1911},{"name":"大正","start":-1357603200000,"offset":1925},{"name":"明治","start":60022080000,"offset":1988}],
+ twoDigitYearMax: 99,
+ patterns: {
+ d: "gg y/M/d",
+ D: "gg y'年'M'月'd'日'",
+ t: "H:mm",
+ T: "H:mm:ss",
+ f: "gg y'年'M'月'd'日' H:mm",
+ F: "gg y'年'M'月'd'日' H:mm:ss",
+ M: "M'月'd'日'",
+ Y: "gg y'年'M'月'"
+ }
+ })
+ }
+ }, cultures["ja-JP"]);
+ culture.calendar = culture.calendars.standard;
+})(Globalization);
\ No newline at end of file
diff --git a/external/glob.js b/external/glob.js
new file mode 100644
index 000000000..8075ee2bd
--- /dev/null
+++ b/external/glob.js
@@ -0,0 +1,1333 @@
+/*
+ * Globalization
+ * http://github.com/nje/jquery-glob
+ */
+(function() {
+
+var Globalization = {},
+ localized = { en: {} };
+localized["default"] = localized.en;
+
+Globalization.extend = function( deep ) {
+ var target = arguments[ 1 ] || {};
+ for ( var i = 2, l = arguments.length; i < l; i++ ) {
+ var source = arguments[ i ];
+ if ( source ) {
+ for ( var field in source ) {
+ var sourceVal = source[ field ];
+ if ( typeof sourceVal !== "undefined" ) {
+ if ( deep && (isObject( sourceVal ) || isArray( sourceVal )) ) {
+ var targetVal = target[ field ];
+ // extend onto the existing value, or create a new one
+ targetVal = targetVal && (isObject( targetVal ) || isArray( targetVal ))
+ ? targetVal
+ : (isArray( sourceVal ) ? [] : {});
+ target[ field ] = this.extend( true, targetVal, sourceVal );
+ }
+ else {
+ target[ field ] = sourceVal;
+ }
+ }
+ }
+ }
+ }
+ return target;
+}
+
+Globalization.findClosestCulture = function(name) {
+ var match;
+ if ( !name ) {
+ return this.culture || this.cultures["default"];
+ }
+ if ( isString( name ) ) {
+ name = name.split( ',' );
+ }
+ if ( isArray( name ) ) {
+ var lang,
+ cultures = this.cultures,
+ list = name,
+ i, l = list.length,
+ prioritized = [];
+ for ( i = 0; i < l; i++ ) {
+ name = trim( list[ i ] );
+ var pri, parts = name.split( ';' );
+ lang = trim( parts[ 0 ] );
+ if ( parts.length === 1 ) {
+ pri = 1;
+ }
+ else {
+ name = trim( parts[ 1 ] );
+ if ( name.indexOf("q=") === 0 ) {
+ name = name.substr( 2 );
+ pri = parseFloat( name, 10 );
+ pri = isNaN( pri ) ? 0 : pri;
+ }
+ else {
+ pri = 1;
+ }
+ }
+ prioritized.push( { lang: lang, pri: pri } );
+ }
+ prioritized.sort(function(a, b) {
+ return a.pri < b.pri ? 1 : -1;
+ });
+ for ( i = 0; i < l; i++ ) {
+ lang = prioritized[ i ].lang;
+ match = cultures[ lang ];
+ // exact match?
+ if ( match ) {
+ return match;
+ }
+ }
+ for ( i = 0; i < l; i++ ) {
+ lang = prioritized[ i ].lang;
+ // for each entry try its neutral language
+ do {
+ var index = lang.lastIndexOf( "-" );
+ if ( index === -1 ) {
+ break;
+ }
+ // strip off the last part. e.g. en-US => en
+ lang = lang.substr( 0, index );
+ match = cultures[ lang ];
+ if ( match ) {
+ return match;
+ }
+ }
+ while ( 1 );
+ }
+ }
+ else if ( typeof name === 'object' ) {
+ return name;
+ }
+ return match || null;
+}
+Globalization.preferCulture = function(name) {
+ this.culture = this.findClosestCulture( name ) || this.cultures["default"];
+}
+Globalization.localize = function(key, culture, value) {
+ if (typeof culture === 'string') {
+ culture = culture || "default";
+ culture = this.cultures[ culture ] || { name: culture };
+ }
+ var local = localized[ culture.name ];
+ if ( arguments.length === 3 ) {
+ if ( !local) {
+ local = localized[ culture.name ] = {};
+ }
+ local[ key ] = value;
+ }
+ else {
+ if ( local ) {
+ value = local[ key ];
+ }
+ if ( typeof value === 'undefined' ) {
+ var language = localized[ culture.language ];
+ if ( language ) {
+ value = language[ key ];
+ }
+ if ( typeof value === 'undefined' ) {
+ value = localized["default"][ key ];
+ }
+ }
+ }
+ return typeof value === "undefined" ? null : value;
+}
+Globalization.format = function(value, format, culture) {
+ culture = this.findClosestCulture( culture );
+ if ( typeof value === "number" ) {
+ value = formatNumber( value, format, culture );
+ }
+ else if ( value instanceof Date ) {
+ value = formatDate( value, format, culture );
+ }
+ return value;
+}
+Globalization.parseInt = function(value, radix, culture) {
+ return Math.floor( this.parseFloat( value, radix, culture ) );
+}
+Globalization.parseFloat = function(value, radix, culture) {
+ culture = this.findClosestCulture( culture );
+ var ret = NaN,
+ nf = culture.numberFormat;
+
+ // trim leading and trailing whitespace
+ value = trim( value );
+
+ // allow infinity or hexidecimal
+ if (regexInfinity.test(value)) {
+ ret = parseFloat(value, radix);
+ }
+ else if (!radix && regexHex.test(value)) {
+ ret = parseInt(value, 16);
+ }
+ else {
+ var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
+ sign = signInfo[0],
+ num = signInfo[1];
+ // determine sign and number
+ if ( sign === "" && nf.pattern[0] !== "-n" ) {
+ signInfo = parseNegativePattern( value, nf, "-n" );
+ sign = signInfo[0];
+ num = signInfo[1];
+ }
+ sign = sign || "+";
+ // determine exponent and number
+ var exponent,
+ intAndFraction,
+ exponentPos = num.indexOf( 'e' );
+ if ( exponentPos < 0 ) exponentPos = num.indexOf( 'E' );
+ if ( exponentPos < 0 ) {
+ intAndFraction = num;
+ exponent = null;
+ }
+ else {
+ intAndFraction = num.substr( 0, exponentPos );
+ exponent = num.substr( exponentPos + 1 );
+ }
+ // determine decimal position
+ var integer,
+ fraction,
+ decSep = nf['.'],
+ decimalPos = intAndFraction.indexOf( decSep );
+ if ( decimalPos < 0 ) {
+ integer = intAndFraction;
+ fraction = null;
+ }
+ else {
+ integer = intAndFraction.substr( 0, decimalPos );
+ fraction = intAndFraction.substr( decimalPos + decSep.length );
+ }
+ // handle groups (e.g. 1,000,000)
+ var groupSep = nf[","];
+ integer = integer.split(groupSep).join('');
+ var altGroupSep = groupSep.replace(/\u00A0/g, " ");
+ if ( groupSep !== altGroupSep ) {
+ integer = integer.split(altGroupSep).join('');
+ }
+ // build a natively parsable number string
+ var p = sign + integer;
+ if ( fraction !== null ) {
+ p += '.' + fraction;
+ }
+ if ( exponent !== null ) {
+ // exponent itself may have a number patternd
+ var expSignInfo = parseNegativePattern( exponent, nf, "-n" );
+ p += 'e' + (expSignInfo[0] || "+") + expSignInfo[1];
+ }
+ if ( regexParseFloat.test( p ) ) {
+ ret = parseFloat( p );
+ }
+ }
+ return ret;
+}
+Globalization.parseDate = function(value, formats, culture) {
+ culture = this.findClosestCulture( culture );
+
+ var date, prop, patterns;
+ if ( formats ) {
+ if ( typeof formats === "string" ) {
+ formats = [ formats ];
+ }
+ if ( formats.length ) {
+ for ( var i = 0, l = formats.length; i < l; i++ ) {
+ var format = formats[ i ];
+ if ( format ) {
+ date = parseExact( value, format, culture );
+ if ( date ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ patterns = culture.calendar.patterns;
+ for ( prop in patterns ) {
+ date = parseExact( value, patterns[prop], culture );
+ if ( date ) {
+ break;
+ }
+ }
+ }
+ return date || null;
+}
+
+// 1. When defining a culture, all fields are required except the ones stated as optional.
+// 2. You can use Globalization.extend to copy an existing culture and provide only the differing values,
+// a good practice since most cultures do not differ too much from the 'default' culture.
+// DO use the 'default' culture if you do this, as it is the only one that definitely
+// exists.
+// 3. Other plugins may add to the culture information provided by extending it. However,
+// that plugin may extend it prior to the culture being defined, or after. Therefore,
+// do not overwrite values that already exist when defining the baseline for a culture,
+// by extending your culture object with the existing one.
+// 4. Each culture should have a ".calendars" object with at least one calendar named "standard"
+// which serves as the default calendar in use by that culture.
+// 5. Each culture should have a ".calendar" object which is the current calendar being used,
+// it may be dynamically changed at any time to one of the calendars in ".calendars".
+
+// To define a culture, use the following pattern, which handles defining the culture based
+// on the 'default culture, extending it with the existing culture if it exists, and defining
+// it if it does not exist.
+// Globalization.cultures.foo = Globalization.extend(true, Globalization.extend(true, {}, Globalization.cultures['default'], fooCulture), Globalization.cultures.foo)
+
+var cultures = Globalization.cultures = Globalization.cultures || {};
+var en = cultures["default"] = cultures.en = Globalization.extend(true, {
+ // A unique name for the culture in the form -
+ name: "en",
+ // the name of the culture in the english language
+ englishName: "English",
+ // the name of the culture in its own language
+ nativeName: "English",
+ // whether the culture uses right-to-left text
+ isRTL: false,
+ // 'language' is used for so-called "specific" cultures.
+ // For example, the culture "es-CL" means "Spanish, in Chili".
+ // It represents the Spanish-speaking culture as it is in Chili,
+ // which might have different formatting rules or even translations
+ // than Spanish in Spain. A "neutral" culture is one that is not
+ // specific to a region. For example, the culture "es" is the generic
+ // Spanish culture, which may be a more generalized version of the language
+ // that may or may not be what a specific culture expects.
+ // For a specific culture like "es-CL", the 'language' field refers to the
+ // neutral, generic culture information for the language it is using.
+ // This is not always a simple matter of the string before the dash.
+ // For example, the "zh-Hans" culture is netural (Simplified Chinese).
+ // And the 'zh-SG' culture is Simplified Chinese in Singapore, whose lanugage
+ // field is "zh-CHS", not "zh".
+ // This field should be used to navigate from a specific culture to it's
+ // more general, neutral culture. If a culture is already as general as it
+ // can get, the language may refer to itself.
+ language: "en",
+ // numberFormat defines general number formatting rules, like the digits in
+ // each grouping, the group separator, and how negative numbers are displayed.
+ numberFormat: {
+ // [negativePattern]
+ // Note, numberFormat.pattern has no 'positivePattern' unlike percent and currency,
+ // but is still defined as an array for consistency with them.
+ // negativePattern: one of "(n)|-n|- n|n-|n -"
+ pattern: ["-n"],
+ // number of decimal places normally shown
+ decimals: 2,
+ // string that separates number groups, as in 1,000,000
+ ',': ",",
+ // string that separates a number from the fractional portion, as in 1.99
+ '.': ".",
+ // array of numbers indicating the size of each number group.
+ // TODO: more detailed description and example
+ groupSizes: [3],
+ // symbol used for positive numbers
+ '+': "+",
+ // symbol used for negative numbers
+ '-': "-",
+ percent: {
+ // [negativePattern, positivePattern]
+ // negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %"
+ // positivePattern: one of "n %|n%|%n|% n"
+ pattern: ["-n %","n %"],
+ // number of decimal places normally shown
+ decimals: 2,
+ // array of numbers indicating the size of each number group.
+ // TODO: more detailed description and example
+ groupSizes: [3],
+ // string that separates number groups, as in 1,000,000
+ ',': ",",
+ // string that separates a number from the fractional portion, as in 1.99
+ '.': ".",
+ // symbol used to represent a percentage
+ symbol: "%"
+ },
+ currency: {
+ // [negativePattern, positivePattern]
+ // negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)"
+ // positivePattern: one of "$n|n$|$ n|n $"
+ pattern: ["($n)","$n"],
+ // number of decimal places normally shown
+ decimals: 2,
+ // array of numbers indicating the size of each number group.
+ // TODO: more detailed description and example
+ groupSizes: [3],
+ // string that separates number groups, as in 1,000,000
+ ',': ",",
+ // string that separates a number from the fractional portion, as in 1.99
+ '.': ".",
+ // symbol used to represent currency
+ symbol: "$"
+ }
+ },
+ // calendars defines all the possible calendars used by this culture.
+ // There should be at least one defined with name 'standard', and is the default
+ // calendar used by the culture.
+ // A calendar contains information about how dates are formatted, information about
+ // the calendar's eras, a standard set of the date formats,
+ // translations for day and month names, and if the calendar is not based on the Gregorian
+ // calendar, conversion functions to and from the Gregorian calendar.
+ calendars: {
+ standard: {
+ // name that identifies the type of calendar this is
+ name: "Gregorian_USEnglish",
+ // separator of parts of a date (e.g. '/' in 11/05/1955)
+ '/': "/",
+ // separator of parts of a time (e.g. ':' in 05:44 PM)
+ ':': ":",
+ // the first day of the week (0 = Sunday, 1 = Monday, etc)
+ firstDay: 0,
+ days: {
+ // full day names
+ names: ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
+ // abbreviated day names
+ namesAbbr: ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],
+ // shortest day names
+ namesShort: ["Su","Mo","Tu","We","Th","Fr","Sa"]
+ },
+ months: {
+ // full month names (13 months for lunar calendards -- 13th month should be "" if not lunar)
+ names: ["January","February","March","April","May","June","July","August","September","October","November","December",""],
+ // abbreviated month names
+ namesAbbr: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""]
+ },
+ // AM and PM designators in one of these forms:
+ // The usual view, and the upper and lower case versions
+ // [standard,lowercase,uppercase]
+ // The culture does not use AM or PM (likely all standard date formats use 24 hour time)
+ // null
+ AM: ["AM", "am", "AM"],
+ PM: ["PM", "pm", "PM"],
+ eras: [
+ // eras in reverse chronological order.
+ // name: the name of the era in this culture (e.g. A.D., C.E.)
+ // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era.
+ // offset: offset in years from gregorian calendar
+ { "name": "A.D.", "start": null, "offset": 0 }
+ ],
+ // when a two digit year is given, it will never be parsed as a four digit
+ // year greater than this year (in the appropriate era for the culture)
+ // Set it as a full year (e.g. 2029) or use an offset format starting from
+ // the current year: "+19" would correspond to 2029 if the current year 2010.
+ twoDigitYearMax: 2029,
+ // set of predefined date and time patterns used by the culture
+ // these represent the format someone in this culture would expect
+ // to see given the portions of the date that are shown.
+ patterns: {
+ // short date pattern
+ d: "M/d/yyyy",
+ // long date pattern
+ D: "dddd, MMMM dd, yyyy",
+ // short time pattern
+ t: "h:mm tt",
+ // long time pattern
+ T: "h:mm:ss tt",
+ // long date, short time pattern
+ f: "dddd, MMMM dd, yyyy h:mm tt",
+ // long date, long time pattern
+ F: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ // month/day pattern
+ M: "MMMM dd",
+ // month/year pattern
+ Y: "yyyy MMMM",
+ // S is a sortable format that does not vary by culture
+ S: "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss"
+ }
+ // optional fields for each calendar:
+ /*
+ monthsGenitive:
+ Same as months but used when the day preceeds the month.
+ Omit if the culture has no genitive distinction in month names.
+ For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx
+ convert:
+ Allows for the support of non-gregorian based calendars. This convert object is used to
+ to convert a date to and from a gregorian calendar date to handle parsing and formatting.
+ The two functions:
+ fromGregorian(date)
+ Given the date as a parameter, return an array with parts [year, month, day]
+ corresponding to the non-gregorian based year, month, and day for the calendar.
+ toGregorian(year, month, day)
+ Given the non-gregorian year, month, and day, return a new Date() object
+ set to the corresponding date in the gregorian calendar.
+ */
+ }
+ }
+}, cultures.en);
+en.calendar = en.calendar || en.calendars.standard;
+
+var regexTrim = /^\s+|\s+$/g,
+ regexInfinity = /^[+-]?infinity$/i,
+ regexHex = /^0x[a-f0-9]+$/i,
+ regexParseFloat = /^[+-]?\d*\.?\d*(e[+-]?\d+)?$/,
+ toString = Object.prototype.toString;
+
+function startsWith(value, pattern) {
+ return value.indexOf( pattern ) === 0;
+}
+
+function endsWith(value, pattern) {
+ return value.substr( value.length - pattern.length ) === pattern;
+}
+
+function trim(value) {
+ return (value+"").replace( regexTrim, "" );
+}
+
+function zeroPad(str, count, left) {
+ for (var l=str.length; l < count; l++) {
+ str = (left ? ('0' + str) : (str + '0'));
+ }
+ return str;
+}
+
+function isArray(obj) {
+ return toString.call(obj) === "[object Array]";
+}
+
+function isString(obj) {
+ return toString.call(obj) === "[object String]";
+}
+
+function isObject(obj) {
+ return toString.call(obj) === "[object Object]";
+}
+
+function arrayIndexOf( array, item ) {
+ if ( array.indexOf ) {
+ return array.indexOf( item );
+ }
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === item ) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// *************************************** Numbers ***************************************
+
+function expandNumber(number, precision, formatInfo) {
+ var groupSizes = formatInfo.groupSizes,
+ curSize = groupSizes[ 0 ],
+ curGroupIndex = 1,
+ factor = Math.pow( 10, precision ),
+ rounded = Math.round( number * factor ) / factor;
+ if ( !isFinite(rounded) ) {
+ rounded = number;
+ }
+ number = rounded;
+
+ var numberString = number+"",
+ right = "",
+ split = numberString.split(/e/i),
+ exponent = split.length > 1 ? parseInt( split[ 1 ], 10 ) : 0;
+ numberString = split[ 0 ];
+ split = numberString.split( "." );
+ numberString = split[ 0 ];
+ right = split.length > 1 ? split[ 1 ] : "";
+
+ var l;
+ if ( exponent > 0 ) {
+ right = zeroPad( right, exponent, false );
+ numberString += right.slice( 0, exponent );
+ right = right.substr( exponent );
+ }
+ else if ( exponent < 0 ) {
+ exponent = -exponent;
+ numberString = zeroPad( numberString, exponent + 1 );
+ right = numberString.slice( -exponent, numberString.length ) + right;
+ numberString = numberString.slice( 0, -exponent );
+ }
+
+ if ( precision > 0 ) {
+ right = formatInfo['.'] +
+ ((right.length > precision) ? right.slice( 0, precision ) : zeroPad( right, precision ));
+ }
+ else {
+ right = "";
+ }
+
+ var stringIndex = numberString.length - 1,
+ sep = formatInfo[","],
+ ret = "";
+
+ while ( stringIndex >= 0 ) {
+ if ( curSize === 0 || curSize > stringIndex ) {
+ return numberString.slice( 0, stringIndex + 1 ) + ( ret.length ? ( sep + ret + right ) : right );
+ }
+ ret = numberString.slice( stringIndex - curSize + 1, stringIndex + 1 ) + ( ret.length ? ( sep + ret ) : "" );
+
+ stringIndex -= curSize;
+
+ if ( curGroupIndex < groupSizes.length ) {
+ curSize = groupSizes[ curGroupIndex ];
+ curGroupIndex++;
+ }
+ }
+ return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right;
+}
+
+
+function parseNegativePattern(value, nf, negativePattern) {
+ var neg = nf["-"],
+ pos = nf["+"],
+ ret;
+ switch (negativePattern) {
+ case "n -":
+ neg = ' ' + neg;
+ pos = ' ' + pos;
+ // fall through
+ case "n-":
+ if ( endsWith( value, neg ) ) {
+ ret = [ '-', value.substr( 0, value.length - neg.length ) ];
+ }
+ else if ( endsWith( value, pos ) ) {
+ ret = [ '+', value.substr( 0, value.length - pos.length ) ];
+ }
+ break;
+ case "- n":
+ neg += ' ';
+ pos += ' ';
+ // fall through
+ case "-n":
+ if ( startsWith( value, neg ) ) {
+ ret = [ '-', value.substr( neg.length ) ];
+ }
+ else if ( startsWith(value, pos) ) {
+ ret = [ '+', value.substr( pos.length ) ];
+ }
+ break;
+ case "(n)":
+ if ( startsWith( value, '(' ) && endsWith( value, ')' ) ) {
+ ret = [ '-', value.substr( 1, value.length - 2 ) ];
+ }
+ break;
+ }
+ return ret || [ '', value ];
+}
+
+function formatNumber(value, format, culture) {
+ if ( !format || format === 'i' ) {
+ return culture.name.length ? value.toLocaleString() : value.toString();
+ }
+ format = format || "D";
+
+ var nf = culture.numberFormat,
+ number = Math.abs(value),
+ precision = -1,
+ pattern;
+ if (format.length > 1) precision = parseInt( format.slice( 1 ), 10 );
+
+ var current = format.charAt( 0 ).toUpperCase(),
+ formatInfo;
+
+ switch (current) {
+ case "D":
+ pattern = 'n';
+ if (precision !== -1) {
+ number = zeroPad( ""+number, precision, true );
+ }
+ if (value < 0) number = -number;
+ break;
+ case "N":
+ formatInfo = nf;
+ // fall through
+ case "C":
+ formatInfo = formatInfo || nf.currency;
+ // fall through
+ case "P":
+ formatInfo = formatInfo || nf.percent;
+ pattern = value < 0 ? formatInfo.pattern[0] : (formatInfo.pattern[1] || "n");
+ if (precision === -1) precision = formatInfo.decimals;
+ number = expandNumber( number * (current === "P" ? 100 : 1), precision, formatInfo );
+ break;
+ default:
+ throw "Bad number format specifier: " + current;
+ }
+
+ var patternParts = /n|\$|-|%/g,
+ ret = "";
+ for (;;) {
+ var index = patternParts.lastIndex,
+ ar = patternParts.exec(pattern);
+
+ ret += pattern.slice( index, ar ? ar.index : pattern.length );
+
+ if (!ar) {
+ break;
+ }
+
+ switch (ar[0]) {
+ case "n":
+ ret += number;
+ break;
+ case "$":
+ ret += nf.currency.symbol;
+ break;
+ case "-":
+ // don't make 0 negative
+ if ( /[1-9]/.test( number ) ) {
+ ret += nf["-"];
+ }
+ break;
+ case "%":
+ ret += nf.percent.symbol;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+// *************************************** Dates ***************************************
+
+function outOfRange(value, low, high) {
+ return value < low || value > high;
+}
+
+function expandYear(cal, year) {
+ // expands 2-digit year into 4 digits.
+ var now = new Date(),
+ era = getEra(now);
+ if ( year < 100 ) {
+ var twoDigitYearMax = cal.twoDigitYearMax;
+ twoDigitYearMax = typeof twoDigitYearMax === 'string' ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
+ var curr = getEraYear( now, cal, era );
+ year += curr - ( curr % 100 );
+ if ( year > twoDigitYearMax ) {
+ year -= 100;
+ }
+ }
+ return year;
+}
+
+function getEra(date, eras) {
+ if ( !eras ) return 0;
+ var start, ticks = date.getTime();
+ for ( var i = 0, l = eras.length; i < l; i++ ) {
+ start = eras[ i ].start;
+ if ( start === null || ticks >= start ) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+function toUpper(value) {
+ // 'he-IL' has non-breaking space in weekday names.
+ return value.split( "\u00A0" ).join(' ').toUpperCase();
+}
+
+function toUpperArray(arr) {
+ var results = [];
+ for ( var i = 0, l = arr.length; i < l; i++ ) {
+ results[i] = toUpper(arr[i]);
+ }
+ return results;
+}
+
+function getEraYear(date, cal, era, sortable) {
+ var year = date.getFullYear();
+ if ( !sortable && cal.eras ) {
+ // convert normal gregorian year to era-shifted gregorian
+ // year by subtracting the era offset
+ year -= cal.eras[ era ].offset;
+ }
+ return year;
+}
+
+function getDayIndex(cal, value, abbr) {
+ var ret,
+ days = cal.days,
+ upperDays = cal._upperDays;
+ if ( !upperDays ) {
+ cal._upperDays = upperDays = [
+ toUpperArray( days.names ),
+ toUpperArray( days.namesAbbr ),
+ toUpperArray( days.namesShort )
+ ];
+ }
+ value = toUpper( value );
+ if ( abbr ) {
+ ret = arrayIndexOf( upperDays[ 1 ], value );
+ if ( ret === -1 ) {
+ ret = arrayIndexOf( upperDays[ 2 ], value );
+ }
+ }
+ else {
+ ret = arrayIndexOf( upperDays[ 0 ], value );
+ }
+ return ret;
+}
+
+function getMonthIndex(cal, value, abbr) {
+ var months = cal.months,
+ monthsGen = cal.monthsGenitive || cal.months,
+ upperMonths = cal._upperMonths,
+ upperMonthsGen = cal._upperMonthsGen;
+ if ( !upperMonths ) {
+ cal._upperMonths = upperMonths = [
+ toUpperArray( months.names ),
+ toUpperArray( months.namesAbbr ),
+ ];
+ cal._upperMonthsGen = upperMonthsGen = [
+ toUpperArray( monthsGen.names ),
+ toUpperArray( monthsGen.namesAbbr )
+ ];
+ }
+ value = toUpper( value );
+ var i = arrayIndexOf( abbr ? upperMonths[ 1 ] : upperMonths[ 0 ], value );
+ if ( i < 0 ) {
+ i = arrayIndexOf( abbr ? upperMonthsGen[ 1 ] : upperMonthsGen[ 0 ], value );
+ }
+ return i;
+}
+
+function appendPreOrPostMatch(preMatch, strings) {
+ // appends pre- and post- token match strings while removing escaped characters.
+ // Returns a single quote count which is used to determine if the token occurs
+ // in a string literal.
+ var quoteCount = 0,
+ escaped = false;
+ for ( var i = 0, il = preMatch.length; i < il; i++ ) {
+ var c = preMatch.charAt( i );
+ switch ( c ) {
+ case '\'':
+ if ( escaped ) {
+ strings.push( "'" );
+ }
+ else {
+ quoteCount++;
+ }
+ escaped = false;
+ break;
+ case '\\':
+ if ( escaped ) {
+ strings.push( "\\" );
+ }
+ escaped = !escaped;
+ break;
+ default:
+ strings.push( c );
+ escaped = false;
+ break;
+ }
+ }
+ return quoteCount;
+}
+
+function expandFormat(cal, format) {
+ // expands unspecified or single character date formats into the full pattern.
+ format = format || "F";
+ var pattern,
+ patterns = cal.patterns,
+ len = format.length;
+ if ( len === 1 ) {
+ pattern = patterns[ format ];
+ if ( !pattern ) {
+ throw "Invalid date format string '" + format + "'.";
+ }
+ format = pattern;
+ }
+ else if ( len === 2 && format.charAt(0) === "%" ) {
+ // %X escape format -- intended as a custom format string that is only one character, not a built-in format.
+ format = format.charAt( 1 );
+ }
+ return format;
+}
+
+function getParseRegExp(cal, format) {
+ // converts a format string into a regular expression with groups that
+ // can be used to extract date fields from a date string.
+ // check for a cached parse regex.
+ var re = cal._parseRegExp;
+ if ( !re ) {
+ cal._parseRegExp = re = {};
+ }
+ else {
+ var reFormat = re[ format ];
+ if ( reFormat ) {
+ return reFormat;
+ }
+ }
+
+ // expand single digit formats, then escape regular expression characters.
+ var expFormat = expandFormat( cal, format ).replace( /([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g, "\\\\$1" ),
+ regexp = ["^"],
+ groups = [],
+ index = 0,
+ quoteCount = 0,
+ tokenRegExp = getTokenRegExp(),
+ match;
+
+ // iterate through each date token found.
+ while ( (match = tokenRegExp.exec( expFormat )) !== null ) {
+ var preMatch = expFormat.slice( index, match.index );
+ index = tokenRegExp.lastIndex;
+
+ // don't replace any matches that occur inside a string literal.
+ quoteCount += appendPreOrPostMatch( preMatch, regexp );
+ if ( quoteCount % 2 ) {
+ regexp.push( match[ 0 ] );
+ continue;
+ }
+
+ // add a regex group for the token.
+ var m = match[ 0 ],
+ len = m.length,
+ add;
+ switch ( m ) {
+ case 'dddd': case 'ddd':
+ case 'MMMM': case 'MMM':
+ case 'gg': case 'g':
+ add = "(\\D+)";
+ break;
+ case 'tt': case 't':
+ add = "(\\D*)";
+ break;
+ case 'yyyy':
+ case 'fff':
+ case 'ff':
+ case 'f':
+ add = "(\\d{" + len + "})";
+ break;
+ case 'dd': case 'd':
+ case 'MM': case 'M':
+ case 'yy': case 'y':
+ case 'HH': case 'H':
+ case 'hh': case 'h':
+ case 'mm': case 'm':
+ case 'ss': case 's':
+ add = "(\\d\\d?)";
+ break;
+ case 'zzz':
+ add = "([+-]?\\d\\d?:\\d{2})";
+ break;
+ case 'zz': case 'z':
+ add = "([+-]?\\d\\d?)";
+ break;
+ case '/':
+ add = "(\\" + cal["/"] + ")";
+ break;
+ default:
+ throw "Invalid date format pattern '" + m + "'.";
+ break;
+ }
+ if ( add ) {
+ regexp.push( add );
+ }
+ groups.push( match[ 0 ] );
+ }
+ appendPreOrPostMatch( expFormat.slice( index ), regexp );
+ regexp.push( "$" );
+
+ // allow whitespace to differ when matching formats.
+ var regexpStr = regexp.join( '' ).replace( /\s+/g, "\\s+" ),
+ parseRegExp = {'regExp': regexpStr, 'groups': groups};
+
+ // cache the regex for this format.
+ return re[ format ] = parseRegExp;
+}
+
+function getTokenRegExp() {
+ // regular expression for matching date and time tokens in format strings.
+ return /\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g;
+}
+
+function parseExact(value, format, culture) {
+ // try to parse the date string by matching against the format string
+ // while using the specified culture for date field names.
+ value = trim( value );
+ var cal = culture.calendar,
+ // convert date formats into regular expressions with groupings.
+ // use the regexp to determine the input format and extract the date fields.
+ parseInfo = getParseRegExp(cal, format),
+ match = new RegExp(parseInfo.regExp).exec(value);
+ if (match === null) {
+ return null;
+ }
+ // found a date format that matches the input.
+ var groups = parseInfo.groups,
+ era = null, year = null, month = null, date = null, weekDay = null,
+ hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null,
+ pmHour = false;
+ // iterate the format groups to extract and set the date fields.
+ for ( var j = 0, jl = groups.length; j < jl; j++ ) {
+ var matchGroup = match[ j + 1 ];
+ if ( matchGroup ) {
+ var current = groups[ j ],
+ clength = current.length,
+ matchInt = parseInt( matchGroup, 10 );
+ switch ( current ) {
+ case 'dd': case 'd':
+ // Day of month.
+ date = matchInt;
+ // check that date is generally in valid range, also checking overflow below.
+ if ( outOfRange( date, 1, 31 ) ) return null;
+ break;
+ case 'MMM':
+ case 'MMMM':
+ month = getMonthIndex( cal, matchGroup, clength === 3 );
+ if ( outOfRange( month, 0, 11 ) ) return null;
+ break;
+ case 'M': case 'MM':
+ // Month.
+ month = matchInt - 1;
+ if ( outOfRange( month, 0, 11 ) ) return null;
+ break;
+ case 'y': case 'yy':
+ case 'yyyy':
+ year = clength < 4 ? expandYear( cal, matchInt ) : matchInt;
+ if ( outOfRange( year, 0, 9999 ) ) return null;
+ break;
+ case 'h': case 'hh':
+ // Hours (12-hour clock).
+ hour = matchInt;
+ if ( hour === 12 ) hour = 0;
+ if ( outOfRange( hour, 0, 11 ) ) return null;
+ break;
+ case 'H': case 'HH':
+ // Hours (24-hour clock).
+ hour = matchInt;
+ if ( outOfRange( hour, 0, 23 ) ) return null;
+ break;
+ case 'm': case 'mm':
+ // Minutes.
+ min = matchInt;
+ if ( outOfRange( min, 0, 59 ) ) return null;
+ break;
+ case 's': case 'ss':
+ // Seconds.
+ sec = matchInt;
+ if ( outOfRange( sec, 0, 59 ) ) return null;
+ break;
+ case 'tt': case 't':
+ // AM/PM designator.
+ // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of
+ // the AM tokens. If not, fail the parse for this format.
+ pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] );
+ if ( !pmHour && ( !cal.AM || (matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2]) ) ) return null;
+ break;
+ case 'f':
+ // Deciseconds.
+ case 'ff':
+ // Centiseconds.
+ case 'fff':
+ // Milliseconds.
+ msec = matchInt * Math.pow( 10, 3-clength );
+ if ( outOfRange( msec, 0, 999 ) ) return null;
+ break;
+ case 'ddd':
+ // Day of week.
+ case 'dddd':
+ // Day of week.
+ weekDay = getDayIndex( cal, matchGroup, clength === 3 );
+ if ( outOfRange( weekDay, 0, 6 ) ) return null;
+ break;
+ case 'zzz':
+ // Time zone offset in +/- hours:min.
+ var offsets = matchGroup.split( /:/ );
+ if ( offsets.length !== 2 ) return null;
+ hourOffset = parseInt( offsets[ 0 ], 10 );
+ if ( outOfRange( hourOffset, -12, 13 ) ) return null;
+ var minOffset = parseInt( offsets[ 1 ], 10 );
+ if ( outOfRange( minOffset, 0, 59 ) ) return null;
+ tzMinOffset = (hourOffset * 60) + (startsWith( matchGroup, '-' ) ? -minOffset : minOffset);
+ break;
+ case 'z': case 'zz':
+ // Time zone offset in +/- hours.
+ hourOffset = matchInt;
+ if ( outOfRange( hourOffset, -12, 13 ) ) return null;
+ tzMinOffset = hourOffset * 60;
+ break;
+ case 'g': case 'gg':
+ var eraName = matchGroup;
+ if ( !eraName || !cal.eras ) return null;
+ eraName = trim( eraName.toLowerCase() );
+ for ( var i = 0, l = cal.eras.length; i < l; i++ ) {
+ if ( eraName === cal.eras[ i ].name.toLowerCase() ) {
+ era = i;
+ break;
+ }
+ }
+ // could not find an era with that name
+ if ( era === null ) return null;
+ break;
+ }
+ }
+ }
+ var result = new Date(), defaultYear, convert = cal.convert;
+ defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear();
+ if ( year === null ) {
+ year = defaultYear;
+ }
+ else if ( cal.eras ) {
+ // year must be shifted to normal gregorian year
+ // but not if year was not specified, its already normal gregorian
+ // per the main if clause above.
+ year += cal.eras[ (era || 0) ].offset;
+ }
+ // set default day and month to 1 and January, so if unspecified, these are the defaults
+ // instead of the current day/month.
+ if ( month === null ) {
+ month = 0;
+ }
+ if ( date === null ) {
+ date = 1;
+ }
+ // now have year, month, and date, but in the culture's calendar.
+ // convert to gregorian if necessary
+ if ( convert ) {
+ result = convert.toGregorian( year, month, date );
+ // conversion failed, must be an invalid match
+ if ( result === null ) return null;
+ }
+ else {
+ // have to set year, month and date together to avoid overflow based on current date.
+ result.setFullYear( year, month, date );
+ // check to see if date overflowed for specified month (only checked 1-31 above).
+ if ( result.getDate() !== date ) return null;
+ // invalid day of week.
+ if ( weekDay !== null && result.getDay() !== weekDay ) {
+ return null;
+ }
+ }
+ // if pm designator token was found make sure the hours fit the 24-hour clock.
+ if ( pmHour && hour < 12 ) {
+ hour += 12;
+ }
+ result.setHours( hour, min, sec, msec );
+ if ( tzMinOffset !== null ) {
+ // adjust timezone to utc before applying local offset.
+ var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() );
+ // Safari limits hours and minutes to the range of -127 to 127. We need to use setHours
+ // to ensure both these fields will not exceed this range. adjustedMin will range
+ // somewhere between -1440 and 1500, so we only need to split this into hours.
+ result.setHours( result.getHours() + parseInt( adjustedMin / 60, 10 ), adjustedMin % 60 );
+ }
+ return result;
+}
+
+function formatDate(value, format, culture) {
+ var cal = culture.calendar,
+ convert = cal.convert;
+ if ( !format || !format.length || format === 'i' ) {
+ var ret;
+ if ( culture && culture.name.length ) {
+ if ( convert ) {
+ // non-gregorian calendar, so we cannot use built-in toLocaleString()
+ ret = formatDate( value, cal.patterns.F, culture );
+ }
+ else {
+ var eraDate = new Date( value.getTime() ),
+ era = getEra( value, cal.eras );
+ eraDate.setFullYear( getEraYear( value, cal, era ) );
+ ret = eraDate.toLocaleString();
+ }
+ }
+ else {
+ ret = value.toString();
+ }
+ return ret;
+ }
+
+ var eras = cal.eras,
+ sortable = format === "s";
+ format = expandFormat( cal, format );
+
+ // Start with an empty string
+ ret = [];
+ var hour,
+ zeros = ['0','00','000'],
+ foundDay,
+ checkedDay,
+ dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g,
+ quoteCount = 0,
+ tokenRegExp = getTokenRegExp(),
+ converted;
+
+ function padZeros(num, c) {
+ var r, s = num+'';
+ if ( c > 1 && s.length < c ) {
+ r = ( zeros[ c - 2 ] + s);
+ return r.substr( r.length - c, c );
+ }
+ else {
+ r = s;
+ }
+ return r;
+ }
+
+ function hasDay() {
+ if ( foundDay || checkedDay ) {
+ return foundDay;
+ }
+ foundDay = dayPartRegExp.test( format );
+ checkedDay = true;
+ return foundDay;
+ }
+
+ function getPart( date, part ) {
+ if ( converted ) {
+ return converted[ part ];
+ }
+ switch ( part ) {
+ case 0: return date.getFullYear();
+ case 1: return date.getMonth();
+ case 2: return date.getDate();
+ }
+ }
+
+ if ( !sortable && convert ) {
+ converted = convert.fromGregorian( value );
+ }
+
+ for (;;) {
+ // Save the current index
+ var index = tokenRegExp.lastIndex,
+ // Look for the next pattern
+ ar = tokenRegExp.exec( format );
+
+ // Append the text before the pattern (or the end of the string if not found)
+ var preMatch = format.slice( index, ar ? ar.index : format.length );
+ quoteCount += appendPreOrPostMatch( preMatch, ret );
+
+ if ( !ar ) {
+ break;
+ }
+
+ // do not replace any matches that occur inside a string literal.
+ if ( quoteCount % 2 ) {
+ ret.push( ar[ 0 ] );
+ continue;
+ }
+
+ var current = ar[ 0 ],
+ clength = current.length;
+
+ switch ( current ) {
+ case "ddd":
+ //Day of the week, as a three-letter abbreviation
+ case "dddd":
+ // Day of the week, using the full name
+ names = (clength === 3) ? cal.days.namesAbbr : cal.days.names;
+ ret.push( names[ value.getDay() ] );
+ break;
+ case "d":
+ // Day of month, without leading zero for single-digit days
+ case "dd":
+ // Day of month, with leading zero for single-digit days
+ foundDay = true;
+ ret.push( padZeros( getPart( value, 2 ), clength ) );
+ break;
+ case "MMM":
+ // Month, as a three-letter abbreviation
+ case "MMMM":
+ // Month, using the full name
+ var part = getPart( value, 1 );
+ ret.push( (cal.monthsGenitive && hasDay())
+ ? cal.monthsGenitive[ clength === 3 ? "namesAbbr" : "names" ][ part ]
+ : cal.months[ clength === 3 ? "namesAbbr" : "names" ][ part ] );
+ break;
+ case "M":
+ // Month, as digits, with no leading zero for single-digit months
+ case "MM":
+ // Month, as digits, with leading zero for single-digit months
+ ret.push( padZeros( getPart( value, 1 ) + 1, clength ) );
+ break;
+ case "y":
+ // Year, as two digits, but with no leading zero for years less than 10
+ case "yy":
+ // Year, as two digits, with leading zero for years less than 10
+ case "yyyy":
+ // Year represented by four full digits
+ part = converted ? converted[ 0 ] : getEraYear( value, cal, getEra( value, eras ), sortable );
+ if ( clength < 4 ) {
+ part = part % 100;
+ }
+ ret.push( padZeros( part, clength ) );
+ break;
+ case "h":
+ // Hours with no leading zero for single-digit hours, using 12-hour clock
+ case "hh":
+ // Hours with leading zero for single-digit hours, using 12-hour clock
+ hour = value.getHours() % 12;
+ if ( hour === 0 ) hour = 12;
+ ret.push( padZeros( hour, clength ) );
+ break;
+ case "H":
+ // Hours with no leading zero for single-digit hours, using 24-hour clock
+ case "HH":
+ // Hours with leading zero for single-digit hours, using 24-hour clock
+ ret.push( padZeros( value.getHours(), clength ) );
+ break;
+ case "m":
+ // Minutes with no leading zero for single-digit minutes
+ case "mm":
+ // Minutes with leading zero for single-digit minutes
+ ret.push( padZeros( value.getMinutes(), clength ) );
+ break;
+ case "s":
+ // Seconds with no leading zero for single-digit seconds
+ case "ss":
+ // Seconds with leading zero for single-digit seconds
+ ret.push( padZeros(value .getSeconds(), clength ) );
+ break;
+ case "t":
+ // One character am/pm indicator ("a" or "p")
+ case "tt":
+ // Multicharacter am/pm indicator
+ part = value.getHours() < 12 ? (cal.AM ? cal.AM[0] : " ") : (cal.PM ? cal.PM[0] : " ");
+ ret.push( clength === 1 ? part.charAt( 0 ) : part );
+ break;
+ case "f":
+ // Deciseconds
+ case "ff":
+ // Centiseconds
+ case "fff":
+ // Milliseconds
+ ret.push( padZeros( value.getMilliseconds(), 3 ).substr( 0, clength ) );
+ break;
+ case "z":
+ // Time zone offset, no leading zero
+ case "zz":
+ // Time zone offset with leading zero
+ hour = value.getTimezoneOffset() / 60;
+ ret.push( (hour <= 0 ? '+' : '-') + padZeros( Math.floor( Math.abs( hour ) ), clength ) );
+ break;
+ case "zzz":
+ // Time zone offset with leading zero
+ hour = value.getTimezoneOffset() / 60;
+ ret.push( (hour <= 0 ? '+' : '-') + padZeros( Math.floor( Math.abs( hour ) ), 2 ) +
+ // Hard coded ":" separator, rather than using cal.TimeSeparator
+ // Repeated here for consistency, plus ":" was already assumed in date parsing.
+ ":" + padZeros( Math.abs( value.getTimezoneOffset() % 60 ), 2 ) );
+ break;
+ case "g":
+ case "gg":
+ if ( cal.eras ) {
+ ret.push( cal.eras[ getEra(value, eras) ].name );
+ }
+ break;
+ case "/":
+ ret.push( cal["/"] );
+ break;
+ default:
+ throw "Invalid date format pattern '" + current + "'.";
+ break;
+ }
+ }
+ return ret.join( '' );
+}
+
+// EXPORTS
+
+window.Globalization = Globalization;
+
+//jQuery.findClosestCulture = Globalization.findClosestCulture;
+//jQuery.culture = Globalization.culture;
+//jQuery.cultures = Globalization.cultures
+//jQuery.preferCulture = Globalization.preferCulture
+//jQuery.localize = Globalization.localize
+//jQuery.format = Globalization.format
+//jQuery.parseInt = Globalization.parseInt
+//jQuery.parseFloat = Globalization.parseFloat
+//jQuery.parseDate = Globalization.parseDate
+
+})();
diff --git a/ui/jquery.ui.spinner.js b/ui/jquery.ui.spinner.js
index c0167fd24..4fc77389b 100644
--- a/ui/jquery.ui.spinner.js
+++ b/ui/jquery.ui.spinner.js
@@ -17,60 +17,29 @@
var hover = 'ui-state-hover',
active = 'ui-state-active',
namespace = '.spinner',
- buttonRegex = /hide|auto|fast|slow|(\d+)/,
uiSpinnerClasses = 'ui-spinner ui-state-default ui-widget ui-widget-content ui-corner-all ';
$.widget('ui.spinner', {
options: {
- currency: false,
dir: 'ltr',
- groupSeparator: '',
incremental: true,
max: null,
min: null,
mouseWheel: true,
+ numberformat: "n",
padding: 0,
page: 5,
- precision: 0,
- radix: 10,
- radixPoint: '.',
spinnerClass: null,
step: null,
- value: 0,
- width: false
+ value: 0
},
_create: function() {
- this._initOptions();
-
this.value(this._parse(this.element.val() || this.options.value));
-
this._draw();
-
this._mousewheel();
-
this._aria();
},
- _initOptions: function() {
- var self = this,
- options = self.options;
-
- // check for precision in stepping and set _precision as internal
- var precision = parseInt(options.precision, 10);
-
- if (self._step().toString().indexOf('.') != -1 && precision === 0) {
- var s = self._step().toString();
- precision = s.slice(s.indexOf('.')+1, s.length).length;
- }
-
- // set currency options
- if (options.currency) {
- precision = 2;
- options.radix = 10;
- options.groupSeparator = options.groupSeparator || (options.radixPoint === ',' ? '' : ',');
- }
- options.precision = precision;
- },
_draw: function() {
var self = this,
options = self.options;
@@ -101,7 +70,10 @@ $.widget('ui.spinner', {
this.element
.bind('keydown'+namespace, function(event) {
- return self._start(event) ? self._keydown(event) : false;
+ if (self._start(event)) {
+ return self._keydown(event);
+ }
+ return true;
})
.bind('keyup'+namespace, function(event) {
if (self.spinning) {
@@ -114,18 +86,13 @@ $.widget('ui.spinner', {
self.focused = true;
})
.bind('blur'+namespace, function(event) {
- self._value(self.element.val());
+ self.value(self.element.val());
if (!self.hovered) {
uiSpinner.removeClass(active);
}
self.focused = false;
});
- // force width if passed through options
- if (options.width) {
- this.element.width(options.width);
- }
-
// disable spinner if element was already disabled
if (options.disabled) {
this.disable();
@@ -133,6 +100,7 @@ $.widget('ui.spinner', {
// button bindings
this.buttons = uiSpinner.find('.ui-spinner-button')
+ .attr("tabIndex", -1)
.bind('mousedown', function(event) {
if (self._start(event) === false) {
return false;
@@ -198,7 +166,7 @@ $.widget('ui.spinner', {
this.counter = 1;
}
- var newVal = this._value() + step * (this.options.incremental && this.counter > 100
+ var newVal = this.value() + step * (this.options.incremental && this.counter > 100
? this.counter > 200
? 100
: 10
@@ -206,7 +174,7 @@ $.widget('ui.spinner', {
// cancelable
if (this._trigger('spin', event, { value: newVal }) !== false) {
- this._value(newVal);
+ this.value(newVal);
this.counter++;
}
},
@@ -227,10 +195,10 @@ $.widget('ui.spinner', {
i = i || 100;
if (this.timer) {
- window.clearInterval(this.timer);
+ window.clearTimeout(this.timer);
}
- this.timer = window.setInterval(function() {
+ this.timer = window.setTimeout(function() {
self._repeat(self.options.incremental && self.counter > 20 ? 20 : i, steps, event);
}, i);
@@ -241,40 +209,32 @@ $.widget('ui.spinner', {
KEYS = $.ui.keyCode;
switch (event.keyCode) {
- case KEYS.UP: this._repeat(null, event.shiftKey ? o.page : 1, event); break;
- case KEYS.DOWN: this._repeat(null, event.shiftKey ? -o.page : -1, event); break;
- case KEYS.PAGE_UP: this._repeat(null, o.page, event); break;
- case KEYS.PAGE_DOWN: this._repeat(null, -o.page, event); break;
+ case KEYS.UP:
+ this._repeat(null, event.shiftKey ? o.page : 1, event);
+ return false;
+ case KEYS.DOWN:
+ this._repeat(null, event.shiftKey ? -o.page : -1, event);
+ return false;
+ case KEYS.PAGE_UP:
+ this._repeat(null, o.page, event);
+ return false;
+ case KEYS.PAGE_DOWN:
+ this._repeat(null, -o.page, event);
+ return false;
- case KEYS.HOME:
- case KEYS.END:
- if (event.shiftKey) {
- return true;
- }
- this._value(this['_' + (event.keyCode == KEYS.HOME ? 'min':'max')]());
- break;
-
- case KEYS.TAB:
- case KEYS.BACKSPACE:
- case KEYS.LEFT:
- case KEYS.RIGHT:
- case KEYS.PERIOD:
- case KEYS.NUMPAD_DECIMAL:
- case KEYS.NUMPAD_SUBTRACT:
+ case KEYS.HOME:
+ case KEYS.END:
+ if (event.shiftKey) {
return true;
+ }
+ this.value(this['_' + (event.keyCode == KEYS.HOME ? 'min' : 'max')]());
+ return false;
- case KEYS.ENTER:
- this.value(this.element.val());
- return true;
-
- default:
- if ((event.keyCode >= 96 && event.keyCode <= 105) || // numeric keypad 0-9
- (new RegExp('[' + this._validChars() + ']', 'i').test(String.fromCharCode(event.keyCode)))) {
- return true;
- };
+ case KEYS.ENTER:
+ this.value(this.element.val());
}
- return false;
+ return true;
},
_mousewheel: function() {
var self = this;
@@ -298,7 +258,7 @@ $.widget('ui.spinner', {
});
}
},
- _value: function(newVal) {
+ value: function(newVal) {
if (!arguments.length) {
return this._parse(this.element.val());
}
@@ -349,10 +309,6 @@ $.widget('ui.spinner', {
}
this._aria();
break;
- case 'width':
- this.element.width(value);
- break;
- case 'precision':
case 'value':
this._format(this._parse(this.options.value));
break;
@@ -364,59 +320,23 @@ $.widget('ui.spinner', {
.attr('aria-valuemax', this._max())
.attr('aria-valuenow', this.value());
},
- _validChars: function() {
- var radix = parseInt(this.options.radix);
- return '\\-\\' + this.options.radixPoint + (this.options.groupSeparator
- ? '\\' + this.options.groupSeparator
- :'') + (radix < 10
- ? '0-' + radix
- : '0-9' + (radix > 10
- ? 'a-' + String.fromCharCode('a'.charCodeAt(0) + radix - 11)
- :''));
- },
+
_parse: function(val) {
+ var input = val;
if (typeof val == 'string') {
- if (this.options.groupSeparator) {
- val = val.replace(new RegExp('\\'+this.options.groupSeparator,'g'), '');
+ // special case for currency formatting until Globalization handles currencies
+ if (this.options.numberformat == "C" && window.Globalization) {
+ // parseFloat should accept number format, including currency
+ var culture = Globalization.culture || Globalization.cultures['default'];
+ val = val.replace(culture.numberFormat.currency.symbol, "");
}
- val = val.replace(new RegExp('[^' + this._validChars() + ']', 'gi'), '').split(this.options.radixPoint);
- result = parseInt(val[0] == '-' ? 0 : val[0] || 0, this.options.radix);
- if (val.length > 1) {
- result += parseInt(val[1], this.options.radix) / Math.pow(this.options.radix, val[1].length) *
- // must test first character of val[0] for minus sign because -0 is parsed as 0 in result
- (val[0].substr(0,1) == '-' ? -1 : 1);
- }
- val = result;
+ val = window.Globalization ? Globalization.parseFloat(val) : +val;
}
+ console.log("input", input, "parsed", val)
return isNaN(val) ? null : val;
},
_format: function(num) {
- var regex = /(\d+)(\d{3})/,
- options = this.options,
- sym = options.currency || '',
- dec = options.precision,
- radix = options.radix,
- group = options.groupSeparator,
- pt = options.radixPoint,
- neg = num < 0 ? '-' : '';
-
- for (
- num = (
- isNaN(num)
- ? options.value
- : radix === 10
- ? parseFloat(num, radix).toFixed(dec)
- : parseInt(num, radix)
- ).toString(radix).replace('.', pt);
- regex.test(num) && group;
- num = num.replace(regex, '$1'+group+'$2')
- );
-
- result = num.replace('-','');
- while (options.padding && (result.length < options.padding)) {
- result = '0' + result;
- }
- this.element.val(neg + sym + result);
+ this.element.val( window.Globalization ? Globalization.format(num, this.options.numberformat) : num );
},
_getOption: function(key, defaultValue) {
return this._parse(this.options[key] !== null
@@ -476,12 +396,6 @@ $.widget('ui.spinner', {
.addClass('ui-spinner-disabled ui-state-disabled');
this.options.disabled = true;
},
- value: function(newVal) {
- if (!arguments.length) {
- return this._value();
- }
- this._value(newVal);
- },
stepUp: function(steps) {
this._spin((steps || 1) * this._step(), null);
return this;
--
cgit v1.2.3
From 0a1da016ffc5081ad1124aa74af778053d58ecb2 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Tue, 26 Oct 2010 10:53:03 +0200
Subject: Slider: Update to latest mousewheel plugin
---
demos/spinner/currency.html | 2 +-
demos/spinner/decimal.html | 2 +-
demos/spinner/default.html | 2 +-
demos/spinner/latlong.html | 2 +-
demos/spinner/rtl.html | 2 +-
external/jquery.mousewheel-3.0.2.js | 60 ----------------------------
external/jquery.mousewheel-3.0.4.js | 78 +++++++++++++++++++++++++++++++++++++
tests/unit/spinner/spinner.html | 4 +-
8 files changed, 85 insertions(+), 67 deletions(-)
delete mode 100644 external/jquery.mousewheel-3.0.2.js
create mode 100644 external/jquery.mousewheel-3.0.4.js
(limited to 'demos/spinner')
diff --git a/demos/spinner/currency.html b/demos/spinner/currency.html
index 418dca228..0909f4ef5 100644
--- a/demos/spinner/currency.html
+++ b/demos/spinner/currency.html
@@ -5,7 +5,7 @@
jQuery UI Spinner - Default functionality
-
+
diff --git a/demos/spinner/decimal.html b/demos/spinner/decimal.html
index 82d0fcc20..c47251552 100644
--- a/demos/spinner/decimal.html
+++ b/demos/spinner/decimal.html
@@ -5,7 +5,7 @@
jQuery UI Spinner - decimal
-
+
diff --git a/demos/spinner/default.html b/demos/spinner/default.html
index d90b73f6d..b0f62308d 100644
--- a/demos/spinner/default.html
+++ b/demos/spinner/default.html
@@ -5,7 +5,7 @@
jQuery UI Spinner - Default functionality
-
+
diff --git a/demos/spinner/latlong.html b/demos/spinner/latlong.html
index 6b955ba47..7c0c9b21a 100644
--- a/demos/spinner/latlong.html
+++ b/demos/spinner/latlong.html
@@ -6,7 +6,7 @@
-
+
diff --git a/demos/spinner/rtl.html b/demos/spinner/rtl.html
index 52d7b1048..93a2022ff 100644
--- a/demos/spinner/rtl.html
+++ b/demos/spinner/rtl.html
@@ -5,7 +5,7 @@
jQuery UI Spinner - Default functionality
-
+
diff --git a/external/jquery.mousewheel-3.0.2.js b/external/jquery.mousewheel-3.0.2.js
deleted file mode 100644
index 507ab005e..000000000
--- a/external/jquery.mousewheel-3.0.2.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
- * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
- * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
- * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
- * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
- *
- * Version: 3.0.2
- *
- * Requires: 1.2.2+
- */
-
-(function($) {
-
-var types = ['DOMMouseScroll', 'mousewheel'];
-
-$.event.special.mousewheel = {
- setup: function() {
- if ( this.addEventListener )
- for ( var i=types.length; i; )
- this.addEventListener( types[--i], handler, false );
- else
- this.onmousewheel = handler;
- },
-
- teardown: function() {
- if ( this.removeEventListener )
- for ( var i=types.length; i; )
- this.removeEventListener( types[--i], handler, false );
- else
- this.onmousewheel = null;
- }
-};
-
-$.fn.extend({
- mousewheel: function(fn) {
- return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
- },
-
- unmousewheel: function(fn) {
- return this.unbind("mousewheel", fn);
- }
-});
-
-
-function handler(event) {
- var args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true;
-
- event = $.event.fix(event || window.event);
- event.type = "mousewheel";
-
- if ( event.wheelDelta ) delta = event.wheelDelta/120;
- if ( event.detail ) delta = -event.detail/3;
-
- // Add events and delta to the front of the arguments
- args.unshift(event, delta);
-
- return $.event.handle.apply(this, args);
-}
-
-})(jQuery);
\ No newline at end of file
diff --git a/external/jquery.mousewheel-3.0.4.js b/external/jquery.mousewheel-3.0.4.js
new file mode 100644
index 000000000..dbf8f4b0f
--- /dev/null
+++ b/external/jquery.mousewheel-3.0.4.js
@@ -0,0 +1,78 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+ * Licensed under the MIT License (LICENSE.txt).
+ *
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
+ *
+ * Version: 3.0.4
+ *
+ * Requires: 1.2.2+
+ */
+
+(function($) {
+
+var types = ['DOMMouseScroll', 'mousewheel'];
+
+$.event.special.mousewheel = {
+ setup: function() {
+ if ( this.addEventListener ) {
+ for ( var i=types.length; i; ) {
+ this.addEventListener( types[--i], handler, false );
+ }
+ } else {
+ this.onmousewheel = handler;
+ }
+ },
+
+ teardown: function() {
+ if ( this.removeEventListener ) {
+ for ( var i=types.length; i; ) {
+ this.removeEventListener( types[--i], handler, false );
+ }
+ } else {
+ this.onmousewheel = null;
+ }
+ }
+};
+
+$.fn.extend({
+ mousewheel: function(fn) {
+ return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+ },
+
+ unmousewheel: function(fn) {
+ return this.unbind("mousewheel", fn);
+ }
+});
+
+
+function handler(event) {
+ var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
+ event = $.event.fix(orgEvent);
+ event.type = "mousewheel";
+
+ // Old school scrollwheel delta
+ if ( event.wheelDelta ) { delta = event.wheelDelta/120; }
+ if ( event.detail ) { delta = -event.detail/3; }
+
+ // New school multidimensional scroll (touchpads) deltas
+ deltaY = delta;
+
+ // Gecko
+ if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
+ deltaY = 0;
+ deltaX = -1*delta;
+ }
+
+ // Webkit
+ if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
+ if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
+
+ // Add event and delta to the front of the arguments
+ args.unshift(event, delta, deltaX, deltaY);
+
+ return $.event.handle.apply(this, args);
+}
+
+})(jQuery);
\ No newline at end of file
diff --git a/tests/unit/spinner/spinner.html b/tests/unit/spinner/spinner.html
index a9902a251..5868a4590 100644
--- a/tests/unit/spinner/spinner.html
+++ b/tests/unit/spinner/spinner.html
@@ -6,7 +6,7 @@
-
+
@@ -33,7 +33,7 @@
-
+
--
cgit v1.2.3
From 2df094527ec12fe9ebec938c27661eda3e999e63 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Tue, 26 Oct 2010 12:14:45 +0200
Subject: Spinner: Changed default for numberformat to null. Fixed disabled
option to not prevent changing value via step and page methods. OVerhauled
testsuite.
---
demos/spinner/decimal.html | 3 +-
tests/unit/spinner/spinner.html | 1 +
tests/unit/spinner/spinner_core.js | 304 +++++++--------------------------
tests/unit/spinner/spinner_defaults.js | 11 +-
tests/unit/spinner/spinner_events.js | 16 +-
tests/unit/spinner/spinner_methods.js | 91 ++++------
tests/unit/spinner/spinner_options.js | 119 +++++--------
ui/jquery.ui.spinner.js | 80 ++++++---
8 files changed, 200 insertions(+), 425 deletions(-)
(limited to 'demos/spinner')
diff --git a/demos/spinner/decimal.html b/demos/spinner/decimal.html
index c47251552..ae45da1e7 100644
--- a/demos/spinner/decimal.html
+++ b/demos/spinner/decimal.html
@@ -17,7 +17,8 @@
+
diff --git a/tests/unit/spinner/spinner_core.js b/tests/unit/spinner/spinner_core.js
index 2996ad128..5a29b411a 100644
--- a/tests/unit/spinner/spinner_core.js
+++ b/tests/unit/spinner/spinner_core.js
@@ -2,332 +2,151 @@
* spinner_core.js
*/
-var el,
- options,
- simulateKeyDownUp = function(el, kCode, shift) {
- el.simulate("keydown",{keyCode:kCode, shiftKey: shift || false })
- .simulate("keyup",{keyCode:kCode, shiftKey: shift || false });
- },
- wrapper = function() {
- return el.closest('.ui-spinner');
- },
- upButton = function() {
- return wrapper().find('.ui-spinner-up');
- },
- downButton = function() {
- return wrapper().find('.ui-spinner-down');
- },
- box = function() {
- return $('.ui-spinner-input', wrapper());
- };
+var simulateKeyDownUp = function(el, kCode, shift) {
+ el.simulate("keydown",{keyCode:kCode, shiftKey: shift || false })
+ .simulate("keyup",{keyCode:kCode, shiftKey: shift || false });
+};
(function($) {
// Spinner Tests
module("spinner: core");
-test("init", function() {
- expect(3);
-
- $(" ").appendTo('body').spinner().remove();
- ok(true, '.spinner() called on element');
-
- $(' ').spinner().remove();
- ok(true, '.spinner() called on disconnected element');
-
- el = $(' ').spinner();
- ok(el.hasClass('ui-spinner-input'), 'input gets ui-spinner-input class on init');
-
-});
-
test("destroy", function() {
- expect(3);
-
- $(" ").appendTo('body').spinner().spinner("destroy").remove();
- ok(true, '.spinner("destroy") called on element');
-
- $(' ').spinner().spinner("destroy").remove();
- ok(true, '.spinner().spinner("destroy") called on disconnected element');
-
- el = $(' ').spinner().spinner('destroy');
- ok(!el.hasClass('ui-spinner-input'), 'ui-spinner-input class removed on destroy');
-});
-
-test("re-attach", function() {
- expect(2);
-
- el = $(" ").spinner().spinner("destroy").spinner();
- ok(true, '.spinner().spinner("destroy").spinner() called on element');
-
- el = $(' ').spinner().spinner("destroy").spinner().remove();
- ok(true, '.spinner().spinner("destroy").spinner() called on disconnected element');
-
+ var beforeHtml = $("#spin").parent().html();
+ var afterHtml = $("#spin").spinner().spinner("destroy").parent().html();
+ // Opera 9 outputs role="" instead of removing the attribute like everyone else
+ /*
+ if ($.browser.opera) {
+ afterHtml = afterHtml.replace(/ role=""/g, "");
+ }
+ */
+ equal( afterHtml, beforeHtml, "before/after html should be the same" );
});
test("keydown UP on input, increases value not greater than max", function() {
- expect(3);
-
- el = $("#spin");
- options = {
+ var el = $("#spin").spinner({
max:100,
value:50,
step:10
- }
- el.spinner(options);
+ });
simulateKeyDownUp(el, $.ui.keyCode.UP);
-
equals(el.val(), 60);
for (i = 0; i<11; i++) {
simulateKeyDownUp(el, $.ui.keyCode.UP);
}
-
equals(el.val(), 100);
el.val(50);
-
simulateKeyDownUp(el, $.ui.keyCode.UP);
-
equals(el.val(), 60);
});
test("keydown DOWN on input, decreases value not less than min", function() {
- expect(3);
-
- el = $("#spin");
- options = {
+ var el = $("#spin").spinner({
min:-100,
value:50,
step:10
- }
- el.spinner(options);
+ });
simulateKeyDownUp(el, $.ui.keyCode.DOWN);
-
equals(el.val(), 40);
for (i = 0; i<21; i++) {
simulateKeyDownUp(el, $.ui.keyCode.DOWN);
}
-
equals(el.val(), -100);
el.val(50);
-
simulateKeyDownUp(el, $.ui.keyCode.DOWN);
-
equals(el.val(), 40);
-
});
test("keydown PGUP on input, increases value not greater than max", function() {
- expect(3);
+ var el = $("#spin").spinner({
+ max: 500,
+ value: 0,
+ step: 10
+ });
- el = $("#spin");
- options = {
- max:100,
- value:0,
- step:10
- }
- el.spinner(options);
-
simulateKeyDownUp(el, $.ui.keyCode.PAGE_UP);
-
- equals(el.val(), 50);
+ equal(el.val(), 100);
for (i = 0; i<5; i++) {
simulateKeyDownUp(el, $.ui.keyCode.PAGE_UP);
}
+ equal(el.val(), 500);
- equals(el.val(), 100);
-
el.val(0);
-
simulateKeyDownUp(el, $.ui.keyCode.PAGE_UP);
-
- equals(el.val(), 50);
+ equals(el.val(), 100);
});
test("keydown PGDN on input, decreases value not less than min", function() {
- expect(3);
-
- el = $("#spin");
- options = {
- min:-100,
+ var el = $("#spin").spinner({
+ min:-500,
value:0,
step:10
- }
- el.spinner(options);
+ });
simulateKeyDownUp(el, $.ui.keyCode.PAGE_DOWN);
-
- equals(el.val(), -50);
+ equals(el.val(), -100);
for (i = 0; i<5; i++) {
simulateKeyDownUp(el, $.ui.keyCode.PAGE_DOWN);
}
-
- equals(el.val(), -100);
+ equals(el.val(), -500);
el.val(0);
-
simulateKeyDownUp(el, $.ui.keyCode.PAGE_DOWN);
-
- equals(el.val(), -50);
-});
-
-test("hold SHIFT and keydown UP, increments value but no greater than max", function() {
- expect(2);
-
- el = $("#spin");
- options = {
- max:100,
- value:0,
- step:10
- }
- el.spinner(options);
-
- simulateKeyDownUp(el, $.ui.keyCode.UP, true);
-
- equals(el.val(), 50);
-
- for (i = 0; i<5; i++) {
- simulateKeyDownUp(el, $.ui.keyCode.UP, true);
- }
-
- equals(el.val(), 100);
-});
-
-test("hold SHIFT and keydown DOWN, decreases value but no less than min", function() {
- expect(2);
-
- el = $("#spin");
- options = {
- min:-100,
- value:0,
- step:10
- }
- el.spinner(options);
-
- simulateKeyDownUp(el, $.ui.keyCode.DOWN, true);
-
- equals(el.val(), -50);
-
- for (i = 0; i<5; i++) {
- simulateKeyDownUp(el, $.ui.keyCode.DOWN, true);
- }
-
- equals(el.val(), -100);
-});
-
-test("keydown HOME on input, sets value to minimum", function() {
- el = $("#spin");
- options = {
- min:-100,
- value:50,
- step:10
- }
- el.spinner(options);
-
- simulateKeyDownUp(el, $.ui.keyCode.HOME);
equals(el.val(), -100);
-
- el.spinner('option', 'min', -200);
-
- simulateKeyDownUp(el, $.ui.keyCode.HOME);
-
- equals(el.val(), -200);
-});
-
-test("keydown END on input, sets value to maximum", function() {
- el = $("#spin");
- options = {
- max:100,
- value:50,
- step:10
- }
- el.spinner(options);
-
- simulateKeyDownUp(el, $.ui.keyCode.END);
- equals(el.val(), 100);
-
- el.spinner('option', 'max', 200);
-
- simulateKeyDownUp(el, $.ui.keyCode.END);
-
- equals(el.val(), 200);
-});
-
-test("keydown LEFT on input has no effect", function() {
- el = $("#spin");
- el.spinner();
- var value = el.val();
-
- simulateKeyDownUp(el, $.ui.keyCode.LEFT);
- equals(el.val(), value);
-
- for (i = 0; i<5; i++) {
- simulateKeyDownUp(el, $.ui.keyCode.LEFT);
- }
-
- equals(el.val(), value);
-});
-
-test("keydown RIGHT on input has no effect", function() {
- expect(2);
-
- el = $("#spin");
- el.spinner();
- var value = el.val();
-
- simulateKeyDownUp(el, $.ui.keyCode.RIGHT);
- equals(el.val(), value);
-
- for (i = 0; i<5; i++) {
- simulateKeyDownUp(el, $.ui.keyCode.RIGHT);
- }
-
- equals(el.val(), value);
});
test("mouse click on buttons", function() {
- expect(4);
-
- el = $("#spin").spinner();
- val = 0;
+ var el = $("#spin").spinner(),
+ val = 0;
$(".ui-spinner-up").trigger("mousedown").trigger("mouseup");
-
equals(el.val(), ++val, "mouse click to up");
$(".ui-spinner-down").trigger("mousedown").trigger("mouseup");
-
equals(el.val(), --val, "mouse click to down");
el.val(50);
-
$(".ui-spinner-up").trigger("mousedown").trigger("mouseup");
-
equals(el.val(), 51);
el.val(50);
-
$(".ui-spinner-down").trigger("mousedown").trigger("mouseup");
-
equals(el.val(), 49);
-
});
test("mouse wheel on input", function() {
- ok(false, 'missing test - untested code is broken code');
+ expect(3);
+
+ var el = $("#spin").spinner();
+ el.trigger("mousewheel", 1);
+ equal(el.val(), 1);
+
+ // mousewheel handler uses a timeout, need to accomodate that
+ stop();
+ setTimeout(function() {
+ el.trigger("mousewheel", -1);
+ equal(el.val(), 0);
+
+ setTimeout(function() {
+ el.trigger("mousewheel", -1);
+ equal(el.val(), -1);
+ start();
+ }, 100);
+ }, 100);
+
});
test("reading HTML5 attributes", function() {
- expect(4);
-
- el = $(' ').spinner();
-
+ var el = $(' ').spinner();
equals(el.spinner('option', 'value'), 5, 'value');
equals(el.spinner('option', 'max'), 100, 'max');
equals(el.spinner('option', 'min'), -100, 'min');
@@ -335,23 +154,22 @@ test("reading HTML5 attributes", function() {
});
test("ARIA attributes", function() {
- expect(7);
-
- el = $('#spin').spinner({ min: -5, max: 5, value: 2 });
+ var el = $('#spin').spinner({ min: -5, max: 5, value: 2 }),
+ wrapper = el.spinner("widget");
- equals(wrapper().attr('role'), 'spinbutton', 'role');
- equals(wrapper().attr('aria-valuemin'), -5, 'aria-valuemin');
- equals(wrapper().attr('aria-valuemax'), 5, 'aria-valuemax');
- equals(wrapper().attr('aria-valuenow'), 2, 'aria-valuenow');
+ equals(wrapper.attr('role'), 'spinbutton', 'role');
+ equals(wrapper.attr('aria-valuemin'), -5, 'aria-valuemin');
+ equals(wrapper.attr('aria-valuemax'), 5, 'aria-valuemax');
+ equals(wrapper.attr('aria-valuenow'), 2, 'aria-valuenow');
el.spinner('stepUp');
- equals(wrapper().attr('aria-valuenow'), 3, 'stepUp 1 step changes aria-valuenow');
+ equals(wrapper.attr('aria-valuenow'), 3, 'stepUp 1 step changes aria-valuenow');
el.spinner('option', { min: -10, max: 10 });
- equals(wrapper().attr('aria-valuemin'), -10, 'min option changed aria-valuemin changes');
- equals(wrapper().attr('aria-valuemax'), 10, 'max option changed aria-valuemax changes');
+ equals(wrapper.attr('aria-valuemin'), -10, 'min option changed aria-valuemin changes');
+ equals(wrapper.attr('aria-valuemax'), 10, 'max option changed aria-valuemax changes');
});
})(jQuery);
diff --git a/tests/unit/spinner/spinner_defaults.js b/tests/unit/spinner/spinner_defaults.js
index aa88fd649..0b3368c00 100644
--- a/tests/unit/spinner/spinner_defaults.js
+++ b/tests/unit/spinner/spinner_defaults.js
@@ -3,15 +3,12 @@
*/
var spinner_defaults = {
- dir: 'ltr',
disabled: false,
incremental: true,
- max: null,
- min: null,
- mouseWheel: true,
- numberformat: "n",
- page: 5,
- step: null,
+ max: Number.MAX_VALUE,
+ min: -Number.MAX_VALUE,
+ numberformat: null,
+ step: 1,
value: null
};
diff --git a/tests/unit/spinner/spinner_events.js b/tests/unit/spinner/spinner_events.js
index ae80801e6..1a006a3dc 100644
--- a/tests/unit/spinner/spinner_events.js
+++ b/tests/unit/spinner/spinner_events.js
@@ -6,11 +6,9 @@
module("spinner: events");
test("start", function() {
- expect(1);
-
var start = 0;
- el = $("#spin").spinner({
+ var el = $("#spin").spinner({
start: function(){
start++;
}
@@ -22,11 +20,9 @@ test("start", function() {
});
test("spin", function() {
- expect(1);
-
var spin = 0;
- el = $("#spin").spinner({
+ var el = $("#spin").spinner({
spin: function(){
spin++;
}
@@ -38,11 +34,9 @@ test("spin", function() {
});
test("stop", function() {
- expect(1);
-
var stop = 0;
- el = $("#spin").spinner({
+ var el = $("#spin").spinner({
stop: function(){
stop++;
}
@@ -54,11 +48,9 @@ test("stop", function() {
});
test("change", function() {
- expect(1);
-
var start = spin = stop = change = 0;
- el = $("#spin").spinner({
+ var el = $("#spin").spinner({
change: function(){
change++;
}
diff --git a/tests/unit/spinner/spinner_methods.js b/tests/unit/spinner/spinner_methods.js
index faeab75f3..fb58edbdf 100644
--- a/tests/unit/spinner/spinner_methods.js
+++ b/tests/unit/spinner/spinner_methods.js
@@ -6,17 +6,16 @@
module("spinner: methods");
test("disable", function() {
- expect(14);
-
- el = $("#spin").spinner({ disabled: false });
- var val = el.val();
+ var el = $("#spin").spinner({ disabled: false }),
+ val = el.val(),
+ wrapper = $("#spin").spinner("widget");
- ok(!wrapper().hasClass(".ui-spinner-disabled"), "before: wrapper does not have ui-spinner-disabled class");
- ok(!box().is(':disabled'), "before: input does not have disabled attribute");
+ ok(!wrapper.hasClass("ui-spinner-disabled"), "before: wrapper does not have ui-spinner-disabled class");
+ ok(!el.is(':disabled'), "before: input does not have disabled attribute");
el.spinner("disable");
- ok(wrapper().hasClass(".ui-spinner-disabled"), "after: wrapper has ui-spinner-disabled class");
- ok(box().is(':disabled'), "after: input has disabled attribute");
+ ok(wrapper.hasClass("ui-spinner-disabled"), "after: wrapper has ui-spinner-disabled class");
+ ok(el.is(':disabled'), "after: input has disabled attribute");
simulateKeyDownUp(el, $.ui.keyCode.UP);
equals(val, el.val(), "keyboard - value does not change on key UP");
@@ -30,10 +29,10 @@ test("disable", function() {
simulateKeyDownUp(el, $.ui.keyCode.PAGE_DOWN);
equals(val, el.val(), "keyboard - value does not change on key PGDN");
- upButton().trigger('mousedown').trigger('mouseup');
+ wrapper.find(":ui-button").first().trigger('mousedown').trigger('mouseup');
equals(val, el.val(), "mouse - value does not change on clicking up button");
- downButton().trigger('mousedown').trigger('mouseup');
+ wrapper.find(":ui-button").last().trigger('mousedown').trigger('mouseup');
equals(val, el.val(), "mouse - value does not change on clicking down button");
el.spinner('stepUp', 6);
@@ -43,7 +42,7 @@ test("disable", function() {
equals(5, el.val(), "script - stepDown 1 step changes value");
el.spinner('pageUp');
- equals(10, el.val(), "script - pageUp 1 page changes value");
+ equals(15, el.val(), "script - pageUp 1 page changes value");
el.spinner('pageDown');
equals(5, el.val(), "script - pageDown 1 page changes value");
@@ -51,61 +50,31 @@ test("disable", function() {
});
test("enable", function() {
- expect(14);
+ var el = $("#spin").spinner({ disabled: true })
+ val = el.val(),
+ wrapper = el.spinner("widget");
- el = $("#spin").spinner({ disabled: true });
- var val = el.val();
-
- ok(wrapper().hasClass(".ui-spinner-disabled"), "before: wrapper has ui-spinner-disabled class");
- ok(box().is(':disabled'), "before: input has disabled attribute");
+ ok(wrapper.hasClass("ui-spinner-disabled"), "before: wrapper has ui-spinner-disabled class");
+ ok(el.is(':disabled'), "before: input has disabled attribute");
el.spinner("enable");
- ok(!wrapper().hasClass(".ui-spinner-disabled"), "after: wrapper does not have ui-spinner-disabled class");
- ok(!box().is(':disabled'), "after: input does not have disabled attribute");
-
- simulateKeyDownUp(el, $.ui.keyCode.UP);
- equals(1, el.val(), "keyboard - value changes on key UP");
-
- simulateKeyDownUp(el, $.ui.keyCode.DOWN);
- equals(0, el.val(), "keyboard - value changes on key DOWN");
-
- simulateKeyDownUp(el, $.ui.keyCode.PAGE_UP);
- equals(5, el.val(), "keyboard - value changes on key PGUP");
-
- simulateKeyDownUp(el, $.ui.keyCode.PAGE_DOWN);
- equals(0, el.val(), "keyboard - value changes on key PGDN");
-
- upButton().trigger('mousedown').trigger('mouseup');
- equals(1, el.val(), "mouse - value changes on clicking up button");
-
- downButton().trigger('mousedown').trigger('mouseup');
- equals(0, el.val(), "mouse - value changes on clicking down button");
-
- el.spinner('stepUp', 6);
- equals(6, el.val(), "script - stepUp 6 steps changes value");
-
- el.spinner('stepDown');
- equals(5, el.val(), "script - stepDown 1 step changes value");
-
- el.spinner('pageUp');
- equals(10, el.val(), "script - pageUp 1 page changes value");
-
- el.spinner('pageDown');
- equals(5, el.val(), "script - pageDown 1 page changes value");
-
+ ok(!wrapper.hasClass(".ui-spinner-disabled"), "after: wrapper does not have ui-spinner-disabled class");
+ ok(!el.is(':disabled'), "after: input does not have disabled attribute");
});
test("pageDown", function() {
- expect(4);
-
- el = $('#spin').spinner({ step: 2, page: 5, value: 0, min: -100 });
+ var el = $('#spin').spinner({
+ step: 2,
+ value: 0,
+ min: -100
+ });
el.spinner('pageDown');
- equals(el.val(), -10, "pageDown 1 page");
+ equals(el.val(), -20, "pageDown 1 page");
el.spinner('pageDown', 3);
- equals(el.val(), -40, "pageDown 3 pages");
+ equals(el.val(), -80, "pageDown 3 pages");
el.val(-91).spinner('pageDown');
equals(el.val(), -100, "value close to min and pageDown 1 page");
@@ -115,15 +84,17 @@ test("pageDown", function() {
});
test("pageUp", function() {
- expect(4);
-
- el = $('#spin').spinner({ step: 2, page: 5, value: 0, max: 100 });
+ var el = $('#spin').spinner({
+ step: 2,
+ value: 0,
+ max: 100
+ });
el.spinner('pageUp');
- equals(el.val(), 10, "pageUp 1 page");
+ equals(el.val(), 20, "pageUp 1 page");
el.spinner('pageUp', 3);
- equals(el.val(), 40, "pageUp 3 pages");
+ equals(el.val(), 80, "pageUp 3 pages");
el.val(91).spinner('pageUp');
equals(el.val(), 100, "value close to max and pageUp 1 page");
diff --git a/tests/unit/spinner/spinner_options.js b/tests/unit/spinner/spinner_options.js
index 48fea3203..3db7e5c55 100644
--- a/tests/unit/spinner/spinner_options.js
+++ b/tests/unit/spinner/spinner_options.js
@@ -5,36 +5,33 @@
module("spinner: options");
-test("numberformat", function() {
- ok( false, "tests for numberformat!");
+test("numberformat, number", function() {
+ var el = $("#spin").spinner({
+ value: "1",
+ numberformat: "n"
+ });
+ equal(el.val(), "1.00");
});
-test("dir - left-to-right (default)", function() {
- expect(3);
-
- el = $("#spin");
- el.spinner();
-
- ok(upButton().position().left > box().position().left, 'input on left up button on right');
- ok(downButton().position().left > box().position().left, 'input on left down button on right');
- ok(wrapper().hasClass('ui-spinner-ltr'), 'container has correct text direction class setting');
+test("numberformat, number, simple", function() {
+ var el = $("#spin").spinner({
+ value: "1",
+ numberformat: "n0"
+ });
+ equal(el.val(), "1");
});
-test("dir - right-to-left", function() {
- expect(3);
-
- el = $("#spin");
- el.spinner({ dir: 'rtl' });
-
- ok(upButton().position().left < box().position().left, 'input on right up button on left');
- ok(downButton().position().left < box().position().left, 'input on right down button on left');
- ok(wrapper().hasClass('ui-spinner-rtl'), 'container has correct text direction class setting');
+test("numberformat, currency", function() {
+ var el = $("#spin").spinner({
+ value: "1",
+ numberformat: "C"
+ });
+ equal(el.val(), "$1.00");
});
+/* TODO figure out how to test this properly
test("incremental - false (default)", function() {
- expect(2);
-
- el = $("#spin").spinner({ incremental:false });
+ var el = $("#spin").spinner({ incremental:false });
for ( var i = 1 ; i<=120 ; i++ ) {
el.simulate("keydown",{keyCode:$.ui.keyCode.UP});
@@ -51,10 +48,8 @@ test("incremental - false (default)", function() {
equals(el.val(), -90, "incremental false - keydown 210 times");
});
-test("incremental - true", function() {
- expect(2);
-
- el.spinner('option', 'incremental', true );
+test("incremental - true (default)", function() {
+ var el = $("#spin").spinner();
for ( var i = 1 ; i<=120 ; i++ ) {
el.simulate("keydown",{keyCode:$.ui.keyCode.UP});
@@ -70,11 +65,10 @@ test("incremental - true", function() {
equals(el.val(), -1800, "incremental true - keydown 210 times (300-100-100*10-10*100)");
});
+*/
test("max", function() {
- expect(3);
-
- el = $("#spin").spinner({ max: 100, value: 1000 });
+ var el = $("#spin").spinner({ max: 100, value: 1000 });
equals(el.val(), 100, "max constrained if value option is greater");
el.spinner('value', 1000);
@@ -85,9 +79,7 @@ test("max", function() {
});
test("min", function() {
- expect(3);
-
- el = $("#spin").spinner({ min: -100, value: -1000 });
+ var el = $("#spin").spinner({ min: -100, value: -1000 });
equals(el.val(), -100, "min constrained if value option is greater");
el.spinner('value', -1000);
@@ -97,53 +89,14 @@ test("min", function() {
equals(el.val(), -100, "min constrained if manual entry");
});
-test("mouseWheel", function() {
- ok(false, 'missing test - untested code is broken code');
-});
-
-test("page", function() {
- expect(3);
-
- el = $("#spin").spinner({ step: 2, page:2.5 });
-
- equals(el.val(), "0", "start number");
-
- simulateKeyDownUp(el, $.ui.keyCode.PAGE_DOWN);
-
- equals(el.val(), "-5", "PAGE_DOWN on spinner once");
-
- for ( var i = 1 ; i<=11 ; i++ ) {
- simulateKeyDownUp(el, $.ui.keyCode.PAGE_UP);
- }
-
- equals(el.val(), "50", "PAGE_UP 11 times on spinner");
-});
-
-test("step", function() {
- expect(7);
-
- el = $("#spin").spinner({ step:0.7 });
- equals(el.val(), "0.0", "value initialized to");
-
- simulateKeyDownUp(el, $.ui.keyCode.DOWN);
- equals(el.val(), "-0.7", "DOWN 1 time with step: 0.7");
-
- for ( var i = 0 ; i < 11 ; i++ ) {
- simulateKeyDownUp(el, $.ui.keyCode.UP);
- }
- equals(el.val(), "7.0", "UP 11 times with step: 0.7");
-
- el.spinner('option', 'step', 1);
- for ( var i = 0 ; i < 3 ; i++ ) {
- simulateKeyDownUp(el, $.ui.keyCode.UP);
- }
- equals(el.val(), "10.0", "UP 3 times with step: 1");
+test("step, 2", function() {
+ var el = $("#spin").spinner({ step: 2 });
+ equals(el.val(), "0", "value initialized to");
- el.spinner('option', 'step', 2);
for ( var i = 0 ; i < 5 ; i++ ) {
simulateKeyDownUp(el, $.ui.keyCode.UP);
}
- equals(el.val(), "20.0", "UP 5 times with step: 2");
+ equals(el.val(), "10", "UP 5 times with step: 2");
el.spinner('value', '10.5');
equals(el.val(), "10.5", "value reset to");
@@ -153,8 +106,22 @@ test("step", function() {
simulateKeyDownUp(el, $.ui.keyCode.UP);
}
equals(el.val(), "20.5", "UP 5 times with step: 2");
+});
+test("step, 0.7", function() {
+ var el = $("#spin").spinner({
+ step: 0.7,
+ numberformat: "n1"
+ });
+ equals(el.val(), "0.0", "value initialized to");
+
+ simulateKeyDownUp(el, $.ui.keyCode.DOWN);
+ equals(el.val(), "-0.7", "DOWN 1 time with step: 0.7");
+ for ( var i = 0 ; i < 11 ; i++ ) {
+ simulateKeyDownUp(el, $.ui.keyCode.UP);
+ }
+ equals(el.val(), "7.0", "UP 11 times with step: 0.7");
});
test("value, default, specified in markup", function() {
diff --git a/ui/jquery.ui.spinner.js b/ui/jquery.ui.spinner.js
index 2c2da22d1..09d056f50 100644
--- a/ui/jquery.ui.spinner.js
+++ b/ui/jquery.ui.spinner.js
@@ -24,13 +24,27 @@ $.widget('ui.spinner', {
incremental: true,
max: Number.MAX_VALUE,
min: -Number.MAX_VALUE,
- numberformat: "n",
+ numberformat: null,
step: 1,
value: null
},
- _create: function() {
- this.value(this.options.value !== null ? this.options.value : this.element.val());
+ _create: function() {
+ // html5 attributes initalization
+ // TODO refactor
+ var min = this.element.attr("min");
+ if (typeof min == "string" && min.length > 0) {
+ this.options.min = this._parse(min);
+ }
+ var max = this.element.attr("max");
+ if (typeof max == "string" && max.length > 0) {
+ this.options.max = this._parse(max);
+ }
+ var step = this.element.attr("step");
+ if (typeof step == "string" && step.length > 0) {
+ this.options.step = this._parse(step);
+ }
+ this.value(this.options.value !== null ? this.options.value : this.element.val() || 0);
this._draw();
this._mousewheel();
this._aria();
@@ -39,7 +53,7 @@ $.widget('ui.spinner', {
var self = this,
options = self.options;
- var uiSpinner = self.element
+ var uiSpinner = this.uiSpinner = self.element
.addClass('ui-spinner-input')
.attr('autocomplete', 'off')
.wrap(self._uiSpinnerHtml())
@@ -65,12 +79,18 @@ $.widget('ui.spinner', {
this.element
.bind('keydown'+namespace, function(event) {
+ if (self.options.disabled) {
+ return;
+ }
if (self._start(event)) {
return self._keydown(event);
}
return true;
})
.bind('keyup'+namespace, function(event) {
+ if (self.options.disabled) {
+ return;
+ }
if (self.spinning) {
self._stop(event);
self._change(event);
@@ -88,11 +108,6 @@ $.widget('ui.spinner', {
self.focused = false;
});
- // disable spinner if element was already disabled
- if (options.disabled) {
- this.disable();
- }
-
// button bindings
this.buttons = uiSpinner.find('.ui-spinner-button')
.attr("tabIndex", -1)
@@ -103,13 +118,19 @@ $.widget('ui.spinner', {
.last()
.removeClass("ui-corner-all")
.end()
- .bind('mousedown', function(event) {
+ .bind('mousedown', function(event) {
+ if (self.options.disabled) {
+ return;
+ }
if (self._start(event) === false) {
return false;
}
self._repeat(null, $(this).hasClass('ui-spinner-up') ? 1 : -1, event);
})
.bind('mouseup', function(event) {
+ if (self.options.disabled) {
+ return;
+ }
if (self.counter == 1) {
self._spin(($(this).hasClass('ui-spinner-up') ? 1 : -1) * self.options.step, event);
}
@@ -119,6 +140,9 @@ $.widget('ui.spinner', {
}
})
.bind("mouseenter", function() {
+ if (self.options.disabled) {
+ return;
+ }
// button will add ui-state-active if mouse was down while mouseleave and kept down
if ($(this).hasClass("ui-state-active")) {
if (self._start(event) === false) {
@@ -132,9 +156,12 @@ $.widget('ui.spinner', {
self._stop(event);
self._change(event);
}
- })
+ });
- self.uiSpinner = uiSpinner;
+ // disable spinner if element was already disabled
+ if (options.disabled) {
+ this.disable();
+ }
},
_uiSpinnerHtml: function() {
return '
';
@@ -154,9 +181,6 @@ $.widget('ui.spinner', {
return false;
},
_spin: function(step, event) {
- if (this.options.disabled) {
- return;
- }
if (!this.counter) {
this.counter = 1;
}
@@ -176,7 +200,7 @@ $.widget('ui.spinner', {
_stop: function(event) {
this.counter = 0;
if (this.timer) {
- window.clearInterval(this.timer);
+ window.clearTimeout(this.timer);
}
this.element[0].focus();
this.spinning = false;
@@ -226,6 +250,9 @@ $.widget('ui.spinner', {
_mousewheel: function() {
var self = this;
this.element.bind("mousewheel", function(event, delta) {
+ if (self.options.disabled) {
+ return;
+ }
if (!self._start(event)) {
return false;
}
@@ -233,12 +260,13 @@ $.widget('ui.spinner', {
if (self.timeout) {
window.clearTimeout(self.timeout);
}
+ // TODO can we implement that without a timeout?
self.timeout = window.setTimeout(function() {
if (self.spinning) {
self._stop(event);
self._change(event);
}
- }, 50);
+ }, 13);
event.preventDefault();
});
},
@@ -286,11 +314,13 @@ $.widget('ui.spinner', {
break;
case 'value':
this._format(this._parse(this.options.value));
+ this._aria();
break;
}
},
_aria: function() {
- this.uiSpinner
+ // TODO remove check, as soon as this method doesn't get called anymore before uiSpinner is initalized
+ this.uiSpinner && this.uiSpinner
.attr('aria-valuemin', this.options.min)
.attr('aria-valuemax', this.options.max)
.attr('aria-valuenow', this.value());
@@ -305,13 +335,13 @@ $.widget('ui.spinner', {
var culture = Globalization.culture || Globalization.cultures['default'];
val = val.replace(culture.numberFormat.currency.symbol, "");
}
- val = window.Globalization ? Globalization.parseFloat(val) : +val;
+ val = window.Globalization && this.options.numberformat ? Globalization.parseFloat(val) : +val;
}
console.log("input", input, "parsed", val)
return isNaN(val) ? null : val;
},
_format: function(num) {
- this.element.val( window.Globalization ? Globalization.format(num, this.options.numberformat) : num );
+ this.element.val( window.Globalization && this.options.numberformat ? Globalization.format(num, this.options.numberformat) : num );
},
destroy: function() {
@@ -331,20 +361,18 @@ $.widget('ui.spinner', {
enable: function() {
this.element
.removeAttr('disabled')
- .siblings()
- .removeAttr('disabled')
.parent()
.removeClass('ui-spinner-disabled ui-state-disabled');
this.options.disabled = false;
+ this.buttons.button("enable");
},
disable: function() {
this.element
.attr('disabled', true)
- .siblings()
- .attr('disabled', true)
.parent()
.addClass('ui-spinner-disabled ui-state-disabled');
this.options.disabled = true;
+ this.buttons.button("disable");
},
stepUp: function(steps) {
this._spin((steps || 1) * this.options.step, null);
@@ -355,10 +383,10 @@ $.widget('ui.spinner', {
return this;
},
pageUp: function(pages) {
- return this.stepUp((pages || 1) * this.options.page);
+ return this.stepUp((pages || 1) * pageModifier);
},
pageDown: function(pages) {
- return this.stepDown((pages || 1) * this.options.page);
+ return this.stepDown((pages || 1) * pageModifier);
},
widget: function() {
--
cgit v1.2.3
From d91cd61f79bf048539ac9443ae3d8ffcbe55ef90 Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Wed, 27 Oct 2010 16:38:00 +0200
Subject: Spinner: More refactorings and cleanups, and heavy improvement on the
incremental-logic, including a delay of 500ms after the first increment and
before continous increments
---
demos/spinner/currency.html | 1 -
ui/jquery.ui.spinner.js | 121 ++++++++++++++++++--------------------------
2 files changed, 50 insertions(+), 72 deletions(-)
(limited to 'demos/spinner')
diff --git a/demos/spinner/currency.html b/demos/spinner/currency.html
index 0909f4ef5..6ecd43c1e 100644
--- a/demos/spinner/currency.html
+++ b/demos/spinner/currency.html
@@ -18,7 +18,6 @@
$(function() {
$("#currency").change(function() {
var current = $("#spinner").spinner("value");
- console.log("before!!", current)
Globalization.preferCulture($(this).val());
$("#spinner").spinner("value", current);
})
diff --git a/ui/jquery.ui.spinner.js b/ui/jquery.ui.spinner.js
index 9597efb73..b6cf615da 100644
--- a/ui/jquery.ui.spinner.js
+++ b/ui/jquery.ui.spinner.js
@@ -27,8 +27,14 @@ $.widget('ui.spinner', {
},
_create: function() {
- // html5 attributes initalization
- // TODO refactor
+ this._draw();
+ this._markupOptions();
+ this._mousewheel();
+ this._aria();
+ },
+
+ _markupOptions: function() {
+ // TODO refactor and read only when the related option is null (set default to null, init Number.MAX_VALUE only when nothing is specified)
var min = this.element.attr("min");
if (typeof min == "string" && min.length > 0) {
this.options.min = this._parse(min);
@@ -42,9 +48,6 @@ $.widget('ui.spinner', {
this.options.step = this._parse(step);
}
this.value(this.options.value !== null ? this.options.value : this.element.val() || 0);
- this._draw();
- this._mousewheel();
- this._aria();
},
_draw: function() {
@@ -69,7 +72,7 @@ $.widget('ui.spinner', {
self.hovered = false;
});
- // TODO: need a better way to exclude IE8 without resorting to $.browser.version
+ // TODO: move to theme, ask FG how
// fix inline-block issues for IE. Since IE8 supports inline-block we need to exclude it.
if (!$.support.opacity && uiSpinner.css('display') == 'inline-block' && $.browser.version < 8) {
uiSpinner.css('display', 'inline');
@@ -110,12 +113,7 @@ $.widget('ui.spinner', {
this.buttons = uiSpinner.find('.ui-spinner-button')
.attr("tabIndex", -1)
.button()
- .first()
- .removeClass("ui-corner-all")
- .end()
- .last()
- .removeClass("ui-corner-all")
- .end()
+ .removeClass("ui-corner-all")
.bind('mousedown', function(event) {
if (self.options.disabled) {
return;
@@ -129,9 +127,6 @@ $.widget('ui.spinner', {
if (self.options.disabled) {
return;
}
- if (self.counter == 1) {
- self._spin(($(this).hasClass('ui-spinner-up') ? 1 : -1) * self.options.step, event);
- }
if (self.spinning) {
self._stop(event);
self._change(event);
@@ -150,7 +145,7 @@ $.widget('ui.spinner', {
}
})
.bind("mouseleave", function() {
- if (self.timer && self.spinning) {
+ if (self.spinning) {
self._stop(event);
self._change(event);
}
@@ -197,11 +192,9 @@ $.widget('ui.spinner', {
return false;
}
self._spin((delta > 0 ? 1 : -1) * self.options.step, event);
- if (self.timeout) {
- window.clearTimeout(self.timeout);
- }
+ clearTimeout(self.timeout);
// TODO can we implement that without a timeout?
- self.timeout = window.setTimeout(function() {
+ self.timeout = setTimeout(function() {
if (self.spinning) {
self._stop(event);
self._change(event);
@@ -231,20 +224,16 @@ $.widget('ui.spinner', {
return false;
},
- // TODO tune repeat behaviour, see http://jsbin.com/aruki4/2 for reference
_repeat: function(i, steps, event) {
var self = this;
- i = i || 100;
+ i = i || 500;
- if (this.timer) {
- window.clearTimeout(this.timer);
- }
-
- this.timer = window.setTimeout(function() {
- self._repeat(self.options.incremental && self.counter > 20 ? 20 : i, steps, event);
+ clearTimeout(this.timer);
+ this.timer = setTimeout(function() {
+ self._repeat(40, steps, event);
}, i);
- self._spin(steps*self.options.step, event);
+ self._spin(steps * self.options.step, event);
},
_spin: function(step, event) {
@@ -252,13 +241,16 @@ $.widget('ui.spinner', {
this.counter = 1;
}
- var newVal = this.options.value + step * (this.options.incremental && this.counter > 100
- ? this.counter > 200
- ? 100
- : 10
- : 1);
+ // TODO refactor, maybe figure out some non-linear math
+ var newVal = this.options.value + step * (this.options.incremental &&
+ this.counter > 20
+ ? this.counter > 100
+ ? this.counter > 200
+ ? 100
+ : 10
+ : 2
+ : 1);
- // cancelable
if (this._trigger('spin', event, { value: newVal }) !== false) {
this.value(newVal);
this.counter++;
@@ -288,28 +280,32 @@ $.widget('ui.spinner', {
if (value > this.options.max) {
value = this.options.max;
}
- }
+ }
+ if (key == 'disabled') {
+ if (value) {
+ this.element.attr("disabled", true);
+ this.buttons.button("disable");
+ } else {
+ this.element.removeAttr("disabled");
+ this.buttons.button("enable");
+ }
+ }
$.Widget.prototype._setOption.call( this, key, value );
- this._afterSetData(key, value);
},
- _afterSetData: function(key, value) {
- switch(key) {
- case 'value':
- this._format(this.options.value);
- case 'max':
- case 'min':
- case 'step':
- this._aria();
+ _setOptions: function( options ) {
+ $.Widget.prototype._setOptions.call( this, options );
+ if ( "value" in options ) {
+ this._format( this.options.value );
}
+ this._aria();
},
_aria: function() {
- // TODO remove check, as soon as this method doesn't get called anymore before uiSpinner is initalized
- this.uiSpinner && this.uiSpinner
- .attr('aria-valuemin', this.options.min)
- .attr('aria-valuemax', this.options.max)
- .attr('aria-valuenow', this.options.value);
+ this.uiSpinner
+ .attr('aria-valuemin', this.options.min)
+ .attr('aria-valuemax', this.options.max)
+ .attr('aria-valuenow', this.options.value);
},
_parse: function(val) {
@@ -327,6 +323,7 @@ $.widget('ui.spinner', {
},
_format: function(num) {
+ var num = this.options.value;
this.element.val( window.Globalization && this.options.numberformat ? Globalization.format(num, this.options.numberformat) : num );
},
@@ -339,30 +336,12 @@ $.widget('ui.spinner', {
this.uiSpinner.replaceWith(this.element);
},
- enable: function() {
- this.element
- .removeAttr('disabled')
- .parent()
- .removeClass('ui-spinner-disabled ui-state-disabled');
- this.options.disabled = false;
- this.buttons.button("enable");
- },
-
- disable: function() {
- this.element
- .attr('disabled', true)
- .parent()
- .addClass('ui-spinner-disabled ui-state-disabled');
- this.options.disabled = true;
- this.buttons.button("disable");
- },
-
stepUp: function(steps) {
- this._spin((steps || 1) * this.options.step, null);
+ this._spin((steps || 1) * this.options.step);
},
stepDown: function(steps) {
- this._spin((steps || 1) * -this.options.step, null);
+ this._spin((steps || 1) * -this.options.step);
},
pageUp: function(pages) {
@@ -377,7 +356,7 @@ $.widget('ui.spinner', {
if (!arguments.length) {
return this.options.value;
}
- this._setOption('value', newVal);
+ this.option('value', newVal);
},
widget: function() {
--
cgit v1.2.3
From 345592ff4a802a0049aae016d88605b135f6d13a Mon Sep 17 00:00:00 2001
From: jzaefferer
Date: Tue, 2 Nov 2010 16:31:22 +0100
Subject: Spinner: Removing rtl demo
---
demos/spinner/index.html | 1 -
demos/spinner/rtl.html | 36 ------------------------------------
2 files changed, 37 deletions(-)
delete mode 100644 demos/spinner/rtl.html
(limited to 'demos/spinner')
diff --git a/demos/spinner/index.html b/demos/spinner/index.html
index 68716ac99..f43f6e2a1 100644
--- a/demos/spinner/index.html
+++ b/demos/spinner/index.html
@@ -13,7 +13,6 @@
Currency
Map
Mousewheel Disabled
- RTL
-
-
-
-
-
-
diff --git a/demos/spinner/rtl.html b/demos/spinner/rtl.html
deleted file mode 100644
index 93a2022ff..000000000
--- a/demos/spinner/rtl.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-