aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gruntfile.js1
-rw-r--r--build/tasks/testswarm.js1
-rw-r--r--demos/calendar/buttonbar.html37
-rw-r--r--demos/calendar/default.html31
-rw-r--r--demos/calendar/dropdown-month-year.html (renamed from demos/datepicker/dropdown-month-year.html)13
-rw-r--r--demos/calendar/index.html22
-rw-r--r--demos/calendar/localization.html43
-rw-r--r--demos/calendar/min-max.html38
-rw-r--r--demos/calendar/multiple-months.html33
-rw-r--r--demos/calendar/other-months.html40
-rw-r--r--demos/calendar/show-week.html35
-rw-r--r--demos/datepicker/alt-field.html29
-rw-r--r--demos/datepicker/animation.html19
-rw-r--r--demos/datepicker/buttonbar.html28
-rw-r--r--demos/datepicker/date-formats.html27
-rw-r--r--demos/datepicker/date-range.html57
-rw-r--r--demos/datepicker/datepicker-ar.js36
-rw-r--r--demos/datepicker/datepicker-fr.js38
-rw-r--r--demos/datepicker/datepicker-he.js36
-rw-r--r--demos/datepicker/datepicker-zh-TW.js36
-rw-r--r--demos/datepicker/default.html6
-rw-r--r--demos/datepicker/icon-trigger.html28
-rw-r--r--demos/datepicker/index.html13
-rw-r--r--demos/datepicker/inline.html26
-rw-r--r--demos/datepicker/localization.html30
-rw-r--r--demos/datepicker/min-max.html26
-rw-r--r--demos/datepicker/multiple-calendars.html29
-rw-r--r--demos/datepicker/other-months.html30
-rw-r--r--demos/datepicker/show-week.html32
-rw-r--r--demos/index.html1
-rw-r--r--external/date.js217
-rw-r--r--external/globalize-old/LICENSE21
-rw-r--r--external/globalize-old/globalize.culture.de-DE.js (renamed from external/globalize/globalize.culture.de-DE.js)0
-rw-r--r--external/globalize-old/globalize.culture.ja-JP.js (renamed from external/globalize/globalize.culture.ja-JP.js)0
-rw-r--r--external/globalize-old/globalize.js1585
-rw-r--r--external/globalize/globalize.js3049
-rw-r--r--external/localization.js3137
-rw-r--r--tests/lib/bootstrap.js8
-rw-r--r--tests/unit/all.html1
-rw-r--r--tests/unit/calendar/all.html26
-rw-r--r--tests/unit/calendar/calendar.html21
-rw-r--r--tests/unit/calendar/common.js26
-rw-r--r--tests/unit/calendar/core.js390
-rw-r--r--tests/unit/calendar/events.js0
-rw-r--r--tests/unit/calendar/helper.js31
-rw-r--r--tests/unit/calendar/methods.js145
-rw-r--r--tests/unit/calendar/options.js323
-rw-r--r--tests/unit/date/all.html26
-rw-r--r--tests/unit/date/core.js197
-rw-r--r--tests/unit/date/date.html19
-rw-r--r--tests/unit/datepicker/common.js36
-rw-r--r--tests/unit/datepicker/core.js629
-rw-r--r--tests/unit/datepicker/datepicker.html6
-rw-r--r--tests/unit/datepicker/events.js270
-rw-r--r--tests/unit/datepicker/helper.js36
-rw-r--r--tests/unit/datepicker/methods.js232
-rw-r--r--tests/unit/datepicker/options.js1211
-rw-r--r--tests/unit/index.html1
-rw-r--r--tests/unit/spinner/options.js4
-rw-r--r--tests/visual/compound/datepicker_dialog.html4
-rw-r--r--tests/visual/compound/dialog_widgets.html4
-rw-r--r--tests/visual/dialog/complex-dialogs.html4
-rw-r--r--themes/base/base.css1
-rw-r--r--themes/base/calendar.css158
-rw-r--r--themes/base/datepicker.css160
-rw-r--r--ui/calendar.js614
-rw-r--r--ui/datepicker.js2193
67 files changed, 9723 insertions, 5883 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 3018702f5..5d77e7393 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -28,6 +28,7 @@ var
"core",
"accordion",
"autocomplete",
+ "calendar",
"button",
"datepicker",
"dialog",
diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js
index 3aca0e7b2..b889c6c36 100644
--- a/build/tasks/testswarm.js
+++ b/build/tasks/testswarm.js
@@ -14,6 +14,7 @@ var versions = {
"Accordion": "accordion/accordion.html",
"Autocomplete": "autocomplete/autocomplete.html",
"Button": "button/button.html",
+ "Calendar": "calendar/calendar.html",
"Core": "core/core.html",
"Datepicker": "datepicker/datepicker.html",
"Dialog": "dialog/dialog.html",
diff --git a/demos/calendar/buttonbar.html b/demos/calendar/buttonbar.html
new file mode 100644
index 000000000..de2ae22dc
--- /dev/null
+++ b/demos/calendar/buttonbar.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Display button bar</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ $( "#calendar" ).calendar({
+ buttons: {
+ Today: function() {
+ $( this ).calendar( "valueAsDate", new Date() );
+ }
+ }
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+
+<div class="demo-description">
+<p>Display a button for selecting Today's date with the <code>buttons</code> option.</p>
+</div>
+</body>
+</html>
diff --git a/demos/calendar/default.html b/demos/calendar/default.html
new file mode 100644
index 000000000..a67c2d702
--- /dev/null
+++ b/demos/calendar/default.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Default functionality</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ $( "#calendar" ).calendar();
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+
+<div class="demo-description">
+<p>The calendar is a widget for selecting a date using a visual calendar representation.</p>
+</div>
+</body>
+</html>
diff --git a/demos/datepicker/dropdown-month-year.html b/demos/calendar/dropdown-month-year.html
index 8668018d9..050a89157 100644
--- a/demos/datepicker/dropdown-month-year.html
+++ b/demos/calendar/dropdown-month-year.html
@@ -2,16 +2,21 @@
<html lang="en">
<head>
<meta charset="utf-8">
- <title>jQuery UI Datepicker - Display month &amp; year menus</title>
+ <title>jQuery UI Calendar - Display month &amp; year menus</title>
<link rel="stylesheet" href="../../themes/base/all.css">
<script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
<script src="../../ui/core.js"></script>
<script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
- $( "#datepicker" ).datepicker({
+ $( "#calendar" ).calendar({
changeMonth: true,
changeYear: true
});
@@ -20,7 +25,7 @@
</head>
<body>
-<p>Date: <input type="text" id="datepicker"></p>
+<div id="calendar"></div>
<div class="demo-description">
<p>Show month and year dropdowns in place of the static month/year header to facilitate navigation through large timeframes. Add the boolean <code>changeMonth</code> and <code>changeYear</code> options.</p>
diff --git a/demos/calendar/index.html b/demos/calendar/index.html
new file mode 100644
index 000000000..751301a00
--- /dev/null
+++ b/demos/calendar/index.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery UI Calendar Demos</title>
+</head>
+<body>
+
+<ul>
+ <li><a href="default.html">Default functionality</a></li>
+ <li><a href="buttonbar.html">Display button bar</a></li>
+ <li><a href="dropdown-month-year.html">Display month &amp; year menus</a></li>
+ <li><a href="localization.html">Localize calendar</a></li>
+ <li><a href="min-max.html">Restrict date range</a></li>
+ <li><a href="multiple-months.html">Display multiple months</a></li>
+ <li><a href="other-months.html">Dates in other months</a></li>
+ <li><a href="show-week.html">Show week of the year</a></li>
+</ul>
+
+</body>
+</html>
diff --git a/demos/calendar/localization.html b/demos/calendar/localization.html
new file mode 100644
index 000000000..9b1e7d070
--- /dev/null
+++ b/demos/calendar/localization.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Localize calendar</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ var calendar = $( "#calendar" ),
+ select = $( "#locale" );
+
+ Globalize.locale( select.val() );
+ calendar.calendar();
+ select.change( function() {
+ Globalize.locale( $( this ).val() );
+ calendar.calendar( "valueAsDate", calendar.calendar( "valueAsDate" ) );
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+<select id="locale">
+ <option value="de-DE" selected>German (Deutsch)</option>
+ <option value="en">English</option>
+</select>
+
+<div class="demo-description">
+<p>Localize the calendar language and format (English / Western formatting is the default). The calendar includes built-in support for languages that read right-to-left, such as Arabic and Hebrew.</p>
+</div>
+</body>
+</html>
diff --git a/demos/calendar/min-max.html b/demos/calendar/min-max.html
new file mode 100644
index 000000000..fa8471e2c
--- /dev/null
+++ b/demos/calendar/min-max.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Restrict date range</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ var now = new Date(),
+ dateMin = new Date( now.getFullYear(), now.getMonth(), now.getDay() + 1 ),
+ dateMax = new Date( now.getFullYear(), now.getMonth(), now.getDay() + 8 );
+
+ $( "#calendar" ).calendar({
+ min: dateMin,
+ max: dateMax
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+
+<div class="demo-description">
+<p>Restrict the range of selectable dates with the <code>min</code> and <code>max</code> options. Set the beginning and end dates as actual dates (<code>new Date(2009, 1 - 1, 26)</code>).</p>
+</div>
+</body>
+</html>
diff --git a/demos/calendar/multiple-months.html b/demos/calendar/multiple-months.html
new file mode 100644
index 000000000..8366b2204
--- /dev/null
+++ b/demos/calendar/multiple-months.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Display multiple months</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ $( "#calendar" ).calendar({
+ numberOfMonths: 3
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+
+<div class="demo-description">
+<p>Set the <code>numberOfMonths</code> option to an integer of 2 or more to show multiple months in a single calendar.</p>
+</div>
+</body>
+</html>
diff --git a/demos/calendar/other-months.html b/demos/calendar/other-months.html
new file mode 100644
index 000000000..0228c62df
--- /dev/null
+++ b/demos/calendar/other-months.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Dates in other months</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ $( "#calendar" ).calendar({
+ eachDay: function( day ) {
+ if ( day.lead ) {
+ day.render = true;
+ day.selectable = true;
+ day.extraClasses = "ui-priority-secondary";
+ }
+ }
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+
+<div class="demo-description">
+<p>The calendar can show dates that come from other than the main month
+ being displayed. These other dates can also be made selectable.</p>
+</div>
+</body>
+</html>
diff --git a/demos/calendar/show-week.html b/demos/calendar/show-week.html
new file mode 100644
index 000000000..08687aa0d
--- /dev/null
+++ b/demos/calendar/show-week.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar - Show week of the year</title>
+ <link rel="stylesheet" href="../../themes/base/all.css">
+ <script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
+ <script src="../../ui/core.js"></script>
+ <script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ $( "#calendar" ).calendar({
+ showWeek: true
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div id="calendar"></div>
+
+<div class="demo-description">
+<p>The calendar can show the week of the year. The calculation follows
+ <a href="http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table">Unicode CLDR specification</a>.
+ This means that some days from one year may be placed into weeks 'belonging' to another year.</p>
+</div>
+</body>
+</html>
diff --git a/demos/datepicker/alt-field.html b/demos/datepicker/alt-field.html
deleted file mode 100644
index 7e3b50a6d..000000000
--- a/demos/datepicker/alt-field.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Populate alternate field</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker({
- altField: "#alternate",
- altFormat: "DD, d MM, yy"
- });
- });
- </script>
-</head>
-<body>
-
-<p>Date: <input type="text" id="datepicker">&nbsp;<input type="text" id="alternate" size="30"/></p>
-
-<div class="demo-description">
-<p>Populate an alternate field with its own date format whenever a date is selected using the <code>altField</code> and <code>altFormat</code> options. This feature could be used to present a human-friendly date for user selection, while passing a more computer-friendly date through for further processing.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/animation.html b/demos/datepicker/animation.html
index 36860cb42..04b196627 100644
--- a/demos/datepicker/animation.html
+++ b/demos/datepicker/animation.html
@@ -5,6 +5,9 @@
<title>jQuery UI Datepicker - Animations</title>
<link rel="stylesheet" href="../../themes/base/all.css">
<script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
<script src="../../ui/core.js"></script>
<script src="../../ui/widget.js"></script>
<script src="../../ui/effect.js"></script>
@@ -14,13 +17,20 @@
<script src="../../ui/effect-drop.js"></script>
<script src="../../ui/effect-fold.js"></script>
<script src="../../ui/effect-slide.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
<script src="../../ui/datepicker.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
$( "#datepicker" ).datepicker();
$( "#anim" ).on( "change", function() {
- $( "#datepicker" ).datepicker( "option", "showAnim", $( this ).val() );
+ var value = $( this ).val(),
+ hideValue = $( this ).find( "option:selected" ).data( "hide" );
+ $( "#datepicker" )
+ .datepicker( "option", "show", value )
+ .datepicker( "option", "hide", hideValue || value );
});
});
</script>
@@ -31,16 +41,15 @@
<p>Animations:<br />
<select id="anim">
- <option value="show">Show (default)</option>
- <option value="slideDown">Slide down</option>
- <option value="fadeIn">Fade in</option>
+ <option value="show">Fade in/out (default)</option>
+ <option value="slideDown" data-hide="slideUp">Slide down/up</option>
<option value="blind">Blind (UI Effect)</option>
<option value="bounce">Bounce (UI Effect)</option>
<option value="clip">Clip (UI Effect)</option>
<option value="drop">Drop (UI Effect)</option>
<option value="fold">Fold (UI Effect)</option>
<option value="slide">Slide (UI Effect)</option>
- <option value="">None</option>
+ <option value="false">None</option>
</select>
</p>
diff --git a/demos/datepicker/buttonbar.html b/demos/datepicker/buttonbar.html
deleted file mode 100644
index 040ec1112..000000000
--- a/demos/datepicker/buttonbar.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Display button bar</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker({
- showButtonPanel: true
- });
- });
- </script>
-</head>
-<body>
-
-<p>Date: <input type="text" id="datepicker"></p>
-
-<div class="demo-description">
-<p>Display a button for selecting Today's date and a Done button for closing the calendar with the boolean <code>showButtonPanel</code> option. Each button is enabled by default when the bar is displayed, but can be turned off with additional options. Button text is customizable.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/date-formats.html b/demos/datepicker/date-formats.html
index 5664beb5b..f00310a47 100644
--- a/demos/datepicker/date-formats.html
+++ b/demos/datepicker/date-formats.html
@@ -5,15 +5,29 @@
<title>jQuery UI Datepicker - Format date</title>
<link rel="stylesheet" href="../../themes/base/all.css">
<script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
<script src="../../ui/core.js"></script>
<script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/position.js"></script>
+ <script src="../../ui/calendar.js"></script>
<script src="../../ui/datepicker.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
- $( "#datepicker" ).datepicker();
+ var value,
+ datepicker = $( "#datepicker" ).datepicker();
+
$( "#format" ).on( "change", function() {
- $( "#datepicker" ).datepicker( "option", "dateFormat", $( this ).val() );
+ value = $( this ).val();
+
+ if ( value === "iso" ) {
+ datepicker.datepicker( "option", "dateFormat", { pattern: "yyyy-MM-dd" } );
+ } else {
+ datepicker.datepicker( "option", "dateFormat", { date: value } );
+ }
});
});
</script>
@@ -24,12 +38,9 @@
<p>Format options:<br />
<select id="format">
- <option value="mm/dd/yy">Default - mm/dd/yy</option>
- <option value="yy-mm-dd">ISO 8601 - yy-mm-dd</option>
- <option value="d M, y">Short - d M, y</option>
- <option value="d MM, y">Medium - d MM, y</option>
- <option value="DD, d MM, yy">Full - DD, d MM, yy</option>
- <option value="'day' d 'of' MM 'in the year' yy">With text - 'day' d 'of' MM 'in the year' yy</option>
+ <option value="short">Short - M/d/yy in "en" locale</option>
+ <option value="long">Long - MMMM d, y in "en" locale</option>
+ <option value="iso">ISO 8601 - yyyy-MM-dd</option>
</select>
</p>
diff --git a/demos/datepicker/date-range.html b/demos/datepicker/date-range.html
deleted file mode 100644
index 8d606969c..000000000
--- a/demos/datepicker/date-range.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Select a Date Range</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- var dateFormat = "mm/dd/yy",
- from = $( "#from" )
- .datepicker({
- defaultDate: "+1w",
- changeMonth: true,
- numberOfMonths: 3
- })
- .on( "change", function() {
- to.datepicker( "option", "minDate", getDate( this ) );
- }),
- to = $( "#to" ).datepicker({
- defaultDate: "+1w",
- changeMonth: true,
- numberOfMonths: 3
- })
- .on( "change", function() {
- from.datepicker( "option", "maxDate", getDate( this ) );
- });
-
- function getDate( element ) {
- var date;
- try {
- date = $.datepicker.parseDate( dateFormat, element.value );
- } catch( error ) {
- date = null;
- }
-
- return date;
- }
- });
- </script>
-</head>
-<body>
-
-<label for="from">From</label>
-<input type="text" id="from" name="from"/>
-<label for="to">to</label>
-<input type="text" id="to" name="to"/>
-
-<div class="demo-description">
-<p>Select the date range to search for.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/datepicker-ar.js b/demos/datepicker/datepicker-ar.js
deleted file mode 100644
index fc6d2a883..000000000
--- a/demos/datepicker/datepicker-ar.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Arabic Translation for jQuery UI date picker plugin. */
-/* Khaled Alhourani -- me@khaledalhourani.com */
-/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */
-(function( factory ) {
- if ( typeof define === "function" && define.amd ) {
-
- // AMD. Register as an anonymous module.
- define([ "../jquery.ui.datepicker" ], factory );
- } else {
-
- // Browser globals
- factory( jQuery.datepicker );
- }
-}(function( datepicker ) {
- datepicker.regional['ar'] = {
- closeText: 'إغلاق',
- prevText: '&#x3C;السابق',
- nextText: 'التالي&#x3E;',
- currentText: 'اليوم',
- monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'مايو', 'حزيران',
- 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],
- monthNamesShort: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
- dayNames: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],
- dayNamesShort: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],
- dayNamesMin: ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],
- weekHeader: 'أسبوع',
- dateFormat: 'dd/mm/yy',
- firstDay: 6,
- isRTL: true,
- showMonthAfterYear: false,
- yearSuffix: ''};
- datepicker.setDefaults(datepicker.regional['ar']);
-
- return datepicker.regional['ar'];
-
-}));
diff --git a/demos/datepicker/datepicker-fr.js b/demos/datepicker/datepicker-fr.js
deleted file mode 100644
index 33fa80d48..000000000
--- a/demos/datepicker/datepicker-fr.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* French initialisation for the jQuery UI date picker plugin. */
-/* Written by Keith Wood (kbwood{at}iinet.com.au),
- Stéphane Nahmani (sholby@sholby.net),
- Stéphane Raimbault <stephane.raimbault@gmail.com> */
-(function( factory ) {
- if ( typeof define === "function" && define.amd ) {
-
- // AMD. Register as an anonymous module.
- define([ "../jquery.ui.datepicker" ], factory );
- } else {
-
- // Browser globals
- factory( jQuery.datepicker );
- }
-}(function( datepicker ) {
- datepicker.regional['fr'] = {
- closeText: 'Fermer',
- prevText: 'Précédent',
- nextText: 'Suivant',
- currentText: 'Aujourd\'hui',
- monthNames: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
- 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
- monthNamesShort: ['janv.', 'févr.', 'mars', 'avril', 'mai', 'juin',
- 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],
- dayNames: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
- dayNamesShort: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
- dayNamesMin: ['D','L','M','M','J','V','S'],
- weekHeader: 'Sem.',
- dateFormat: 'dd/mm/yy',
- firstDay: 1,
- isRTL: false,
- showMonthAfterYear: false,
- yearSuffix: ''};
- datepicker.setDefaults(datepicker.regional['fr']);
-
- return datepicker.regional['fr'];
-
-}));
diff --git a/demos/datepicker/datepicker-he.js b/demos/datepicker/datepicker-he.js
deleted file mode 100644
index bf58038f5..000000000
--- a/demos/datepicker/datepicker-he.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Hebrew initialisation for the UI Datepicker extension. */
-/* Written by Amir Hardon (ahardon at gmail dot com). */
-(function( factory ) {
- if ( typeof define === "function" && define.amd ) {
-
- // AMD. Register as an anonymous module.
- define([ "../jquery.ui.datepicker" ], factory );
- } else {
-
- // Browser globals
- factory( jQuery.datepicker );
- }
-}(function( datepicker ) {
- datepicker.regional['he'] = {
- closeText: 'סגור',
- prevText: '&#x3C;הקודם',
- nextText: 'הבא&#x3E;',
- currentText: 'היום',
- monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני',
- 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'],
- monthNamesShort: ['ינו','פבר','מרץ','אפר','מאי','יוני',
- 'יולי','אוג','ספט','אוק','נוב','דצמ'],
- dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'],
- dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'],
- dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'],
- weekHeader: 'Wk',
- dateFormat: 'dd/mm/yy',
- firstDay: 0,
- isRTL: true,
- showMonthAfterYear: false,
- yearSuffix: ''};
- datepicker.setDefaults(datepicker.regional['he']);
-
- return datepicker.regional['he'];
-
-}));
diff --git a/demos/datepicker/datepicker-zh-TW.js b/demos/datepicker/datepicker-zh-TW.js
deleted file mode 100644
index ebfd73ac5..000000000
--- a/demos/datepicker/datepicker-zh-TW.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Chinese initialisation for the jQuery UI date picker plugin. */
-/* Written by Ressol (ressol@gmail.com). */
-(function( factory ) {
- if ( typeof define === "function" && define.amd ) {
-
- // AMD. Register as an anonymous module.
- define([ "../jquery.ui.datepicker" ], factory );
- } else {
-
- // Browser globals
- factory( jQuery.datepicker );
- }
-}(function( datepicker ) {
- datepicker.regional['zh-TW'] = {
- closeText: '關閉',
- prevText: '&#x3C;上月',
- nextText: '下月&#x3E;',
- currentText: '今天',
- monthNames: ['一月','二月','三月','四月','五月','六月',
- '七月','八月','九月','十月','十一月','十二月'],
- monthNamesShort: ['一月','二月','三月','四月','五月','六月',
- '七月','八月','九月','十月','十一月','十二月'],
- dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'],
- dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'],
- dayNamesMin: ['日','一','二','三','四','五','六'],
- weekHeader: '周',
- dateFormat: 'yy/mm/dd',
- firstDay: 1,
- isRTL: false,
- showMonthAfterYear: true,
- yearSuffix: '年'};
- datepicker.setDefaults(datepicker.regional['zh-TW']);
-
- return datepicker.regional['zh-TW'];
-
-}));
diff --git a/demos/datepicker/default.html b/demos/datepicker/default.html
index a11d5def7..b2439b29a 100644
--- a/demos/datepicker/default.html
+++ b/demos/datepicker/default.html
@@ -5,8 +5,14 @@
<title>jQuery UI Datepicker - Default functionality</title>
<link rel="stylesheet" href="../../themes/base/all.css">
<script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
<script src="../../ui/core.js"></script>
<script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/position.js"></script>
+ <script src="../../ui/calendar.js"></script>
<script src="../../ui/datepicker.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
diff --git a/demos/datepicker/icon-trigger.html b/demos/datepicker/icon-trigger.html
index 8268f947b..c694631e1 100644
--- a/demos/datepicker/icon-trigger.html
+++ b/demos/datepicker/icon-trigger.html
@@ -5,18 +5,34 @@
<title>jQuery UI Datepicker - Icon trigger</title>
<link rel="stylesheet" href="../../themes/base/all.css">
<script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
<script src="../../ui/core.js"></script>
<script src="../../ui/widget.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/position.js"></script>
<script src="../../ui/datepicker.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
- $( "#datepicker" ).datepicker({
- showOn: "button",
- buttonImage: "images/calendar.gif",
- buttonImageOnly: true,
- buttonText: "Select date"
- });
+ var allowOpen = false,
+ datepicker = $( "#datepicker" ).datepicker({
+ beforeOpen: function() {
+ return allowOpen;
+ },
+ open: function() {
+ allowOpen = false;
+ }
+ });
+
+ $( "<img src='images/calendar.gif' alt='Open Datepicker'>")
+ .insertAfter( datepicker )
+ .click( function() {
+ allowOpen = true;
+ datepicker.focus();
+ });
});
</script>
</head>
diff --git a/demos/datepicker/index.html b/demos/datepicker/index.html
index d9c8dfc10..a56df7bd6 100644
--- a/demos/datepicker/index.html
+++ b/demos/datepicker/index.html
@@ -9,19 +9,10 @@
<ul>
<li><a href="default.html">Default functionality</a></li>
+ <li><a href="animation.html">Animations</a></li>
<li><a href="date-formats.html">Format date</a></li>
- <li><a href="min-max.html">Restrict date range</a></li>
- <li><a href="localization.html">Localize calendar</a></li>
- <li><a href="alt-field.html">Populate alternate field</a></li>
- <li><a href="inline.html">Display inline</a></li>
- <li><a href="buttonbar.html">Display button bar</a></li>
- <li><a href="dropdown-month-year.html">Display month &amp; year menus</a></li>
- <li><a href="other-months.html">Dates in other months</a></li>
- <li><a href="show-week.html">Show week of the year</a></li>
- <li><a href="multiple-calendars.html">Display multiple months</a></li>
<li><a href="icon-trigger.html">Icon trigger</a></li>
- <li><a href="animation.html">Animations</a></li>
- <li><a href="date-range.html">Date Range</a></li>
+ <li><a href="localization.html">Localize calendar</a></li>
</ul>
</body>
diff --git a/demos/datepicker/inline.html b/demos/datepicker/inline.html
deleted file mode 100644
index 5d120457b..000000000
--- a/demos/datepicker/inline.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Display inline</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker();
- });
- </script>
-</head>
-<body>
-
-Date: <div id="datepicker"></div>
-
-<div class="demo-description">
-<p>Display the datepicker embedded in the page instead of in an overlay. Simply call .datepicker() on a div instead of an input.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/localization.html b/demos/datepicker/localization.html
index 72933f011..36449a516 100644
--- a/demos/datepicker/localization.html
+++ b/demos/datepicker/localization.html
@@ -5,20 +5,27 @@
<title>jQuery UI Datepicker - Localize calendar</title>
<link rel="stylesheet" href="../../themes/base/all.css">
<script src="../../external/jquery/jquery.js"></script>
+ <script src="../../external/globalize/globalize.js"></script>
+ <script src="../../external/date.js"></script>
+ <script src="../../external/localization.js"></script>
<script src="../../ui/core.js"></script>
<script src="../../ui/widget.js"></script>
+ <script src="../../ui/button.js"></script>
+ <script src="../../ui/calendar.js"></script>
+ <script src="../../ui/position.js"></script>
<script src="../../ui/datepicker.js"></script>
- <script src="datepicker-ar.js"></script>
- <script src="datepicker-fr.js"></script>
- <script src="datepicker-he.js"></script>
- <script src="datepicker-zh-TW.js"></script>
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
- $( "#datepicker" ).datepicker( $.datepicker.regional[ "fr" ] );
- $( "#locale" ).on( "change", function() {
- $( "#datepicker" ).datepicker( "option",
- $.datepicker.regional[ $( this ).val() ] );
+ var datepicker = $( "#datepicker" ),
+ select = $( "#locale" );
+
+ Globalize.locale( select.val() );
+ datepicker.datepicker();
+
+ select.on( "change", function() {
+ Globalize.locale( $( this ).val() );
+ datepicker.datepicker( "valueAsDate", datepicker.datepicker( "valueAsDate" ) );
});
});
</script>
@@ -27,11 +34,8 @@
<p>Date: <input type="text" id="datepicker"/>&nbsp;
<select id="locale">
- <option value="ar">Arabic (&#8235;(&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;</option>
- <option value="zh-TW">Chinese Traditional (&#32321;&#39636;&#20013;&#25991;)</option>
- <option value="">English</option>
- <option value="fr" selected="selected">French (Fran&ccedil;ais)</option>
- <option value="he">Hebrew (&#8235;(&#1506;&#1489;&#1512;&#1497;&#1514;</option>
+ <option value="de-DE" selected>German (Deutsch)</option>
+ <option value="en">English</option>
</select></p>
<div class="demo-description">
diff --git a/demos/datepicker/min-max.html b/demos/datepicker/min-max.html
deleted file mode 100644
index 4052c1785..000000000
--- a/demos/datepicker/min-max.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Restrict date range</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker({ minDate: -20, maxDate: "+1M +10D" });
- });
- </script>
-</head>
-<body>
-
-<p>Date: <input type="text" id="datepicker"></p>
-
-<div class="demo-description">
-<p>Restrict the range of selectable dates with the <code>minDate</code> and <code>maxDate</code> options. Set the beginning and end dates as actual dates (new Date(2009, 1 - 1, 26)), as a numeric offset from today (-20), or as a string of periods and units ('+1M +10D'). For the last, use 'D' for days, 'W' for weeks, 'M' for months, or 'Y' for years.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/multiple-calendars.html b/demos/datepicker/multiple-calendars.html
deleted file mode 100644
index 716b6c68e..000000000
--- a/demos/datepicker/multiple-calendars.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Display multiple months</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker({
- numberOfMonths: 3,
- showButtonPanel: true
- });
- });
- </script>
-</head>
-<body>
-
-<p>Date: <input type="text" id="datepicker"></p>
-
-<div class="demo-description">
-<p>Set the <code>numberOfMonths</code> option to an integer of 2 or more to show multiple months in a single datepicker.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/other-months.html b/demos/datepicker/other-months.html
deleted file mode 100644
index 71a06c5d2..000000000
--- a/demos/datepicker/other-months.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Dates in other months</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker({
- showOtherMonths: true,
- selectOtherMonths: true
- });
- });
- </script>
-</head>
-<body>
-
-<p>Date: <input type="text" id="datepicker"></p>
-
-<div class="demo-description">
-<p>The datepicker can show dates that come from other than the main month
- being displayed. These other dates can also be made selectable.</p>
-</div>
-</body>
-</html>
diff --git a/demos/datepicker/show-week.html b/demos/datepicker/show-week.html
deleted file mode 100644
index 362645a7e..000000000
--- a/demos/datepicker/show-week.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>jQuery UI Datepicker - Show week of the year</title>
- <link rel="stylesheet" href="../../themes/base/all.css">
- <script src="../../external/jquery/jquery.js"></script>
- <script src="../../ui/core.js"></script>
- <script src="../../ui/widget.js"></script>
- <script src="../../ui/datepicker.js"></script>
- <link rel="stylesheet" href="../demos.css">
- <script>
- $(function() {
- $( "#datepicker" ).datepicker({
- showWeek: true,
- firstDay: 1
- });
- });
- </script>
-</head>
-<body>
-
-<p>Date: <input type="text" id="datepicker"></p>
-
-<div class="demo-description">
-<p>The datepicker can show the week of the year. The default calculation follows
- the ISO 8601 definition: the week starts on Monday, the first week of the year
- contains the first Thursday of the year. This means that some days from one
- year may be placed into weeks 'belonging' to another year.</p>
-</div>
-</body>
-</html>
diff --git a/demos/index.html b/demos/index.html
index f37874a44..c4a0fdf95 100644
--- a/demos/index.html
+++ b/demos/index.html
@@ -11,6 +11,7 @@
<li><a href="accordion/">accordion</a></li>
<li><a href="autocomplete/">autocomplete</a></li>
<li><a href="button/">button</a></li>
+ <li><a href="calendar/">calendar</a></li>
<li><a href="datepicker/">datepicker</a></li>
<li><a href="dialog/">dialog</a></li>
<li><a href="draggable/">draggable</a></li>
diff --git a/external/date.js b/external/date.js
new file mode 100644
index 000000000..4d404efe1
--- /dev/null
+++ b/external/date.js
@@ -0,0 +1,217 @@
+/*
+ * Calendar math built on jquery-global
+ *
+ * Based on Marc Grabanski's jQuery Date Plugin
+ * http://marcgrabanski.com/articles/jquery-date-plugin
+ */
+( function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ define( [
+ "jquery",
+ "globalize"
+ ], factory );
+ } else {
+
+ // Browser globals
+ factory( jQuery, Globalize );
+ }
+}( function( $, Globalize ) {
+
+var weekdays = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ],
+ weekdaysRev = {
+ "sun": 0,
+ "mon": 1,
+ "tue": 2,
+ "wed": 3,
+ "thu": 4,
+ "fri": 5,
+ "sat": 6
+ };
+
+Globalize.locale( "en" );
+
+$.date = function( date, globalFormat ) {
+ if ( !( this instanceof $.date ) ) {
+ return new $.date( date, globalFormat );
+ }
+ if ( typeof date === "string" && date.length ) {
+ this.dateObject = Globalize.parseDate( date, globalFormat );
+ }
+ if ( $.type( date ) === "date" ) {
+ this.dateObject = date;
+ }
+
+ this.dateObject = this.dateObject || new Date();
+ this.globalFormat = globalFormat;
+};
+
+$.date.prototype = {
+ setFormat: function( format ) {
+ if ( format ) {
+ this.globalFormat = format;
+ }
+ return this;
+ },
+ //TODO: same as the underlying Date object's terminology, but still misleading.
+ //TODO: We can use .setTime() instead of new Date and rename to setTimestamp.
+ setTime: function( time ) {
+ this.dateObject = new Date( time );
+ return this;
+ },
+ setDay: function( day ) {
+ var date = this.dateObject;
+ this.dateObject = new Date( date.getFullYear(), date.getMonth(), day, date.getHours(),
+ date.getMinutes(), date.getSeconds() );
+ return this;
+ },
+ setMonth: function( month ) {
+ // Overflow example: Month is October 31 (yeah Halloween) and month is changed to April with 30 days,
+ // the new date will me May 1. We will honor the month the user wants to set and if and overflow
+ // occurs, set to last day of month.
+ var date = this.dateObject,
+ days = date.getDay(), year = date.getFullYear();
+ if ( days > this.daysInMonth( year, month ) ) {
+
+ // Overflow
+ days = this.daysInMonth( year, month );
+ }
+ this.dateObject = new Date( year, month, days, date.getHours(),
+ date.getMinutes(), date.getSeconds() );
+ return this;
+ },
+ setYear: function( year ) {
+ var date = this.dateObject,
+ day = date.getDate(),
+ month = date.getMonth();
+
+ // Check if Leap, and February and day is 29th
+ if ( this.isLeapYear( year ) && month == 1 && day == 29 ) {
+
+ // set day to last day of February
+ day = this.daysInMonth( year, month );
+ }
+ this.dateObject = new Date( year, month, day, date.getHours(),
+ date.getMinutes(), date.getSeconds() );
+ return this;
+ },
+ setFullDate: function( year, month, day ) {
+ this.dateObject = new Date( year, month, day );
+ return this;
+ },
+ adjust: function( period, offset ) {
+ var date = this.dateObject,
+ day = period == "D" ? date.getDate() + offset : date.getDate(),
+ month = period == "M" ? date.getMonth() + offset : date.getMonth(),
+ year = period == "Y" ? date.getFullYear() + offset : date.getFullYear();
+
+ // If not day, update the day to the new month and year
+ if ( period != "D" ) {
+ day = Math.max( 1, Math.min( day, this.daysInMonth( year, month ) ) );
+ }
+ this.dateObject = new Date( year, month, day, date.getHours(),
+ date.getMinutes(), date.getSeconds() );
+ return this;
+ },
+ daysInMonth: function( year, month ) {
+ var date = this.dateObject;
+ year = year || date.getFullYear();
+ month = month || date.getMonth();
+ return 32 - new Date( year, month, 32 ).getDate();
+ },
+ monthName: function() {
+ return Globalize.format( this.dateObject, { pattern: "MMMM" } );
+ },
+ day: function() {
+ return this.dateObject.getDate();
+ },
+ month: function() {
+ return this.dateObject.getMonth();
+ },
+ year: function() {
+ return this.dateObject.getFullYear();
+ },
+ isLeapYear: function( year ) {
+ year = year || this.dateObject.getFullYear();
+ return new Date( year, 1, 29 ).getMonth() == 1;
+ },
+ weekdays: function() {
+ var result = [];
+ for ( var dow = 0; dow < 7; dow++ ) {
+ var day = ( dow + weekdaysRev[ Globalize.locale().supplemental.weekData.firstDay() ] ) % 7;
+ result.push({
+ shortname: Globalize.locale().main([ "dates/calendars/gregorian/days/format/short", weekdays[ day ] ]),
+ fullname: Globalize.locale().main([ "dates/calendars/gregorian/days/format/wide", weekdays[ day ] ])
+ });
+ }
+ return result;
+ },
+ days: function() {
+ var result = [],
+ today = $.date(),
+ date = this.dateObject,
+ firstDayOfMonth = new Date( this.year(), date.getMonth(), 1 ).getDay(),
+ leadDays = ( firstDayOfMonth - weekdaysRev[ Globalize.locale().supplemental.weekData.firstDay() ] + 7 ) % 7,
+ rows = Math.ceil( ( leadDays + this.daysInMonth() ) / 7 ),
+ printDate = new Date( this.year(), date.getMonth(), 1 - leadDays );
+ for ( var row = 0; row < rows; row++ ) {
+ var week = result[ result.length ] = {
+ number: Globalize.format( printDate, { pattern: "w" } ),
+ days: []
+ };
+ for ( var dayx = 0; dayx < 7; dayx++ ) {
+ var day = week.days[ week.days.length ] = {
+ lead: printDate.getMonth() != date.getMonth(),
+ date: printDate.getDate(),
+ month: printDate.getMonth(),
+ year: printDate.getFullYear(),
+ timestamp: printDate.getTime(),
+ today: today.equal( printDate )
+ };
+ day.render = day.selectable = !day.lead;
+ if ( this.eachDay ) {
+ this.eachDay( day );
+ }
+ // TODO use adjust("D", 1)?
+ printDate.setDate( printDate.getDate() + 1 );
+ }
+ }
+ return result;
+ },
+ // specialized for multi-month template, could be used in general
+ months: function( add ) {
+ var clone,
+ result = [ this ];
+
+ for ( var i = 0; i < add; i++ ) {
+ clone = this.clone();
+ clone.adjust( "M", i + 1 );
+ result.push( clone );
+ }
+ result[ 0 ].first = true;
+ result[ result.length - 1 ].last = true;
+ return result;
+ },
+ clone: function() {
+ var date = this.dateObject;
+ return new $.date( new Date( date.getFullYear(), date.getMonth(),
+ date.getDate(), date.getHours(),
+ date.getMinutes(), date.getSeconds()), this.globalFormat );
+ },
+ // TODO compare year, month, day each for better performance
+ equal: function( other ) {
+ function format( date ) {
+ return Globalize.format( date, { pattern: "yyyyMMdd" } );
+ }
+ return format( this.dateObject ) === format( other );
+ },
+ date: function() {
+ return this.dateObject;
+ },
+ format: function( format ) {
+ return Globalize.format( this.dateObject, format || this.globalFormat );
+ }
+};
+
+} ) );
diff --git a/external/globalize-old/LICENSE b/external/globalize-old/LICENSE
new file mode 100644
index 000000000..9c8b02240
--- /dev/null
+++ b/external/globalize-old/LICENSE
@@ -0,0 +1,21 @@
+Copyright Software Freedom Conservancy, Inc.
+http://jquery.org/license
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/external/globalize/globalize.culture.de-DE.js b/external/globalize-old/globalize.culture.de-DE.js
index 5466bd75e..5466bd75e 100644
--- a/external/globalize/globalize.culture.de-DE.js
+++ b/external/globalize-old/globalize.culture.de-DE.js
diff --git a/external/globalize/globalize.culture.ja-JP.js b/external/globalize-old/globalize.culture.ja-JP.js
index a9469d709..a9469d709 100644
--- a/external/globalize/globalize.culture.ja-JP.js
+++ b/external/globalize-old/globalize.culture.ja-JP.js
diff --git a/external/globalize-old/globalize.js b/external/globalize-old/globalize.js
new file mode 100644
index 000000000..a38a32625
--- /dev/null
+++ b/external/globalize-old/globalize.js
@@ -0,0 +1,1585 @@
+/*!
+ * Globalize
+ *
+ * http://github.com/jquery/globalize
+ *
+ * Copyright Software Freedom Conservancy, Inc.
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( window, undefined ) {
+
+var Globalize,
+ // private variables
+ regexHex,
+ regexInfinity,
+ regexParseFloat,
+ regexTrim,
+ // private JavaScript utility functions
+ arrayIndexOf,
+ endsWith,
+ extend,
+ isArray,
+ isFunction,
+ isObject,
+ startsWith,
+ trim,
+ truncate,
+ zeroPad,
+ // private Globalization utility functions
+ appendPreOrPostMatch,
+ expandFormat,
+ formatDate,
+ formatNumber,
+ getTokenRegExp,
+ getEra,
+ getEraYear,
+ parseExact,
+ parseNegativePattern;
+
+// Global variable (Globalize) or CommonJS module (globalize)
+Globalize = function( cultureSelector ) {
+ return new Globalize.prototype.init( cultureSelector );
+};
+
+if ( typeof require !== "undefined" &&
+ typeof exports !== "undefined" &&
+ typeof module !== "undefined" ) {
+ // Assume CommonJS
+ module.exports = Globalize;
+} else {
+ // Export as global variable
+ window.Globalize = Globalize;
+}
+
+Globalize.cultures = {};
+
+Globalize.prototype = {
+ constructor: Globalize,
+ init: function( cultureSelector ) {
+ this.cultures = Globalize.cultures;
+ this.cultureSelector = cultureSelector;
+
+ return this;
+ }
+};
+Globalize.prototype.init.prototype = Globalize.prototype;
+
+// 1. When defining a culture, all fields are required except the ones stated as optional.
+// 2. 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.
+// 3. 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".
+Globalize.cultures[ "default" ] = {
+ // A unique name for the culture in the form <language code>-<country/region code>
+ 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
+ "-": "-",
+ // symbol used for NaN (Not-A-Number)
+ "NaN": "NaN",
+ // symbol used for Negative Infinity
+ negativeInfinity: "-Infinity",
+ // symbol used for Positive Infinity
+ positiveInfinity: "Infinity",
+ 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.
+ */
+ }
+ },
+ // For localized strings
+ messages: {}
+};
+
+Globalize.cultures[ "default" ].calendar = Globalize.cultures[ "default" ].calendars.standard;
+
+Globalize.cultures.en = Globalize.cultures[ "default" ];
+
+Globalize.cultureSelector = "en";
+
+//
+// private variables
+//
+
+regexHex = /^0x[a-f0-9]+$/i;
+regexInfinity = /^[+\-]?infinity$/i;
+regexParseFloat = /^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/;
+regexTrim = /^\s+|\s+$/g;
+
+//
+// private JavaScript utility functions
+//
+
+arrayIndexOf = function( 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;
+};
+
+endsWith = function( value, pattern ) {
+ return value.substr( value.length - pattern.length ) === pattern;
+};
+
+extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !isFunction(target) ) {
+ target = {};
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( isObject(copy) || (copyIsArray = isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && isArray(src) ? src : [];
+
+ } else {
+ clone = src && isObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+isArray = Array.isArray || function( obj ) {
+ return Object.prototype.toString.call( obj ) === "[object Array]";
+};
+
+isFunction = function( obj ) {
+ return Object.prototype.toString.call( obj ) === "[object Function]";
+};
+
+isObject = function( obj ) {
+ return Object.prototype.toString.call( obj ) === "[object Object]";
+};
+
+startsWith = function( value, pattern ) {
+ return value.indexOf( pattern ) === 0;
+};
+
+trim = function( value ) {
+ return ( value + "" ).replace( regexTrim, "" );
+};
+
+truncate = function( value ) {
+ if ( isNaN( value ) ) {
+ return NaN;
+ }
+ return Math[ value < 0 ? "ceil" : "floor" ]( value );
+};
+
+zeroPad = function( str, count, left ) {
+ var l;
+ for ( l = str.length; l < count; l += 1 ) {
+ str = ( left ? ("0" + str) : (str + "0") );
+ }
+ return str;
+};
+
+//
+// private Globalization utility functions
+//
+
+appendPreOrPostMatch = function( 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;
+};
+
+expandFormat = function( 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;
+};
+
+formatDate = function( value, format, culture ) {
+ var cal = culture.calendar,
+ convert = cal.convert,
+ ret;
+
+ if ( !format || !format.length || format === "i" ) {
+ 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();
+ default:
+ throw "Invalid part value " + part;
+ }
+ }
+
+ 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
+ var 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 + "\'.";
+ }
+ }
+ return ret.join( "" );
+};
+
+// formatNumber
+(function() {
+ var expandNumber;
+
+ expandNumber = function( 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 ] : "";
+
+ 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, true );
+ 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;
+ };
+
+ formatNumber = function( value, format, culture ) {
+ if ( !isFinite(value) ) {
+ if ( value === Infinity ) {
+ return culture.numberFormat.positiveInfinity;
+ }
+ if ( value === -Infinity ) {
+ return culture.numberFormat.negativeInfinity;
+ }
+ return culture.numberFormat.NaN;
+ }
+ 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";
+ number = truncate( number );
+ if ( precision !== -1 ) {
+ number = zeroPad( "" + number, precision, true );
+ }
+ if ( value < 0 ) number = "-" + number;
+ break;
+ case "N":
+ formatInfo = nf;
+ /* falls through */
+ case "C":
+ formatInfo = formatInfo || nf.currency;
+ /* falls 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;
+ };
+
+}());
+
+getTokenRegExp = function() {
+ // 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);
+};
+
+getEra = function( 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;
+};
+
+getEraYear = function( 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;
+};
+
+// parseExact
+(function() {
+ var expandYear,
+ getDayIndex,
+ getMonthIndex,
+ getParseRegExp,
+ outOfRange,
+ toUpper,
+ toUpperArray;
+
+ expandYear = function( cal, year ) {
+ // expands 2-digit year into 4 digits.
+ if ( year < 100 ) {
+ var now = new Date(),
+ era = getEra( now ),
+ curr = getEraYear( now, cal, era ),
+ twoDigitYearMax = cal.twoDigitYearMax;
+ twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
+ year += curr - ( curr % 100 );
+ if ( year > twoDigitYearMax ) {
+ year -= 100;
+ }
+ }
+ return year;
+ };
+
+ getDayIndex = function ( 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;
+ };
+
+ getMonthIndex = function( 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;
+ };
+
+ getParseRegExp = function( 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 = "(\\/)";
+ break;
+ default:
+ throw "Invalid date format pattern \'" + m + "\'.";
+ }
+ 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;
+ };
+
+ outOfRange = function( value, low, high ) {
+ return value < low || value > high;
+ };
+
+ toUpper = function( value ) {
+ // "he-IL" has non-breaking space in weekday names.
+ return value.split( "\u00A0" ).join( " " ).toUpperCase();
+ };
+
+ toUpperArray = function( arr ) {
+ var results = [];
+ for ( var i = 0, l = arr.length; i < l; i++ ) {
+ results[ i ] = toUpper( arr[i] );
+ }
+ return results;
+ };
+
+ parseExact = function( 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;
+ };
+}());
+
+parseNegativePattern = function( value, nf, negativePattern ) {
+ var neg = nf[ "-" ],
+ pos = nf[ "+" ],
+ ret;
+ switch ( negativePattern ) {
+ case "n -":
+ neg = " " + neg;
+ pos = " " + pos;
+ /* falls 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 += " ";
+ /* falls 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 ];
+};
+
+//
+// public instance functions
+//
+
+Globalize.prototype.findClosestCulture = function( cultureSelector ) {
+ return Globalize.findClosestCulture.call( this, cultureSelector );
+};
+
+Globalize.prototype.format = function( value, format, cultureSelector ) {
+ return Globalize.format.call( this, value, format, cultureSelector );
+};
+
+Globalize.prototype.localize = function( key, cultureSelector ) {
+ return Globalize.localize.call( this, key, cultureSelector );
+};
+
+Globalize.prototype.parseInt = function( value, radix, cultureSelector ) {
+ return Globalize.parseInt.call( this, value, radix, cultureSelector );
+};
+
+Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) {
+ return Globalize.parseFloat.call( this, value, radix, cultureSelector );
+};
+
+Globalize.prototype.culture = function( cultureSelector ) {
+ return Globalize.culture.call( this, cultureSelector );
+};
+
+//
+// public singleton functions
+//
+
+Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) {
+
+ var base = {},
+ isNew = false;
+
+ if ( typeof cultureName !== "string" ) {
+ // cultureName argument is optional string. If not specified, assume info is first
+ // and only argument. Specified info deep-extends current culture.
+ info = cultureName;
+ cultureName = this.culture().name;
+ base = this.cultures[ cultureName ];
+ } else if ( typeof baseCultureName !== "string" ) {
+ // baseCultureName argument is optional string. If not specified, assume info is second
+ // argument. Specified info deep-extends specified culture.
+ // If specified culture does not exist, create by deep-extending default
+ info = baseCultureName;
+ isNew = ( this.cultures[ cultureName ] == null );
+ base = this.cultures[ cultureName ] || this.cultures[ "default" ];
+ } else {
+ // cultureName and baseCultureName specified. Assume a new culture is being created
+ // by deep-extending an specified base culture
+ isNew = true;
+ base = this.cultures[ baseCultureName ];
+ }
+
+ this.cultures[ cultureName ] = extend(true, {},
+ base,
+ info
+ );
+ // Make the standard calendar the current culture if it's a new culture
+ if ( isNew ) {
+ this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard;
+ }
+};
+
+Globalize.findClosestCulture = function( name ) {
+ var match;
+ if ( !name ) {
+ return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ];
+ }
+ if ( typeof name === "string" ) {
+ 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 );
+ pri = isNaN( pri ) ? 0 : pri;
+ }
+ else {
+ pri = 1;
+ }
+ }
+ prioritized.push({ lang: lang, pri: pri });
+ }
+ prioritized.sort(function( a, b ) {
+ if ( a.pri < b.pri ) {
+ return 1;
+ } else if ( a.pri > b.pri ) {
+ return -1;
+ }
+ return 0;
+ });
+ // exact match
+ for ( i = 0; i < l; i++ ) {
+ lang = prioritized[ i ].lang;
+ match = cultures[ lang ];
+ if ( match ) {
+ return match;
+ }
+ }
+
+ // neutral language match
+ for ( i = 0; i < l; i++ ) {
+ lang = prioritized[ i ].lang;
+ 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 );
+ }
+
+ // last resort: match first culture using that language
+ for ( i = 0; i < l; i++ ) {
+ lang = prioritized[ i ].lang;
+ for ( var cultureKey in cultures ) {
+ var culture = cultures[ cultureKey ];
+ if ( culture.language === lang ) {
+ return culture;
+ }
+ }
+ }
+ }
+ else if ( typeof name === "object" ) {
+ return name;
+ }
+ return match || null;
+};
+
+Globalize.format = function( value, format, cultureSelector ) {
+ var culture = this.findClosestCulture( cultureSelector );
+ if ( value instanceof Date ) {
+ value = formatDate( value, format, culture );
+ }
+ else if ( typeof value === "number" ) {
+ value = formatNumber( value, format, culture );
+ }
+ return value;
+};
+
+Globalize.localize = function( key, cultureSelector ) {
+ return this.findClosestCulture( cultureSelector ).messages[ key ] ||
+ this.cultures[ "default" ].messages[ key ];
+};
+
+Globalize.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;
+};
+
+Globalize.parseInt = function( value, radix, cultureSelector ) {
+ return truncate( Globalize.parseFloat(value, radix, cultureSelector) );
+};
+
+Globalize.parseFloat = function( value, radix, cultureSelector ) {
+ // radix argument is optional
+ if ( typeof radix !== "number" ) {
+ cultureSelector = radix;
+ radix = 10;
+ }
+
+ var culture = this.findClosestCulture( cultureSelector );
+ var ret = NaN,
+ nf = culture.numberFormat;
+
+ if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) {
+ // remove currency symbol
+ value = value.replace( culture.numberFormat.currency.symbol, "" );
+ // replace decimal seperator
+ value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] );
+ }
+
+ //Remove percentage character from number string before parsing
+ if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){
+ value = value.replace( culture.numberFormat.percent.symbol, "" );
+ }
+
+ // remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR
+ value = value.replace( / /g, "" );
+
+ // allow infinity or hexidecimal
+ if ( regexInfinity.test(value) ) {
+ ret = parseFloat( value );
+ }
+ else if ( !radix && regexHex.test(value) ) {
+ ret = parseInt( value, 16 );
+ }
+ else {
+
+ // determine sign and number
+ var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
+ sign = signInfo[ 0 ],
+ num = signInfo[ 1 ];
+
+ // #44 - try parsing as "(n)"
+ if ( sign === "" && nf.pattern[0] !== "(n)" ) {
+ signInfo = parseNegativePattern( value, nf, "(n)" );
+ sign = signInfo[ 0 ];
+ num = signInfo[ 1 ];
+ }
+
+ // try parsing as "-n"
+ 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;
+};
+
+Globalize.culture = function( cultureSelector ) {
+ // setter
+ if ( typeof cultureSelector !== "undefined" ) {
+ this.cultureSelector = cultureSelector;
+ }
+ // getter
+ return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ];
+};
+
+}( this )); \ No newline at end of file
diff --git a/external/globalize/globalize.js b/external/globalize/globalize.js
index a38a32625..1086d339d 100644
--- a/external/globalize/globalize.js
+++ b/external/globalize/globalize.js
@@ -1,1585 +1,1788 @@
/*!
- * Globalize
+ * Globalize v1.0.0pre
*
* http://github.com/jquery/globalize
*
- * Copyright Software Freedom Conservancy, Inc.
- * Dual licensed under the MIT or GPL Version 2 licenses.
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
* http://jquery.org/license
+ *
+ * Date: 2013-12-01T12:08Z
*/
-
-(function( window, undefined ) {
-
-var Globalize,
- // private variables
- regexHex,
- regexInfinity,
- regexParseFloat,
- regexTrim,
- // private JavaScript utility functions
- arrayIndexOf,
- endsWith,
- extend,
- isArray,
- isFunction,
- isObject,
- startsWith,
- trim,
- truncate,
- zeroPad,
- // private Globalization utility functions
- appendPreOrPostMatch,
- expandFormat,
- formatDate,
- formatNumber,
- getTokenRegExp,
- getEra,
- getEraYear,
- parseExact,
- parseNegativePattern;
-
-// Global variable (Globalize) or CommonJS module (globalize)
-Globalize = function( cultureSelector ) {
- return new Globalize.prototype.init( cultureSelector );
-};
-
-if ( typeof require !== "undefined" &&
- typeof exports !== "undefined" &&
- typeof module !== "undefined" ) {
- // Assume CommonJS
- module.exports = Globalize;
-} else {
- // Export as global variable
- window.Globalize = Globalize;
-}
-
-Globalize.cultures = {};
-
-Globalize.prototype = {
- constructor: Globalize,
- init: function( cultureSelector ) {
- this.cultures = Globalize.cultures;
- this.cultureSelector = cultureSelector;
-
- return this;
+(function( root, factory ) {
+
+ if ( typeof define === "function" && define.amd ) {
+ // AMD.
+ define( factory );
+ } else if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // Node. CommonJS.
+ module.exports = factory();
+ } else {
+ // Global
+ root.Globalize = factory();
}
-};
-Globalize.prototype.init.prototype = Globalize.prototype;
-
-// 1. When defining a culture, all fields are required except the ones stated as optional.
-// 2. 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.
-// 3. 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".
-Globalize.cultures[ "default" ] = {
- // A unique name for the culture in the form <language code>-<country/region code>
- 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
- "-": "-",
- // symbol used for NaN (Not-A-Number)
- "NaN": "NaN",
- // symbol used for Negative Infinity
- negativeInfinity: "-Infinity",
- // symbol used for Positive Infinity
- positiveInfinity: "Infinity",
- 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: "$"
+
+}( this, function() {
+
+/**
+ * CLDR JavaScript Library v0.2.4-pre
+ * http://jquery.com/
+ *
+ * Copyright 2013 Rafael Xavier de Souza
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-11-30T11:30Z
+ */
+/*!
+ * CLDR JavaScript Library v0.2.4-pre 2013-11-30T11:30Z MIT license © Rafael Xavier
+ * http://git.io/h4lmVg
+ */
+ var Cldr = (function() {
+
+
+
+ var alwaysArray = function( stringOrArray ) {
+ return typeof stringOrArray === "string" ? [ stringOrArray ] : stringOrArray;
+ };
+
+
+
+
+ var common = function( Cldr ) {
+
+ Cldr.prototype.main = function( path ) {
+ path = alwaysArray( path );
+ return this.get( [ "main/{languageId}" ].concat( path ) );
+ };
+
+ };
+
+
+
+
+ var arrayIsArray = Array.isArray || function( obj ) {
+ return Object.prototype.toString.call( obj ) === "[object Array]";
+ };
+
+
+
+
+ var pathNormalize = function( path, attributes ) {
+ if ( arrayIsArray( path ) ) {
+ path = path.join( "/" );
}
- },
- // 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.
- */
+ if ( typeof path !== "string" ) {
+ throw new Error( "invalid path \"" + path + "\"" );
}
- },
- // For localized strings
- messages: {}
-};
+ // 1: Ignore leading slash `/`
+ // 2: Ignore leading `cldr/`
+ path = path
+ .replace( /^\// , "" ) /* 1 */
+ .replace( /^cldr\// , "" ); /* 2 */
+
+ // Replace {attribute}'s
+ path = path.replace( /{[a-zA-Z]+}/g, function( name ) {
+ name = name.replace( /^{([^}]*)}$/, "$1" );
+ return attributes[ name ];
+ });
-Globalize.cultures[ "default" ].calendar = Globalize.cultures[ "default" ].calendars.standard;
+ return path.split( "/" );
+ };
-Globalize.cultures.en = Globalize.cultures[ "default" ];
-Globalize.cultureSelector = "en";
-//
-// private variables
-//
-regexHex = /^0x[a-f0-9]+$/i;
-regexInfinity = /^[+\-]?infinity$/i;
-regexParseFloat = /^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/;
-regexTrim = /^\s+|\s+$/g;
+ var arraySome = function( array, callback ) {
+ var i, length;
+ if ( array.some ) {
+ return array.some( callback );
+ }
+ for ( i = 0, length = array.length; i < length; i++ ) {
+ if ( callback( array[ i ], i, array ) ) {
+ return true;
+ }
+ }
+ return false;
+ };
-//
-// private JavaScript utility functions
-//
-arrayIndexOf = function( 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 the maximized language id as defined in
+ // http://www.unicode.org/reports/tr35/#Likely_Subtags
+ // 1. Canonicalize.
+ // 1.1 Make sure the input locale is in canonical form: uses the right separator, and has the right casing.
+ // TODO Right casing? What df? It seems languages are lowercase, scripts are Capitalized, territory is uppercase. I am leaving this as an exercise to the user.
+
+ // 1.2 Replace any deprecated subtags with their canonical values using the <alias> data in supplemental metadata. Use the first value in the replacement list, if it exists. Language tag replacements may have multiple parts, such as "sh" ➞ "sr_Latn" or mo" ➞ "ro_MD". In such a case, the original script and/or region are retained if there is one. Thus "sh_Arab_AQ" ➞ "sr_Arab_AQ", not "sr_Latn_AQ".
+ // TODO What <alias> data?
+
+ // 1.3 If the tag is grandfathered (see <variable id="$grandfathered" type="choice"> in the supplemental data), then return it.
+ // TODO grandfathered?
+
+ // 1.4 Remove the script code 'Zzzz' and the region code 'ZZ' if they occur.
+ // 1.5 Get the components of the cleaned-up source tag (languages, scripts, and regions), plus any variants and extensions.
+ // 2. Lookup. Lookup each of the following in order, and stop on the first match:
+ // 2.1 languages_scripts_regions
+ // 2.2 languages_regions
+ // 2.3 languages_scripts
+ // 2.4 languages
+ // 2.5 und_scripts
+ // 3. Return
+ // 3.1 If there is no match, either return an error value, or the match for "und" (in APIs where a valid language tag is required).
+ // 3.2 Otherwise there is a match = languagem_scriptm_regionm
+ // 3.3 Let xr = xs if xs is not empty, and xm otherwise.
+ // 3.4 Return the language tag composed of languager _ scriptr _ regionr + variants + extensions .
+
+ //
+ // @subtags [Array] normalized language id subtags tuple (see init.js).
+ var likelySubtags = function( cldr, subtags, options ) {
+ var match, matchFound,
+ language = subtags[ 0 ],
+ script = subtags[ 1 ],
+ territory = subtags[ 2 ];
+ options = options || {};
+
+ // Skip if (language, script, territory) is not empty [3.3]
+ if ( language !== "und" && script !== "Zzzz" && territory !== "ZZ" ) {
+ return [ language, script, territory ];
+ }
+
+ // Skip if no supplemental likelySubtags data is present
+ if ( typeof cldr.get( "supplemental/likelySubtags" ) === "undefined" ) {
+ return;
+ }
+
+ // [2]
+ matchFound = arraySome([
+ [ language, script, territory ],
+ [ language, territory ],
+ [ language, script ],
+ [ language ],
+ [ "und", script ]
+ ], function( test ) {
+ return match = !(/\b(Zzzz|ZZ)\b/).test( test.join( "_" ) ) /* [1.4] */ && cldr.get( [ "supplemental/likelySubtags", test.join( "_" ) ] );
+ });
+
+ // [3]
+ if ( matchFound ) {
+ // [3.2 .. 3.4]
+ match = match.split( "_" );
+ return [
+ language !== "und" ? language : match[ 0 ],
+ script !== "Zzzz" ? script : match[ 1 ],
+ territory !== "ZZ" ? territory : match[ 2 ]
+ ];
+ } else if ( options.force ) {
+ // [3.1.2]
+ return cldr.get( "supplemental/likelySubtags/und" ).split( "_" );
+ } else {
+ // [3.1.1]
+ return;
}
- }
- return -1;
-};
-
-endsWith = function( value, pattern ) {
- return value.substr( value.length - pattern.length ) === pattern;
-};
-
-extend = function() {
- var options, name, src, copy, copyIsArray, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
-
- // Handle a deep copy situation
- if ( typeof target === "boolean" ) {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
+ };
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !isFunction(target) ) {
- target = {};
- }
- for ( ; i < length; i++ ) {
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
- // Extend the base object
- for ( name in options ) {
- src = target[ name ];
- copy = options[ name ];
-
- // Prevent never-ending loop
- if ( target === copy ) {
- continue;
- }
- // Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( isObject(copy) || (copyIsArray = isArray(copy)) ) ) {
- if ( copyIsArray ) {
- copyIsArray = false;
- clone = src && isArray(src) ? src : [];
+ // Given a locale, remove any fields that Add Likely Subtags would add.
+ // http://www.unicode.org/reports/tr35/#Likely_Subtags
+ // 1. First get max = AddLikelySubtags(inputLocale). If an error is signaled, return it.
+ // 2. Remove the variants from max.
+ // 3. Then for trial in {language, language _ region, language _ script}. If AddLikelySubtags(trial) = max, then return trial + variants.
+ // 4. If you do not get a match, return max + variants.
+ //
+ // @maxLanguageId [Array] maxLanguageId tuple (see init.js).
+ var removeLikelySubtags = function( cldr, maxLanguageId ) {
+ var match, matchFound,
+ language = maxLanguageId[ 0 ],
+ script = maxLanguageId[ 1 ],
+ territory = maxLanguageId[ 2 ];
+
+ // [3]
+ matchFound = arraySome([
+ [ [ language, "Zzzz", "ZZ" ], [ language ] ],
+ [ [ language, "Zzzz", territory ], [ language, territory ] ],
+ [ [ language, script, "ZZ" ], [ language, script ] ]
+ ], function( test ) {
+ var result = likelySubtags( cldr, test[ 0 ] );
+ match = test[ 1 ];
+ return result && result[ 0 ] === maxLanguageId[ 0 ] &&
+ result[ 1 ] === maxLanguageId[ 1 ] &&
+ result[ 2 ] === maxLanguageId[ 2 ];
+ });
- } else {
- clone = src && isObject(src) ? src : {};
- }
+ // [4]
+ return matchFound ? match : maxLanguageId;
+ };
- // Never move original objects, clone them
- target[ name ] = extend( deep, clone, copy );
- // Don't bring in undefined values
- } else if ( copy !== undefined ) {
- target[ name ] = copy;
- }
- }
+
+
+ var supplemental = function( cldr ) {
+
+ var prepend, supplemental;
+
+ prepend = function( prepend ) {
+ return function( path ) {
+ path = alwaysArray( path );
+ return cldr.get( [ prepend ].concat( path ) );
+ };
+ };
+
+ supplemental = prepend( "supplemental" );
+
+ // Week Data
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#Week_Data
+ supplemental.weekData = prepend( "supplemental/weekData" );
+
+ supplemental.weekData.firstDay = function() {
+ return cldr.get( "supplemental/weekData/firstDay/{territory}" ) ||
+ cldr.get( "supplemental/weekData/firstDay/001" );
+ };
+
+ supplemental.weekData.minDays = function() {
+ var minDays = cldr.get( "supplemental/weekData/minDays/{territory}" ) ||
+ cldr.get( "supplemental/weekData/minDays/001" );
+ return parseInt( minDays, 10 );
+ };
+
+ // Time Data
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
+ supplemental.timeData = prepend( "supplemental/timeData" );
+
+ supplemental.timeData.allowed = function() {
+ return cldr.get( "supplemental/timeData/{territory}/_allowed" ) ||
+ cldr.get( "supplemental/timeData/001/_allowed" );
+ };
+
+ supplemental.timeData.preferred = function() {
+ return cldr.get( "supplemental/timeData/{territory}/_preferred" ) ||
+ cldr.get( "supplemental/timeData/001/_preferred" );
+ };
+
+ return supplemental;
+
+ };
+
+
+
+
+ var init = function( locale ) {
+ var language, languageId, maxLanguageId, script, territory, unicodeLanguageId, variant;
+
+ if ( typeof locale !== "string" ) {
+ throw new Error( "invalid locale type: \"" + JSON.stringify( locale ) + "\"" );
}
- }
- // Return the modified object
- return target;
-};
+ // Normalize locale code.
+ // Get (or deduce) the "triple subtags": language, territory (also aliased as region), and script subtags.
+ // Get the variant subtags (calendar, collation, currency, etc).
+ // refs:
+ // - http://www.unicode.org/reports/tr35/#Field_Definitions
+ // - http://www.unicode.org/reports/tr35/#Language_and_Locale_IDs
+ // - http://www.unicode.org/reports/tr35/#Unicode_locale_identifier
-isArray = Array.isArray || function( obj ) {
- return Object.prototype.toString.call( obj ) === "[object Array]";
-};
+ locale = locale.replace( /-/, "_" );
-isFunction = function( obj ) {
- return Object.prototype.toString.call( obj ) === "[object Function]";
-};
+ // TODO normalize unicode locale extensions. Currently, skipped.
+ // unicodeLocaleExtensions = locale.split( "_u_" )[ 1 ];
+ locale = locale.split( "_u_" )[ 0 ];
-isObject = function( obj ) {
- return Object.prototype.toString.call( obj ) === "[object Object]";
-};
+ // TODO normalize transformed extensions. Currently, skipped.
+ // transformedExtensions = locale.split( "_t_" )[ 1 ];
+ locale = locale.split( "_t_" )[ 0 ];
-startsWith = function( value, pattern ) {
- return value.indexOf( pattern ) === 0;
-};
+ unicodeLanguageId = locale;
-trim = function( value ) {
- return ( value + "" ).replace( regexTrim, "" );
-};
+ // unicodeLanguageId = ...
+ switch ( true ) {
-truncate = function( value ) {
- if ( isNaN( value ) ) {
- return NaN;
- }
- return Math[ value < 0 ? "ceil" : "floor" ]( value );
-};
+ // language_script_territory..
+ case /^[a-z]{2}_[A-Z][a-z]{3}_[A-Z0-9]{2}(\b|_)/.test( unicodeLanguageId ):
+ language = unicodeLanguageId.split( "_" )[ 0 ];
+ script = unicodeLanguageId.split( "_" )[ 1 ];
+ territory = unicodeLanguageId.split( "_" )[ 2 ];
+ variant = unicodeLanguageId.split( "_" )[ 3 ];
+ break;
-zeroPad = function( str, count, left ) {
- var l;
- for ( l = str.length; l < count; l += 1 ) {
- str = ( left ? ("0" + str) : (str + "0") );
- }
- return str;
-};
-
-//
-// private Globalization utility functions
-//
-
-appendPreOrPostMatch = function( 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;
+ // language_script..
+ case /^[a-z]{2}_[A-Z][a-z]{3}(\b|_)/.test( unicodeLanguageId ):
+ language = unicodeLanguageId.split( "_" )[ 0 ];
+ script = unicodeLanguageId.split( "_" )[ 1 ];
+ territory = "ZZ";
+ variant = unicodeLanguageId.split( "_" )[ 2 ];
break;
- case "\\":
- if ( escaped ) {
- strings.push( "\\" );
- }
- escaped = !escaped;
+
+ // language_territory..
+ case /^[a-z]{2}_[A-Z0-9]{2}(\b|_)/.test( unicodeLanguageId ):
+ language = unicodeLanguageId.split( "_" )[ 0 ];
+ script = "Zzzz";
+ territory = unicodeLanguageId.split( "_" )[ 1 ];
+ variant = unicodeLanguageId.split( "_" )[ 2 ];
break;
+
+ // language.., or root
+ case /^([a-z]{2}|root)(\b|_)/.test( unicodeLanguageId ):
+ language = unicodeLanguageId.split( "_" )[ 0 ];
+ script = "Zzzz";
+ territory = "ZZ";
+ variant = unicodeLanguageId.split( "_" )[ 1 ];
+ break;
+
default:
- strings.push( c );
- escaped = false;
+ language = "und";
break;
}
- }
- return quoteCount;
-};
-
-expandFormat = function( 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;
-};
-
-formatDate = function( value, format, culture ) {
- var cal = culture.calendar,
- convert = cal.convert,
- ret;
-
- if ( !format || !format.length || format === "i" ) {
- 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();
+
+ // When a locale id does not specify a language, or territory (region), or script, they are obtained by Likely Subtags.
+ maxLanguageId = likelySubtags( this, [ language, script, territory ], { force: true } ) || unicodeLanguageId.split( "_" );
+ language = maxLanguageId[ 0 ];
+ script = maxLanguageId[ 1 ];
+ territory = maxLanguageId[ 2 ];
+
+ // TODO json content distributed on zip file use languageId with `-` on main.<lang>. Why `-` vs. `_` ?
+ languageId = removeLikelySubtags( this, maxLanguageId ).join( "_" );
+
+ // Set attributes
+ this.attributes = {
+
+ // Unicode Language Id
+ languageId: languageId,
+ maxLanguageId: maxLanguageId.join( "_" ),
+
+ // Unicode Language Id Subtabs
+ language: language,
+ script: script,
+ territory: territory,
+ region: territory, /* alias */
+ variant: variant
+ };
+
+ this.locale = variant ? [ languageId, variant ].join( "_" ) : languageId;
+
+ // Inlcude supplemental helper
+ this.supplemental = supplemental( this );
+ };
+
+
+
+
+ // @path: normalized path
+ var resourceGet = function( data, path ) {
+ var i,
+ node = data,
+ length = path.length;
+
+ for ( i = 0; i < length - 1; i++ ) {
+ node = node[ path[ i ] ];
+ if ( !node ) {
+ return undefined;
}
}
- else {
- ret = value.toString();
+ return node[ path[ i ] ];
+ };
+
+
+
+
+ var bundleParentLookup = function( Cldr, locale ) {
+ var parent;
+
+ if ( locale === "root" ) {
+ return;
}
- 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 );
+ // First, try to find parent on supplemental data.
+ parent = resourceGet( Cldr._resolved, pathNormalize( [ "supplemental/parentLocales/parentLocale", locale ] ) );
+ if ( parent ) {
+ return parent;
}
- else {
- r = s;
+
+ // Or truncate locale.
+ parent = locale.substr( 0, locale.lastIndexOf( "_" ) );
+ if ( !parent ) {
+ return "root";
}
- return r;
- }
- function hasDay() {
- if ( foundDay || checkedDay ) {
- return foundDay;
+ return parent;
+ };
+
+
+
+
+ // @path: normalized path
+ var resourceSet = function( data, path, value ) {
+ var i,
+ node = data,
+ length = path.length;
+
+ for ( i = 0; i < length - 1; i++ ) {
+ if ( !node[ path[ i ] ] ) {
+ node[ path[ i ] ] = {};
+ }
+ node = node[ path[ i ] ];
}
- foundDay = dayPartRegExp.test( format );
- checkedDay = true;
- return foundDay;
- }
+ node[ path[ i ] ] = value;
+ };
+
- function getPart( date, part ) {
- if ( converted ) {
- return converted[ part ];
+
+
+ var arrayForEach = function( array, callback ) {
+ var i, length;
+ if ( array.forEach ) {
+ return array.forEach( callback );
}
- switch ( part ) {
- case 0:
- return date.getFullYear();
- case 1:
- return date.getMonth();
- case 2:
- return date.getDate();
- default:
- throw "Invalid part value " + part;
+ for ( i = 0, length = array.length; i < length; i++ ) {
+ callback( array[ i ], i, array );
}
- }
+ };
- 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 );
+ var jsonMerge = (function() {
- // 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 );
+ // Returns new deeply merged JSON.
+ //
+ // Eg.
+ // merge( { a: { b: 1, c: 2 } }, { a: { b: 3, d: 4 } } )
+ // -> { a: { b: 3, c: 2, d: 4 } }
+ //
+ // @arguments JSON's
+ //
+ var merge = function() {
+ var destination = {},
+ sources = [].slice.call( arguments, 0 );
+ arrayForEach( sources, function( source ) {
+ var prop;
+ for ( prop in source ) {
+ if ( prop in destination && arrayIsArray( destination[ prop ] ) ) {
- if ( !ar ) {
- break;
- }
+ // Concat Arrays
+ destination[ prop ] = destination[ prop ].concat( source[ prop ] );
- // do not replace any matches that occur inside a string literal.
- if ( quoteCount % 2 ) {
- ret.push( ar[0] );
- continue;
- }
+ } else if ( prop in destination && typeof destination[ prop ] === "object" ) {
- var current = ar[ 0 ],
- clength = current.length;
+ // Merge Objects
+ destination[ prop ] = merge( destination[ prop ], source[ prop ] );
+
+ } else {
+
+ // Set new values
+ destination[ prop ] = source[ prop ];
- switch ( current ) {
- case "ddd":
- //Day of the week, as a three-letter abbreviation
- case "dddd":
- // Day of the week, using the full name
- var 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 + "\'.";
- }
- }
- return ret.join( "" );
-};
-
-// formatNumber
-(function() {
- var expandNumber;
-
- expandNumber = function( 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 ] : "";
-
- 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, true );
- right = numberString.slice( -exponent, numberString.length ) + right;
- numberString = numberString.slice( 0, -exponent );
+ }
+ });
+ return destination;
+ };
+
+ return merge;
+
+}());
+ var itemLookup = (function() {
+
+ var lookup;
+
+ lookup = function( Cldr, locale, path, attributes, childLocale ) {
+ var normalizedPath, parent, value;
+
+ // 1: Finish recursion
+ // 2: Avoid infinite loop
+ if ( typeof locale === "undefined" /* 1 */ || locale === childLocale /* 2 */ ) {
+ return;
}
- if ( precision > 0 ) {
- right = formatInfo[ "." ] +
- ( (right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision) );
+ // Resolve path
+ normalizedPath = pathNormalize( path, attributes );
+
+ // Check resolved (cached) data first
+ value = resourceGet( Cldr._resolved, normalizedPath );
+ if ( value ) {
+ return value;
}
- else {
- right = "";
+
+ // Check raw data
+ value = resourceGet( Cldr._raw, normalizedPath );
+
+ if ( !value ) {
+ // Or, lookup at parent locale
+ parent = bundleParentLookup( Cldr, locale );
+ value = lookup( Cldr, parent, path, jsonMerge( attributes, { languageId: parent }), locale );
}
- var stringIndex = numberString.length - 1,
- sep = formatInfo[ "," ],
- ret = "";
+ // Set resolved (cached)
+ resourceSet( Cldr._resolved, normalizedPath, value );
- 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) : "" );
+ return value;
+ };
- stringIndex -= curSize;
+ return lookup;
- if ( curGroupIndex < groupSizes.length ) {
- curSize = groupSizes[ curGroupIndex ];
- curGroupIndex++;
- }
+}());
+
+
+ var itemGetResolved = function( Cldr, path, attributes ) {
+ // Resolve path
+ var normalizedPath = pathNormalize( path, attributes );
+
+ return resourceGet( Cldr._resolved, normalizedPath );
+ };
+
+
+
+
+ var Cldr = function() {
+ init.apply( this, arguments );
+ };
+
+ Cldr._resolved = {};
+ Cldr._raw = {};
+
+ // Load resolved or unresolved cldr data
+ // @json [JSON]
+ Cldr.load = function( json ) {
+ if ( typeof json !== "object" ) {
+ throw new Error( "invalid json" );
}
+ Cldr._raw = jsonMerge( Cldr._raw, json );
+ };
- return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right;
+ Cldr.prototype.get = function( path ) {
+ // Simplify locale using languageId (there are no other resource bundles)
+ // 1: during init(), get is called, but languageId is not defined. Use "" as a workaround in this very specific scenario.
+ var locale = this.attributes && this.attributes.languageId || "" /* 1 */;
+
+ return itemGetResolved( Cldr, path, this.attributes ) ||
+ itemLookup( Cldr, locale, path, this.attributes );
};
- formatNumber = function( value, format, culture ) {
- if ( !isFinite(value) ) {
- if ( value === Infinity ) {
- return culture.numberFormat.positiveInfinity;
- }
- if ( value === -Infinity ) {
- return culture.numberFormat.negativeInfinity;
- }
- return culture.numberFormat.NaN;
+ common( Cldr );
+
+ return Cldr;
+
+
+
+}());
+
+
+ var arrayMap = function( array, callback ) {
+ var clone, i, length;
+ if ( array.map ) {
+ return array.map( callback );
}
- if ( !format || format === "i" ) {
- return culture.name.length ? value.toLocaleString() : value.toString();
+ for ( clone = [], i = 0, length = array.length; i < length; i++ ) {
+ clone[ i ] = callback( array[ i ], i, array );
}
- 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";
- number = truncate( number );
- if ( precision !== -1 ) {
- number = zeroPad( "" + number, precision, true );
- }
- if ( value < 0 ) number = "-" + number;
- break;
- case "N":
- formatInfo = nf;
- /* falls through */
- case "C":
- formatInfo = formatInfo || nf.currency;
- /* falls 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;
+ return clone;
+ };
+
+
+
+
+ var objectValues = function( object ) {
+ var i,
+ result = [];
+
+ for ( i in object ) {
+ result.push( object[ i ] );
}
- var patternParts = /n|\$|-|%/g,
- ret = "";
- for ( ; ; ) {
- var index = patternParts.lastIndex,
- ar = patternParts.exec( pattern );
+ return result;
+ };
- ret += pattern.slice( index, ar ? ar.index : pattern.length );
- if ( !ar ) {
- break;
+
+
+ /**
+ * allPreset()
+ *
+ * @cldr [Cldr instance].
+ *
+ * Return an Array with all (skeleton, date, time, datetime) presets.
+ */
+ var datetimeAllPresets = function( cldr ) {
+ var result = [];
+
+ // Skeleton
+ result = objectValues( cldr.main( "dates/calendars/gregorian/dateTimeFormats/availableFormats" ) );
+
+ // Time
+ result = result.concat( objectValues( cldr.main( "dates/calendars/gregorian/timeFormats" ) ) );
+
+ // Date
+ result = result.concat( objectValues( cldr.main( "dates/calendars/gregorian/dateFormats" ) ) );
+
+ // Datetime
+ result = result.concat( arrayMap( objectValues( cldr.main( "dates/calendars/gregorian/dateTimeFormats" ) ), function( datetimeFormat, key ) {
+ if ( typeof datetimeFormat !== "string" ) {
+ return datetimeFormat;
}
+ return datetimeFormat
+ .replace( /\{0\}/, cldr.main([
+ "dates/calendars/gregorian/timeFormats",
+ key
+ ]))
+ .replace( /\{1\}/, cldr.main([
+ "dates/calendars/gregorian/dateFormats",
+ key
+ ]));
+ }));
+
+ return arrayMap( result, function( pattern ) {
+ return { pattern: pattern };
+ });
+ };
+
+
- switch ( ar[0] ) {
- case "n":
- ret += number;
+
+ /**
+ * expandPattern( pattern, cldr )
+ *
+ * @pattern [String or Object] if String, it's considered a skeleton. Object accepts:
+ * - skeleton: [String] lookup availableFormat;
+ * - date: [String] ( "full" | "long" | "medium" | "short" );
+ * - time: [String] ( "full" | "long" | "medium" | "short" );
+ * - datetime: [String] ( "full" | "long" | "medium" | "short" );
+ * - pattern: [String] For more info see datetime/format.js.
+ *
+ * @cldr [Cldr instance].
+ *
+ * Return the corresponding pattern.
+ * Eg for "en":
+ * - "GyMMMd" returns "MMM d, y G";
+ * - { skeleton: "GyMMMd" } returns "MMM d, y G";
+ * - { date: "full" } returns "EEEE, MMMM d, y";
+ * - { time: "full" } returns "h:mm:ss a zzzz";
+ * - { datetime: "full" } returns "EEEE, MMMM d, y 'at' h:mm:ss a zzzz";
+ * - { pattern: "dd/mm" } returns "dd/mm";
+ */
+ var datetimeExpandPattern = function( pattern, cldr ) {
+ var result;
+
+ if ( typeof pattern === "string" ) {
+ pattern = { skeleton: pattern };
+ }
+
+ if ( typeof pattern === "object" ) {
+
+ switch ( true ) {
+ case "skeleton" in pattern:
+ result = cldr.main([
+ "dates/calendars/gregorian/dateTimeFormats/availableFormats",
+ pattern.skeleton
+ ]);
break;
- case "$":
- ret += nf.currency.symbol;
+
+ case "date" in pattern:
+ case "time" in pattern:
+ result = cldr.main([
+ "dates/calendars/gregorian",
+ "date" in pattern ? "dateFormats" : "timeFormats",
+ ( pattern.date || pattern.time )
+ ]);
break;
- case "-":
- // don't make 0 negative
- if ( /[1-9]/.test(number) ) {
- ret += nf[ "-" ];
+
+ case "datetime" in pattern:
+ result = cldr.main([
+ "dates/calendars/gregorian/dateTimeFormats",
+ pattern.datetime
+ ]);
+ if ( result ) {
+ result = result
+ .replace( /\{0\}/, cldr.main([
+ "dates/calendars/gregorian/timeFormats",
+ pattern.datetime
+ ]))
+ .replace( /\{1\}/, cldr.main([
+ "dates/calendars/gregorian/dateFormats",
+ pattern.datetime
+ ]));
}
break;
- case "%":
- ret += nf.percent.symbol;
+
+ case "pattern" in pattern:
+ result = pattern.pattern;
break;
+
+ default:
+ throw new Error( "Invalid pattern" );
}
+
+ } else {
+ throw new Error( "Invalid pattern" );
+ }
+
+ if ( !result ) {
+ throw new Error( "Pattern not found" );
}
- return ret;
+ return result;
};
-}());
-getTokenRegExp = function() {
- // 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);
-};
-
-getEra = function( 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;
+
+ var datetimeWeekDays = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ];
+
+
+
+ var arrayIndexOf = function( array, item ) {
+ if ( array.indexOf ) {
+ return array.indexOf( item );
}
- }
- return 0;
-};
-
-getEraYear = function( 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;
-};
-
-// parseExact
-(function() {
- var expandYear,
- getDayIndex,
- getMonthIndex,
- getParseRegExp,
- outOfRange,
- toUpper,
- toUpperArray;
-
- expandYear = function( cal, year ) {
- // expands 2-digit year into 4 digits.
- if ( year < 100 ) {
- var now = new Date(),
- era = getEra( now ),
- curr = getEraYear( now, cal, era ),
- twoDigitYearMax = cal.twoDigitYearMax;
- twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
- year += curr - ( curr % 100 );
- if ( year > twoDigitYearMax ) {
- year -= 100;
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[i] === item ) {
+ return i;
}
}
- return year;
+ return -1;
};
- getDayIndex = function ( 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;
+
+
+
+ /**
+ * firstDayOfWeek
+ */
+ var datetimeFirstDayOfWeek = function( cldr ) {
+ return arrayIndexOf( datetimeWeekDays, cldr.supplemental.weekData.firstDay() );
};
- getMonthIndex = function( 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 );
+
+
+
+ /**
+ * dayOfWeek
+ *
+ * Return the day of the week normalized by the territory's firstDay [0-6].
+ * Eg for "mon":
+ * - return 0 if territory is GB, or BR, or DE, or FR (week starts on "mon");
+ * - return 1 if territory is US (week starts on "sun");
+ * - return 2 if territory is EG (week starts on "sat");
+ */
+ var datetimeDayOfWeek = function( date, cldr ) {
+ return ( date.getDay() - datetimeFirstDayOfWeek( cldr ) + 7 ) % 7;
+ };
+
+
+
+
+ /**
+ * distanceInDays( from, to )
+ *
+ * Return the distance in days between from and to Dates.
+ */
+ var datetimeDistanceInDays = function( from, to ) {
+ var inDays = 864e5;
+ return ( to.getTime() - from.getTime() ) / inDays;
+ };
+
+
+
+
+ /**
+ * startOf
+ *
+ * Return the
+ */
+ var datetimeStartOf = function( date, unit ) {
+ date = new Date( date.getTime() );
+ switch( unit ) {
+ case "year":
+ date.setMonth( 0 );
+ /* falls through */
+ case "month":
+ date.setDate( 1 );
+ /* falls through */
+ case "day":
+ date.setHours( 0 );
+ /* falls through */
+ case "hour":
+ date.setMinutes( 0 );
+ /* falls through */
+ case "minute":
+ date.setSeconds( 0 );
+ /* falls through */
+ case "second":
+ date.setMilliseconds( 0 );
}
- return i;
+ return date;
};
- getParseRegExp = function( 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 = {};
+
+
+
+ /**
+ * dayOfYear
+ *
+ * Return the distance in days of the date to the begin of the year [0-d].
+ */
+ var datetimeDayOfYear = function( date ) {
+ return Math.floor( datetimeDistanceInDays( datetimeStartOf( date, "year" ), date ) );
+ };
+
+
+
+
+ /**
+ * millisecondsInDay
+ */
+ var datetimeMillisecondsInDay = function( date ) {
+ // TODO Handle daylight savings discontinuities
+ return date - datetimeStartOf( date, "day" );
+ };
+
+
+
+ var datetimePatternRe = (/([a-z])\1*|'[^']+'|''|./ig);
+
+
+
+ var stringPad = function( str, count, right ) {
+ var length;
+ if ( typeof str !== "string" ) {
+ str = String( str );
}
- else {
- var reFormat = re[ format ];
- if ( reFormat ) {
- return reFormat;
- }
+ for ( length = str.length; length < count; length += 1 ) {
+ str = ( right ? ( str + "0" ) : ( "0" + str ) );
}
+ return str;
+ };
+
+
- // 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;
+
+ /**
+ * format( date, pattern, cldr )
+ *
+ * @date [Date instance].
+ *
+ * @pattern [String] raw pattern.
+ * ref: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
+ *
+ * @cldr [Cldr instance].
+ *
+ * TODO Support other calendar types.
+ *
+ * Disclosure: this function borrows excerpts of dojo/date/locale.
+ */
+ var datetimeFormat = function( date, pattern, cldr ) {
+ var widths = [ "abbreviated", "wide", "narrow" ];
+ return pattern.replace( datetimePatternRe, function( current ) {
+ var pad, ret,
+ chr = current.charAt( 0 ),
+ length = current.length;
+
+ if ( chr === "j" ) {
+ // Locale preferred hHKk.
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
+ chr = cldr.supplemental.timeData.preferred();
}
- // 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+)";
+ switch ( chr ) {
+
+ // Era
+ case "G":
+ ret = cldr.main([
+ "dates/calendars/gregorian/eras",
+ length <= 3 ? "eraAbbr" : ( length === 4 ? "eraNames" : "eraNarrow" ),
+ date.getFullYear() < 0 ? 0 : 1
+ ]);
+ break;
+
+ // Year
+ case "y":
+ // Plain year.
+ // The length specifies the padding, but for two letters it also specifies the maximum length.
+ ret = String( date.getFullYear() );
+ pad = true;
+ if ( length === 2 ) {
+ ret = ret.substr( ret.length - 2 );
+ }
+ break;
+
+ case "Y":
+ // Year in "Week of Year"
+ // The length specifies the padding, but for two letters it also specifies the maximum length.
+ // yearInWeekofYear = date + DaysInAWeek - (dayOfWeek - firstDay) - minDays
+ ret = new Date( date.getTime() );
+ ret.setDate( ret.getDate() + 7 - ( datetimeDayOfWeek( date, cldr ) - datetimeFirstDayOfWeek( cldr ) ) - cldr.supplemental.weekData.minDays() );
+ ret = String( ret.getFullYear() );
+ pad = true;
+ if ( length === 2 ) {
+ ret = ret.substr( ret.length - 2 );
+ }
+ break;
+
+ case "u": // Extended year. Need to be implemented.
+ case "U": // Cyclic year name. Need to be implemented.
+ throw new Error( "Not implemented" );
+
+ // Quarter
+ case "Q":
+ case "q":
+ ret = Math.ceil( ( date.getMonth() + 1 ) / 3 );
+ if ( length <= 2 ) {
+ pad = true;
+ } else {
+ // http://unicode.org/cldr/trac/ticket/6788
+ ret = cldr.main([
+ "dates/calendars/gregorian/quarters",
+ chr === "Q" ? "format" : "stand-alone",
+ widths[ length - 3 ],
+ ret
+ ]);
+ }
+ break;
+
+ // Month
+ case "M":
+ case "L":
+ ret = date.getMonth() + 1;
+ if ( length <= 2 ) {
+ pad = true;
+ } else {
+ ret = cldr.main([
+ "dates/calendars/gregorian/months",
+ chr === "M" ? "format" : "stand-alone",
+ widths[ length - 3 ],
+ ret
+ ]);
+ }
+ break;
+
+ // Week
+ case "w":
+ // Week of Year.
+ // woy = ceil( ( doy + dow of 1/1 ) / 7 ) - minDaysStuff ? 1 : 0.
+ // TODO should pad on ww? Not documented, but I guess so.
+ ret = datetimeDayOfWeek( datetimeStartOf( date, "year" ), cldr );
+ ret = Math.ceil( ( datetimeDayOfYear( date ) + ret ) / 7 ) - ( 7 - ret >= cldr.supplemental.weekData.minDays() ? 0 : 1 );
+ pad = true;
+ break;
+
+ case "W":
+ // Week of Month.
+ // wom = ceil( ( dom + dow of `1/month` ) / 7 ) - minDaysStuff ? 1 : 0.
+ ret = datetimeDayOfWeek( datetimeStartOf( date, "month" ), cldr );
+ ret = Math.ceil( ( date.getDate() + ret ) / 7 ) - ( 7 - ret >= cldr.supplemental.weekData.minDays() ? 0 : 1 );
+ break;
+
+ // Day
+ case "d":
+ ret = date.getDate();
+ pad = true;
+ break;
+
+ case "D":
+ ret = datetimeDayOfYear( date ) + 1;
+ pad = true;
+ break;
+
+ case "F":
+ // Day of Week in month. eg. 2nd Wed in July.
+ ret = Math.floor( date.getDate() / 7 ) + 1;
+ break;
+
+ case "g+":
+ // Modified Julian day. Need to be implemented.
+ throw new Error( "Not implemented" );
+
+ // Week day
+ case "e":
+ case "c":
+ if ( length <= 2 ) {
+ // Range is [1-7] (deduced by example provided on documentation)
+ // TODO Should pad with zeros (not specified in the docs)?
+ ret = datetimeDayOfWeek( date, cldr ) + 1;
+ pad = true;
+ break;
+ }
+
+ /* falls through */
+ case "E":
+ ret = datetimeWeekDays[ date.getDay() ];
+ if ( length === 6 ) {
+ // If short day names are not explicitly specified, abbreviated day names are used instead.
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#months_days_quarters_eras
+ // http://unicode.org/cldr/trac/ticket/6790
+ ret = cldr.main([
+ "dates/calendars/gregorian/days",
+ [ chr === "c" ? "stand-alone" : "format" ],
+ "short",
+ ret
+ ]) || cldr.main([
+ "dates/calendars/gregorian/days",
+ [ chr === "c" ? "stand-alone" : "format" ],
+ "abbreviated",
+ ret
+ ]);
+ } else {
+ ret = cldr.main([
+ "dates/calendars/gregorian/days",
+ [ chr === "c" ? "stand-alone" : "format" ],
+ widths[ length < 3 ? 0 : length - 3 ],
+ ret
+ ]);
+ }
+ break;
+
+ // Period (AM or PM)
+ case "a":
+ ret = cldr.main([
+ "dates/calendars/gregorian/dayPeriods/format/wide",
+ date.getHours() < 12 ? "am" : "pm"
+ ]);
break;
- case "tt": case "t":
- add = "(\\D*)";
+
+ // Hour
+ case "h": // 1-12
+ ret = ( date.getHours() % 12 ) || 12;
+ pad = true;
break;
- case "yyyy":
- case "fff":
- case "ff":
- case "f":
- add = "(\\d{" + len + "})";
+
+ case "H": // 0-23
+ ret = date.getHours();
+ pad = true;
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?)";
+
+ case "K": // 0-11
+ ret = date.getHours() % 12;
+ pad = true;
+ break;
+
+ case "k": // 1-24
+ ret = date.getHours() || 24;
+ pad = true;
+ break;
+
+ // Minute
+ case "m":
+ ret = date.getMinutes();
+ pad = true;
break;
- case "zzz":
- add = "([+-]?\\d\\d?:\\d{2})";
+
+ // Second
+ case "s":
+ ret = date.getSeconds();
+ pad = true;
break;
- case "zz": case "z":
- add = "([+-]?\\d\\d?)";
+
+ case "S":
+ ret = Math.round( date.getMilliseconds() * Math.pow( 10, length - 3 ) );
+ pad = true;
break;
- case "/":
- add = "(\\/)";
+
+ case "A":
+ ret = Math.round( datetimeMillisecondsInDay( date ) * Math.pow( 10, length - 3 ) );
+ pad = true;
break;
+
+ // Zone
+ // see http://www.unicode.org/reports/tr35/tr35-dates.html#Using_Time_Zone_Names ?
+ // Need to be implemented.
+ case "z":
+ case "Z":
+ case "O":
+ case "v":
+ case "V":
+ case "X":
+ case "x":
+ throw new Error( "Not implemented" );
+
+ // Anything else is considered a literal, including [ ,:/.'@#], chinese, japonese, and arabic characters.
default:
- throw "Invalid date format pattern \'" + m + "\'.";
+ return current;
}
- if ( add ) {
- regexp.push( add );
+ if ( pad ) {
+ ret = stringPad( ret, length );
}
- 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;
+ return ret;
+ });
};
- outOfRange = function( value, low, high ) {
- return value < low || value > high;
- };
- toUpper = function( value ) {
- // "he-IL" has non-breaking space in weekday names.
- return value.split( "\u00A0" ).join( " " ).toUpperCase();
- };
- toUpperArray = function( arr ) {
- var results = [];
- for ( var i = 0, l = arr.length; i < l; i++ ) {
- results[ i ] = toUpper( arr[i] );
+
+ var arrayEvery = function( array, callback ) {
+ var i, length;
+ if ( array.every ) {
+ return array.every( callback );
+ }
+ for ( i = 0, length = array.length; i < length; i++ ) {
+ if ( !callback( array[ i ], i, array ) ) {
+ return false;
+ }
}
- return results;
+ return true;
};
- parseExact = function( 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;
+
+
+
+ /**
+ * tokenizer( value, pattern )
+ *
+ * Returns an Array of tokens, eg. value "5 o'clock PM", pattern "h 'o''clock' a":
+ * [{
+ * type: "h",
+ * lexeme: "5"
+ * }, {
+ * type: "literal",
+ * lexeme: " "
+ * }, {
+ * type: "literal",
+ * lexeme: "o'clock"
+ * }, {
+ * type: "literal",
+ * lexeme: " "
+ * }, {
+ * type: "a",
+ * lexeme: "PM",
+ * value: "pm"
+ * }]
+ *
+ * OBS: lexeme's are always String and may return invalid ranges depending of the token type. Eg. "99" for month number.
+ *
+ * Return an empty Array when not successfully parsed.
+ */
+ var datetimeTokenizer = function( value, pattern, cldr ) {
+ var valid,
+ tokens = [],
+ widths = [ "abbreviated", "wide", "narrow" ];
+
+ valid = arrayEvery( pattern.match( datetimePatternRe ), function( current ) {
+ var chr, length, tokenRe,
+ token = {};
+
+ function oneDigitIfLengthOne() {
+ if ( length === 1 ) {
+ return tokenRe = /\d/;
}
}
- }
- 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;
+
+ function oneOrTwoDigitsIfLengthOne() {
+ if ( length === 1 ) {
+ return tokenRe = /\d\d?/;
+ }
}
- }
- // 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;
- };
-}());
-parseNegativePattern = function( value, nf, negativePattern ) {
- var neg = nf[ "-" ],
- pos = nf[ "+" ],
- ret;
- switch ( negativePattern ) {
- case "n -":
- neg = " " + neg;
- pos = " " + pos;
- /* falls through */
- case "n-":
- if ( endsWith(value, neg) ) {
- ret = [ "-", value.substr(0, value.length - neg.length) ];
+ function twoDigitsIfLengthTwo() {
+ if ( length === 2 ) {
+ return tokenRe = /\d\d/;
+ }
}
- else if ( endsWith(value, pos) ) {
- ret = [ "+", value.substr(0, value.length - pos.length) ];
+
+ // Brute-force test every locale entry in an attempt to match the given value.
+ // Return the first found one (and set token accordingly), or null.
+ function lookup( path ) {
+ var i, re,
+ data = cldr.main( path );
+ for ( i in data ) {
+ re = new RegExp( "^" + data[ i ] );
+ if ( re.test( value ) ) {
+ token.value = i;
+ return tokenRe = new RegExp( data[ i ] );
+ }
+ }
+ return null;
}
- break;
- case "- n":
- neg += " ";
- pos += " ";
- /* falls through */
- case "-n":
- if ( startsWith(value, neg) ) {
- ret = [ "-", value.substr(neg.length) ];
+
+ token.type = current;
+ chr = current.charAt( 0 ),
+ length = current.length;
+
+ switch ( chr ) {
+
+ // Era
+ case "G":
+ lookup([
+ "dates/calendars/gregorian/eras",
+ length <= 3 ? "eraAbbr" : ( length === 4 ? "eraNames" : "eraNarrow" )
+ ]);
+ break;
+
+ // Year
+ case "y":
+ case "Y":
+ // number l=1:+, l=2:{2}, l=3:{3,}, l=4:{4,}, ...
+ if ( length === 1 ) {
+ tokenRe = /\d+/;
+ } else if ( length === 2 ) {
+ tokenRe = /\d\d/;
+ } else {
+ tokenRe = new RegExp( "\\d{" + length + ",}" );
+ }
+ break;
+
+ case "u": // Extended year. Need to be implemented.
+ case "U": // Cyclic year name. Need to be implemented.
+ throw new Error( "Not implemented" );
+
+ // Quarter
+ case "Q":
+ case "q":
+ // number l=1:{1}, l=2:{2}.
+ // lookup l=3...
+ oneDigitIfLengthOne() || twoDigitsIfLengthTwo() || lookup([
+ "dates/calendars/gregorian/quarters",
+ chr === "Q" ? "format" : "stand-alone",
+ widths[ length - 3 ]
+ ]);
+ break;
+
+ // Month
+ case "M":
+ case "L":
+ // number l=1:{1,2}, l=2:{2}.
+ // lookup l=3...
+ oneOrTwoDigitsIfLengthOne() || twoDigitsIfLengthTwo() || lookup([
+ "dates/calendars/gregorian/months",
+ chr === "M" ? "format" : "stand-alone",
+ widths[ length - 3 ]
+ ]);
+ break;
+
+ // Day (see d below)
+ case "D":
+ // number {l,3}.
+ if ( length <= 3 ) {
+ tokenRe = new RegExp( "\\d{" + length + ",3}" );
+ }
+ break;
+
+ case "W":
+ case "F":
+ // number l=1:{1}.
+ oneDigitIfLengthOne();
+ break;
+
+ case "g+":
+ // Modified Julian day. Need to be implemented.
+ throw new Error( "Not implemented" );
+
+ // Week day
+ case "e":
+ case "c":
+ // number l=1:{1}, l=2:{2}.
+ // lookup for length >=3.
+ if( length <= 2 ) {
+ oneDigitIfLengthOne() || twoDigitsIfLengthTwo();
+ break;
+ }
+
+ /* falls through */
+ case "E":
+ if ( length === 6 ) {
+ // Note: if short day names are not explicitly specified, abbreviated day names are used instead http://www.unicode.org/reports/tr35/tr35-dates.html#months_days_quarters_eras
+ lookup([
+ "dates/calendars/gregorian/days",
+ [ chr === "c" ? "stand-alone" : "format" ],
+ "short"
+ ]) || lookup([
+ "dates/calendars/gregorian/days",
+ [ chr === "c" ? "stand-alone" : "format" ],
+ "abbreviated"
+ ]);
+ } else {
+ lookup([
+ "dates/calendars/gregorian/days",
+ [ chr === "c" ? "stand-alone" : "format" ],
+ widths[ length < 3 ? 0 : length - 3 ]
+ ]);
+ }
+ break;
+
+ // Period (AM or PM)
+ case "a":
+ lookup([
+ "dates/calendars/gregorian/dayPeriods/format/wide"
+ ]);
+ break;
+
+ // Week, Day, Hour, Minute, or Second
+ case "w":
+ case "d":
+ case "h":
+ case "H":
+ case "K":
+ case "k":
+ case "j":
+ case "m":
+ case "s":
+ // number l1:{1,2}, l2:{2}.
+ oneOrTwoDigitsIfLengthOne() || twoDigitsIfLengthTwo();
+ break;
+
+ case "S":
+ // number {l}.
+ tokenRe = new RegExp( "\\d{" + length + "}" );
+ break;
+
+ case "A":
+ // number {l+5}.
+ tokenRe = new RegExp( "\\d{" + ( length + 5 ) + "}" );
+ break;
+
+ // Zone
+ // see http://www.unicode.org/reports/tr35/tr35-dates.html#Using_Time_Zone_Names ?
+ // Need to be implemented.
+ case "z":
+ case "Z":
+ case "O":
+ case "v":
+ case "V":
+ case "X":
+ case "x":
+ throw new Error( "Not implemented" );
+
+ case "'":
+ token.type = "literal";
+ if ( current.charAt( 1 ) === "'" ) {
+ tokenRe = /'/;
+ } else {
+ tokenRe = /'[^']+'/;
+ }
+ break;
+
+ default:
+ token.type = "literal";
+ tokenRe = /./;
}
- else if ( startsWith(value, pos) ) {
- ret = [ "+", value.substr(pos.length) ];
+
+ if ( !tokenRe ) {
+ return false;
}
- break;
- case "(n)":
- if ( startsWith(value, "(") && endsWith(value, ")") ) {
- ret = [ "-", value.substr(1, value.length - 2) ];
+
+ // Get lexeme and consume it.
+ value = value.replace( new RegExp( "^" + tokenRe.source ), function( lexeme ) {
+ token.lexeme = lexeme;
+ return "";
+ });
+
+ if ( !token.lexeme ) {
+ return false;
}
- break;
- }
- return ret || [ "", value ];
-};
-
-//
-// public instance functions
-//
-
-Globalize.prototype.findClosestCulture = function( cultureSelector ) {
- return Globalize.findClosestCulture.call( this, cultureSelector );
-};
-
-Globalize.prototype.format = function( value, format, cultureSelector ) {
- return Globalize.format.call( this, value, format, cultureSelector );
-};
-
-Globalize.prototype.localize = function( key, cultureSelector ) {
- return Globalize.localize.call( this, key, cultureSelector );
-};
-
-Globalize.prototype.parseInt = function( value, radix, cultureSelector ) {
- return Globalize.parseInt.call( this, value, radix, cultureSelector );
-};
-
-Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) {
- return Globalize.parseFloat.call( this, value, radix, cultureSelector );
-};
-
-Globalize.prototype.culture = function( cultureSelector ) {
- return Globalize.culture.call( this, cultureSelector );
-};
-
-//
-// public singleton functions
-//
-
-Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) {
-
- var base = {},
- isNew = false;
-
- if ( typeof cultureName !== "string" ) {
- // cultureName argument is optional string. If not specified, assume info is first
- // and only argument. Specified info deep-extends current culture.
- info = cultureName;
- cultureName = this.culture().name;
- base = this.cultures[ cultureName ];
- } else if ( typeof baseCultureName !== "string" ) {
- // baseCultureName argument is optional string. If not specified, assume info is second
- // argument. Specified info deep-extends specified culture.
- // If specified culture does not exist, create by deep-extending default
- info = baseCultureName;
- isNew = ( this.cultures[ cultureName ] == null );
- base = this.cultures[ cultureName ] || this.cultures[ "default" ];
- } else {
- // cultureName and baseCultureName specified. Assume a new culture is being created
- // by deep-extending an specified base culture
- isNew = true;
- base = this.cultures[ baseCultureName ];
- }
- this.cultures[ cultureName ] = extend(true, {},
- base,
- info
- );
- // Make the standard calendar the current culture if it's a new culture
- if ( isNew ) {
- this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard;
- }
-};
+ tokens.push( token );
+ return true;
+ });
-Globalize.findClosestCulture = function( name ) {
- var match;
- if ( !name ) {
- return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ];
- }
- if ( typeof name === "string" ) {
- name = name.split( "," );
+ return valid ? tokens : [];
+ };
+
+
+ var datetimeParse = (function() {
+
+ function outOfRange( value, low, high ) {
+ return value < low || value > high;
}
- 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 );
- pri = isNaN( pri ) ? 0 : pri;
- }
- else {
- pri = 1;
- }
- }
- prioritized.push({ lang: lang, pri: pri });
+
+ /**
+ * parse
+ *
+ * ref: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
+ */
+ return function( value, pattern, cldr ) {
+ var amPm, era, hour24, valid,
+ YEAR = 0,
+ MONTH = 1,
+ DAY = 2,
+ HOUR = 3,
+ MINUTE = 4,
+ SECOND = 5,
+ MILLISECONDS = 6,
+ date = new Date(),
+ tokens = datetimeTokenizer( value, pattern, cldr ),
+ truncateAt = [],
+ units = [ "year", "month", "day", "hour", "minute", "second", "milliseconds" ];
+
+ if ( !tokens.length ) {
+ return null;
}
- prioritized.sort(function( a, b ) {
- if ( a.pri < b.pri ) {
- return 1;
- } else if ( a.pri > b.pri ) {
- return -1;
+
+ valid = arrayEvery( tokens, function( token ) {
+ var century, chr, value, length;
+
+ if ( token.type === "literal" ) {
+ // continue
+ return true;
}
- return 0;
- });
- // exact match
- for ( i = 0; i < l; i++ ) {
- lang = prioritized[ i ].lang;
- match = cultures[ lang ];
- if ( match ) {
- return match;
+
+ chr = token.type.charAt( 0 );
+ length = token.type.length;
+
+ if ( chr === "j" ) {
+ // Locale preferred hHKk.
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
+ chr = cldr.supplemental.timeData.preferred();
}
- }
- // neutral language match
- for ( i = 0; i < l; i++ ) {
- lang = prioritized[ i ].lang;
- do {
- var index = lang.lastIndexOf( "-" );
- if ( index === -1 ) {
+ switch ( chr ) {
+
+ // Era
+ case "G":
+ truncateAt.push( YEAR );
+ era = +token.value;
break;
- }
- // strip off the last part. e.g. en-US => en
- lang = lang.substr( 0, index );
- match = cultures[ lang ];
- if ( match ) {
- return match;
- }
+
+ // Year
+ case "y":
+ value = +token.lexeme;
+ if ( length === 2 ) {
+ if ( outOfRange( value, 0, 99 ) ) {
+ return false;
+ }
+ // mimic dojo/date/locale: choose century to apply, according to a sliding window of 80 years before and 20 years after present year.
+ century = Math.floor( date.getFullYear() / 100 ) * 100;
+ value += century;
+ if ( value > date.getFullYear() + 20 ) {
+ value -= 100;
+ }
+ }
+ date.setFullYear( value );
+ truncateAt.push( YEAR );
+ break;
+
+ case "Y": // Year in "Week of Year"
+ case "u": // Extended year. Need to be implemented.
+ case "U": // Cyclic year name. Need to be implemented.
+ throw new Error( "Not implemented" );
+
+ // Quarter (skip)
+ case "Q":
+ case "q":
+ break;
+
+ // Month
+ case "M":
+ case "L":
+ if ( length <= 2 ) {
+ value = +token.lexeme;
+ } else {
+ value = +token.value;
+ }
+ if( outOfRange( value, 1, 12 ) ) {
+ return false;
+ }
+ date.setMonth( value - 1 );
+ truncateAt.push( MONTH );
+ break;
+
+ // Week (skip)
+ case "w": // Week of Year.
+ case "W": // Week of Month.
+ break;
+
+ // Day
+ case "d":
+ value = +token.lexeme;
+ if( outOfRange( value, 1, 31 ) ) {
+ return false;
+ }
+ date.setDate( value );
+ truncateAt.push( DAY );
+ break;
+
+ case "D":
+ value = +token.lexeme;
+ if( outOfRange( value, 1, 366 ) ) {
+ return false;
+ }
+ date.setMonth(0);
+ date.setDate( value );
+ truncateAt.push( DAY );
+ break;
+
+ case "F":
+ // Day of Week in month. eg. 2nd Wed in July.
+ // Skip
+ break;
+
+ case "g+":
+ // Modified Julian day. Need to be implemented.
+ throw new Error( "Not implemented" );
+
+ // Week day
+ case "e":
+ case "c":
+ case "E":
+ // Skip.
+ // value = arrayIndexOf( datetimeWeekDays, token.value );
+ break;
+
+ // Period (AM or PM)
+ case "a":
+ amPm = token.value;
+ break;
+
+ // Hour
+ case "K": // 0-11
+ value = +token.lexeme + 1;
+
+ /* falls through */
+ case "h": // 1-12
+ value = value || +token.lexeme;
+ if( outOfRange( value, 1, 12 ) ) {
+ return false;
+ }
+ date.setHours( value );
+ truncateAt.push( HOUR );
+ break;
+
+ case "H": // 0-23
+ value = +token.lexeme + 1;
+
+ /* falls through */
+ case "k": // 1-24
+ hour24 = true;
+ value = value || +token.lexeme;
+ if( outOfRange( value, 1, 24 ) ) {
+ return false;
+ }
+ date.setHours( value );
+ truncateAt.push( HOUR );
+ break;
+
+ // Minute
+ case "m":
+ value = +token.lexeme;
+ if( outOfRange( value, 0, 59 ) ) {
+ return false;
+ }
+ date.setMinutes( value );
+ truncateAt.push( MINUTE );
+ break;
+
+ // Second
+ case "s":
+ value = +token.lexeme;
+ if( outOfRange( value, 0, 59 ) ) {
+ return false;
+ }
+ date.setSeconds( value );
+ truncateAt.push( SECOND );
+ break;
+
+ case "A":
+ date.setHours( 0 );
+ date.setMinutes( 0 );
+ date.setSeconds( 0 );
+
+ /* falls through */
+ case "S":
+ value = Math.round( +token.lexeme * Math.pow( 10, 3 - length ) );
+ date.setMilliseconds( value );
+ truncateAt.push( MILLISECONDS );
+ break;
+
+ // Zone
+ // see http://www.unicode.org/reports/tr35/tr35-dates.html#Using_Time_Zone_Names ?
+ // Need to be implemented.
+ case "z":
+ case "Z":
+ case "O":
+ case "v":
+ case "V":
+ case "X":
+ case "x":
+ throw new Error( "Not implemented" );
}
- while ( 1 );
+
+ return true;
+ });
+
+ if ( !valid || amPm && hour24 ) {
+ return null;
}
- // last resort: match first culture using that language
- for ( i = 0; i < l; i++ ) {
- lang = prioritized[ i ].lang;
- for ( var cultureKey in cultures ) {
- var culture = cultures[ cultureKey ];
- if ( culture.language === lang ) {
- return culture;
- }
- }
+ if ( era === 0 ) {
+ // 1 BC = year 0
+ date.setFullYear( date.getFullYear() * -1 + 1 );
}
- }
- else if ( typeof name === "object" ) {
- return name;
- }
- return match || null;
-};
-Globalize.format = function( value, format, cultureSelector ) {
- var culture = this.findClosestCulture( cultureSelector );
- if ( value instanceof Date ) {
- value = formatDate( value, format, culture );
- }
- else if ( typeof value === "number" ) {
- value = formatNumber( value, format, culture );
- }
- return value;
-};
+ if ( amPm === "pm" && date.getHours() !== 12 ) {
+ date.setHours( date.getHours() + 12 );
+ }
-Globalize.localize = function( key, cultureSelector ) {
- return this.findClosestCulture( cultureSelector ).messages[ key ] ||
- this.cultures[ "default" ].messages[ key ];
-};
+ // Truncate date at the most precise unit defined. Eg.
+ // If value is "12/31", and pattern is "MM/dd":
+ // => new Date( <current Year>, 12, 31, 0, 0, 0, 0 );
+ truncateAt = Math.max.apply( null, truncateAt );
+ date = datetimeStartOf( date, units[ truncateAt ] );
-Globalize.parseDate = function( value, formats, culture ) {
- culture = this.findClosestCulture( culture );
+ return date;
+ };
- 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;
- }
- }
- }
+}());
+
+
+ var arrayIsArray = Array.isArray || function( obj ) {
+ return Object.prototype.toString.call( obj ) === "[object Array]";
+ };
+
+
+
+
+ var alwaysArray = function( stringOrArray ) {
+ return arrayIsArray( stringOrArray ) ? stringOrArray : [ stringOrArray ];
+ };
+
+
+
+
+ var arraySome = function( array, callback ) {
+ var i, length;
+ if ( array.some ) {
+ return array.some( callback );
}
- } else {
- patterns = culture.calendar.patterns;
- for ( prop in patterns ) {
- date = parseExact( value, patterns[prop], culture );
- if ( date ) {
- break;
+ for ( i = 0, length = array.length; i < length; i++ ) {
+ if ( callback( array[ i ], i, array ) ) {
+ return true;
}
}
- }
+ return false;
+ };
- return date || null;
-};
-Globalize.parseInt = function( value, radix, cultureSelector ) {
- return truncate( Globalize.parseFloat(value, radix, cultureSelector) );
-};
-Globalize.parseFloat = function( value, radix, cultureSelector ) {
- // radix argument is optional
- if ( typeof radix !== "number" ) {
- cultureSelector = radix;
- radix = 10;
- }
- var culture = this.findClosestCulture( cultureSelector );
- var ret = NaN,
- nf = culture.numberFormat;
+ var defaultLocale;
- if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) {
- // remove currency symbol
- value = value.replace( culture.numberFormat.currency.symbol, "" );
- // replace decimal seperator
- value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] );
+ function getLocale( locale ) {
+ return locale ? new Cldr( locale ) : defaultLocale;
}
- //Remove percentage character from number string before parsing
- if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){
- value = value.replace( culture.numberFormat.percent.symbol, "" );
- }
+ var Globalize = {};
+
+ /**
+ * Globalize.load( json )
+ *
+ * @json [JSON]
+ *
+ * Load resolved or unresolved cldr data.
+ * Somewhat equivalent to previous Globalize.addCultureInfo(...).
+ */
+ Globalize.load = function( json ) {
+ Cldr.load( json );
+ };
- // remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR
- value = value.replace( / /g, "" );
+ /**
+ * Globalize.loadTranslations( locale, json )
+ *
+ * @locale [String]
+ *
+ * @json [JSON]
+ *
+ * Load translation data per locale.
+ */
+ Globalize.loadTranslations = function( locale, json ) {
+ var customData = {
+ "globalize-translation": {}
+ };
+ locale = new Cldr( locale );
+ customData[ "globalize-translation" ][ locale.attributes.languageId ] = json;
+ Cldr.load( customData );
+ };
- // allow infinity or hexidecimal
- if ( regexInfinity.test(value) ) {
- ret = parseFloat( value );
- }
- else if ( !radix && regexHex.test(value) ) {
- ret = parseInt( value, 16 );
- }
- else {
-
- // determine sign and number
- var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
- sign = signInfo[ 0 ],
- num = signInfo[ 1 ];
-
- // #44 - try parsing as "(n)"
- if ( sign === "" && nf.pattern[0] !== "(n)" ) {
- signInfo = parseNegativePattern( value, nf, "(n)" );
- sign = signInfo[ 0 ];
- num = signInfo[ 1 ];
- }
+ /**
+ * Globalize.locale( locale )
+ *
+ * @locale [String]
+ *
+ * Set default locale.
+ * Somewhat equivalent to previous culture( selector ).
+ */
+ Globalize.locale = function( locale ) {
+ if ( arguments.length ) {
+ defaultLocale = new Cldr( locale );
+ }
+ return defaultLocale;
+ };
- // try parsing as "-n"
- if ( sign === "" && nf.pattern[0] !== "-n" ) {
- signInfo = parseNegativePattern( value, nf, "-n" );
- sign = signInfo[ 0 ];
- num = signInfo[ 1 ];
- }
+ /**
+ * Globalize.format( value, pattern, locale )
+ *
+ * @value [Date or Number]
+ *
+ * @pattern [String or Object] see datetime/expand_pattern for more info.
+ *
+ * @locale [String]
+ *
+ * Formats a date or number according to the given pattern string and the given locale (or the default locale if not specified).
+ */
+ Globalize.format = function( value, pattern, locale ) {
+ locale = getLocale( locale );
+
+ if ( value instanceof Date ) {
+
+ if ( !pattern ) {
+ throw new Error( "Missing pattern" );
+ }
+ pattern = datetimeExpandPattern( pattern, locale );
- sign = sign || "+";
+ value = datetimeFormat( value, pattern, locale );
- // 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 if ( typeof value === "number" ) {
+ // TODO value = numberFormat( value, pattern, locale );
+ throw new Error( "Number Format not implemented yet" );
}
- 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;
-};
-Globalize.culture = function( cultureSelector ) {
- // setter
- if ( typeof cultureSelector !== "undefined" ) {
- this.cultureSelector = cultureSelector;
- }
- // getter
- return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ];
-};
+ return value;
+ };
+
+ /**
+ * Globalize.parseDate( value, patterns, locale )
+ *
+ * @value [Date]
+ *
+ * @patterns [Array] Optional. See datetime/expand_pattern for more info about each pattern. Defaults to the list of all presets defined in the locale (see datetime/all_presets for more info).
+ *
+ * @locale [String]
+ *
+ * Return a Date instance or null.
+ */
+ Globalize.parseDate = function( value, patterns, locale ) {
+ var date;
+ locale = getLocale( locale );
+
+ if ( typeof value !== "string" ) {
+ throw new Error( "invalid value (" + value + "), string expected" );
+ }
+
+ if ( !patterns ) {
+ patterns = datetimeAllPresets( locale );
+ } else {
+ patterns = alwaysArray( patterns );
+ }
+
+ arraySome( patterns, function( pattern ) {
+ pattern = datetimeExpandPattern( pattern, locale );
+ date = datetimeParse( value, pattern, locale );
+ return !!date;
+ });
+
+ return date || null;
+ };
+
+ /**
+ * Globalize.translate( path, locale )
+ *
+ * @path [String or Array]
+ *
+ * @locale [String]
+ *
+ * Translate item given its path.
+ */
+ Globalize.translate = function( path , locale ) {
+ locale = getLocale( locale );
+ path = alwaysArray( path );
+ return locale.get( [ "globalize-translation/{languageId}" ].concat( path ) );
+ };
+
+ return Globalize;
+
+
-}( this )); \ No newline at end of file
+}));
diff --git a/external/localization.js b/external/localization.js
new file mode 100644
index 000000000..a03fcd9b4
--- /dev/null
+++ b/external/localization.js
@@ -0,0 +1,3137 @@
+/**
+ * CLDR locale data
+ */
+( function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ define( [
+ "globalize"
+ ], factory );
+ } else {
+
+ // Browser globals
+ factory( Globalize );
+ }
+}( function( Globalize ) {
+
+Globalize.load({
+ "main": {
+ "en": {
+ "identity": {
+ "version": {
+ "_cldrVersion": "24",
+ "_number": "$Revision: 9287 $"
+ },
+ "generation": {
+ "_date": "$Date: 2013-08-28 21:32:04 -0500 (Wed, 28 Aug 2013) $"
+ },
+ "language": "en"
+ },
+ "dates": {
+ "calendars": {
+ "gregorian": {
+ "months": {
+ "format": {
+ "abbreviated": {
+ "1": "Jan",
+ "2": "Feb",
+ "3": "Mar",
+ "4": "Apr",
+ "5": "May",
+ "6": "Jun",
+ "7": "Jul",
+ "8": "Aug",
+ "9": "Sep",
+ "10": "Oct",
+ "11": "Nov",
+ "12": "Dec"
+ },
+ "narrow": {
+ "1": "J",
+ "2": "F",
+ "3": "M",
+ "4": "A",
+ "5": "M",
+ "6": "J",
+ "7": "J",
+ "8": "A",
+ "9": "S",
+ "10": "O",
+ "11": "N",
+ "12": "D"
+ },
+ "wide": {
+ "1": "January",
+ "2": "February",
+ "3": "March",
+ "4": "April",
+ "5": "May",
+ "6": "June",
+ "7": "July",
+ "8": "August",
+ "9": "September",
+ "10": "October",
+ "11": "November",
+ "12": "December"
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "1": "Jan",
+ "2": "Feb",
+ "3": "Mar",
+ "4": "Apr",
+ "5": "May",
+ "6": "Jun",
+ "7": "Jul",
+ "8": "Aug",
+ "9": "Sep",
+ "10": "Oct",
+ "11": "Nov",
+ "12": "Dec"
+ },
+ "narrow": {
+ "1": "J",
+ "2": "F",
+ "3": "M",
+ "4": "A",
+ "5": "M",
+ "6": "J",
+ "7": "J",
+ "8": "A",
+ "9": "S",
+ "10": "O",
+ "11": "N",
+ "12": "D"
+ },
+ "wide": {
+ "1": "January",
+ "2": "February",
+ "3": "March",
+ "4": "April",
+ "5": "May",
+ "6": "June",
+ "7": "July",
+ "8": "August",
+ "9": "September",
+ "10": "October",
+ "11": "November",
+ "12": "December"
+ }
+ }
+ },
+ "days": {
+ "format": {
+ "abbreviated": {
+ "sun": "Sun",
+ "mon": "Mon",
+ "tue": "Tue",
+ "wed": "Wed",
+ "thu": "Thu",
+ "fri": "Fri",
+ "sat": "Sat"
+ },
+ "narrow": {
+ "sun": "S",
+ "mon": "M",
+ "tue": "T",
+ "wed": "W",
+ "thu": "T",
+ "fri": "F",
+ "sat": "S"
+ },
+ "short": {
+ "sun": "Su",
+ "mon": "Mo",
+ "tue": "Tu",
+ "wed": "We",
+ "thu": "Th",
+ "fri": "Fr",
+ "sat": "Sa"
+ },
+ "wide": {
+ "sun": "Sunday",
+ "mon": "Monday",
+ "tue": "Tuesday",
+ "wed": "Wednesday",
+ "thu": "Thursday",
+ "fri": "Friday",
+ "sat": "Saturday"
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "sun": "Sun",
+ "mon": "Mon",
+ "tue": "Tue",
+ "wed": "Wed",
+ "thu": "Thu",
+ "fri": "Fri",
+ "sat": "Sat"
+ },
+ "narrow": {
+ "sun": "S",
+ "mon": "M",
+ "tue": "T",
+ "wed": "W",
+ "thu": "T",
+ "fri": "F",
+ "sat": "S"
+ },
+ "short": {
+ "sun": "Su",
+ "mon": "Mo",
+ "tue": "Tu",
+ "wed": "We",
+ "thu": "Th",
+ "fri": "Fr",
+ "sat": "Sa"
+ },
+ "wide": {
+ "sun": "Sunday",
+ "mon": "Monday",
+ "tue": "Tuesday",
+ "wed": "Wednesday",
+ "thu": "Thursday",
+ "fri": "Friday",
+ "sat": "Saturday"
+ }
+ }
+ },
+ "quarters": {
+ "format": {
+ "abbreviated": {
+ "1": "Q1",
+ "2": "Q2",
+ "3": "Q3",
+ "4": "Q4"
+ },
+ "narrow": {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4"
+ },
+ "wide": {
+ "1": "1st quarter",
+ "2": "2nd quarter",
+ "3": "3rd quarter",
+ "4": "4th quarter"
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "1": "Q1",
+ "2": "Q2",
+ "3": "Q3",
+ "4": "Q4"
+ },
+ "narrow": {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4"
+ },
+ "wide": {
+ "1": "1st quarter",
+ "2": "2nd quarter",
+ "3": "3rd quarter",
+ "4": "4th quarter"
+ }
+ }
+ },
+ "dayPeriods": {
+ "format": {
+ "abbreviated": {
+ "am": "AM",
+ "am-alt-variant": "a.m.",
+ "noon": "noon",
+ "pm": "PM",
+ "pm-alt-variant": "p.m."
+ },
+ "narrow": {
+ "am": "a",
+ "am-alt-variant": "a.m.",
+ "noon": "n",
+ "pm": "p",
+ "pm-alt-variant": "p.m."
+ },
+ "wide": {
+ "am": "AM",
+ "am-alt-variant": "a.m.",
+ "noon": "noon",
+ "pm": "PM",
+ "pm-alt-variant": "p.m."
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "am": "AM",
+ "am-alt-variant": "a.m.",
+ "noon": "noon",
+ "pm": "PM",
+ "pm-alt-variant": "p.m."
+ },
+ "narrow": {
+ "am": "a",
+ "am-alt-variant": "a.m.",
+ "noon": "n",
+ "pm": "p",
+ "pm-alt-variant": "p.m."
+ },
+ "wide": {
+ "am": "AM",
+ "am-alt-variant": "a.m.",
+ "noon": "noon",
+ "pm": "PM",
+ "pm-alt-variant": "p.m."
+ }
+ }
+ },
+ "eras": {
+ "eraNames": {
+ "0": "Before Christ",
+ "0-alt-variant": "Before Common Era",
+ "1": "Anno Domini",
+ "1-alt-variant": "Common Era"
+ },
+ "eraAbbr": {
+ "0": "BC",
+ "0-alt-variant": "BCE",
+ "1": "AD",
+ "1-alt-variant": "CE"
+ },
+ "eraNarrow": {
+ "0": "B",
+ "0-alt-variant": "BCE",
+ "1": "A",
+ "1-alt-variant": "CE"
+ }
+ },
+ "dateFormats": {
+ "full": "EEEE, MMMM d, y",
+ "long": "MMMM d, y",
+ "medium": "MMM d, y",
+ "short": "M/d/yy"
+ },
+ "timeFormats": {
+ "full": "h:mm:ss a zzzz",
+ "long": "h:mm:ss a z",
+ "medium": "h:mm:ss a",
+ "short": "h:mm a"
+ },
+ "dateTimeFormats": {
+ "full": "{1} 'at' {0}",
+ "long": "{1} 'at' {0}",
+ "medium": "{1}, {0}",
+ "short": "{1}, {0}",
+ "availableFormats": {
+ "d": "d",
+ "Ed": "d E",
+ "Ehm": "E h:mm a",
+ "EHm": "E HH:mm",
+ "Ehms": "E h:mm:ss a",
+ "EHms": "E HH:mm:ss",
+ "Gy": "y G",
+ "GyMMM": "MMM y G",
+ "GyMMMd": "MMM d, y G",
+ "GyMMMEd": "E, MMM d, y G",
+ "h": "h a",
+ "H": "HH",
+ "hm": "h:mm a",
+ "Hm": "HH:mm",
+ "hms": "h:mm:ss a",
+ "Hms": "HH:mm:ss",
+ "M": "L",
+ "Md": "M/d",
+ "MEd": "E, M/d",
+ "MMM": "LLL",
+ "MMMd": "MMM d",
+ "MMMEd": "E, MMM d",
+ "ms": "mm:ss",
+ "y": "y",
+ "yM": "M/y",
+ "yMd": "M/d/y",
+ "yMEd": "E, M/d/y",
+ "yMMM": "MMM y",
+ "yMMMd": "MMM d, y",
+ "yMMMEd": "E, MMM d, y",
+ "yQQQ": "QQQ y",
+ "yQQQQ": "QQQQ y"
+ },
+ "appendItems": {
+ "Day": "{0} ({2}: {1})",
+ "Day-Of-Week": "{0} {1}",
+ "Era": "{0} {1}",
+ "Hour": "{0} ({2}: {1})",
+ "Minute": "{0} ({2}: {1})",
+ "Month": "{0} ({2}: {1})",
+ "Quarter": "{0} ({2}: {1})",
+ "Second": "{0} ({2}: {1})",
+ "Timezone": "{0} {1}",
+ "Week": "{0} ({2}: {1})",
+ "Year": "{0} {1}"
+ },
+ "intervalFormats": {
+ "intervalFormatFallback": "{0} – {1}",
+ "d": {
+ "d": "d – d"
+ },
+ "h": {
+ "a": "h a – h a",
+ "h": "h – h a"
+ },
+ "H": {
+ "H": "HH – HH"
+ },
+ "hm": {
+ "a": "h:mm a – h:mm a",
+ "h": "h:mm – h:mm a",
+ "m": "h:mm – h:mm a"
+ },
+ "Hm": {
+ "H": "HH:mm – HH:mm",
+ "m": "HH:mm – HH:mm"
+ },
+ "hmv": {
+ "a": "h:mm a – h:mm a v",
+ "h": "h:mm – h:mm a v",
+ "m": "h:mm – h:mm a v"
+ },
+ "Hmv": {
+ "H": "HH:mm – HH:mm v",
+ "m": "HH:mm – HH:mm v"
+ },
+ "hv": {
+ "a": "h a – h a v",
+ "h": "h – h a v"
+ },
+ "Hv": {
+ "H": "HH – HH v"
+ },
+ "M": {
+ "M": "M – M"
+ },
+ "Md": {
+ "d": "M/d – M/d",
+ "M": "M/d – M/d"
+ },
+ "MEd": {
+ "d": "E, M/d – E, M/d",
+ "M": "E, M/d – E, M/d"
+ },
+ "MMM": {
+ "M": "MMM – MMM"
+ },
+ "MMMd": {
+ "d": "MMM d – d",
+ "M": "MMM d – MMM d"
+ },
+ "MMMEd": {
+ "d": "E, MMM d – E, MMM d",
+ "M": "E, MMM d – E, MMM d"
+ },
+ "y": {
+ "y": "y – y"
+ },
+ "yM": {
+ "M": "M/y – M/y",
+ "y": "M/y – M/y"
+ },
+ "yMd": {
+ "d": "M/d/y – M/d/y",
+ "M": "M/d/y – M/d/y",
+ "y": "M/d/y – M/d/y"
+ },
+ "yMEd": {
+ "d": "E, M/d/y – E, M/d/y",
+ "M": "E, M/d/y – E, M/d/y",
+ "y": "E, M/d/y – E, M/d/y"
+ },
+ "yMMM": {
+ "M": "MMM – MMM y",
+ "y": "MMM y – MMM y"
+ },
+ "yMMMd": {
+ "d": "MMM d – d, y",
+ "M": "MMM d – MMM d, y",
+ "y": "MMM d, y – MMM d, y"
+ },
+ "yMMMEd": {
+ "d": "E, MMM d – E, MMM d, y",
+ "M": "E, MMM d – E, MMM d, y",
+ "y": "E, MMM d, y – E, MMM d, y"
+ },
+ "yMMMM": {
+ "M": "MMMM – MMMM y",
+ "y": "MMMM y – MMMM y"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+});
+
+Globalize.load({
+ "main": {
+ "de": {
+ "identity": {
+ "version": {
+ "_cldrVersion": "24",
+ "_number": "$Revision: 9287 $"
+ },
+ "generation": {
+ "_date": "$Date: 2013-08-28 21:32:04 -0500 (Wed, 28 Aug 2013) $"
+ },
+ "language": "de"
+ },
+ "dates": {
+ "calendars": {
+ "gregorian": {
+ "months": {
+ "format": {
+ "abbreviated": {
+ "1": "Jan.",
+ "2": "Feb.",
+ "3": "März",
+ "4": "Apr.",
+ "5": "Mai",
+ "6": "Juni",
+ "7": "Juli",
+ "8": "Aug.",
+ "9": "Sep.",
+ "10": "Okt.",
+ "11": "Nov.",
+ "12": "Dez."
+ },
+ "narrow": {
+ "1": "J",
+ "2": "F",
+ "3": "M",
+ "4": "A",
+ "5": "M",
+ "6": "J",
+ "7": "J",
+ "8": "A",
+ "9": "S",
+ "10": "O",
+ "11": "N",
+ "12": "D"
+ },
+ "wide": {
+ "1": "Januar",
+ "2": "Februar",
+ "3": "März",
+ "4": "April",
+ "5": "Mai",
+ "6": "Juni",
+ "7": "Juli",
+ "8": "August",
+ "9": "September",
+ "10": "Oktober",
+ "11": "November",
+ "12": "Dezember"
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "1": "Jan",
+ "2": "Feb",
+ "3": "Mär",
+ "4": "Apr",
+ "5": "Mai",
+ "6": "Jun",
+ "7": "Jul",
+ "8": "Aug",
+ "9": "Sep",
+ "10": "Okt",
+ "11": "Nov",
+ "12": "Dez"
+ },
+ "narrow": {
+ "1": "J",
+ "2": "F",
+ "3": "M",
+ "4": "A",
+ "5": "M",
+ "6": "J",
+ "7": "J",
+ "8": "A",
+ "9": "S",
+ "10": "O",
+ "11": "N",
+ "12": "D"
+ },
+ "wide": {
+ "1": "Januar",
+ "2": "Februar",
+ "3": "März",
+ "4": "April",
+ "5": "Mai",
+ "6": "Juni",
+ "7": "Juli",
+ "8": "August",
+ "9": "September",
+ "10": "Oktober",
+ "11": "November",
+ "12": "Dezember"
+ }
+ }
+ },
+ "days": {
+ "format": {
+ "abbreviated": {
+ "sun": "So.",
+ "mon": "Mo.",
+ "tue": "Di.",
+ "wed": "Mi.",
+ "thu": "Do.",
+ "fri": "Fr.",
+ "sat": "Sa."
+ },
+ "narrow": {
+ "sun": "S",
+ "mon": "M",
+ "tue": "D",
+ "wed": "M",
+ "thu": "D",
+ "fri": "F",
+ "sat": "S"
+ },
+ "short": {
+ "sun": "So.",
+ "mon": "Mo.",
+ "tue": "Di.",
+ "wed": "Mi.",
+ "thu": "Do.",
+ "fri": "Fr.",
+ "sat": "Sa."
+ },
+ "wide": {
+ "sun": "Sonntag",
+ "mon": "Montag",
+ "tue": "Dienstag",
+ "wed": "Mittwoch",
+ "thu": "Donnerstag",
+ "fri": "Freitag",
+ "sat": "Samstag"
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "sun": "So",
+ "mon": "Mo",
+ "tue": "Di",
+ "wed": "Mi",
+ "thu": "Do",
+ "fri": "Fr",
+ "sat": "Sa"
+ },
+ "narrow": {
+ "sun": "S",
+ "mon": "M",
+ "tue": "D",
+ "wed": "M",
+ "thu": "D",
+ "fri": "F",
+ "sat": "S"
+ },
+ "short": {
+ "sun": "So.",
+ "mon": "Mo.",
+ "tue": "Di.",
+ "wed": "Mi.",
+ "thu": "Do.",
+ "fri": "Fr.",
+ "sat": "Sa."
+ },
+ "wide": {
+ "sun": "Sonntag",
+ "mon": "Montag",
+ "tue": "Dienstag",
+ "wed": "Mittwoch",
+ "thu": "Donnerstag",
+ "fri": "Freitag",
+ "sat": "Samstag"
+ }
+ }
+ },
+ "quarters": {
+ "format": {
+ "abbreviated": {
+ "1": "Q1",
+ "2": "Q2",
+ "3": "Q3",
+ "4": "Q4"
+ },
+ "narrow": {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4"
+ },
+ "wide": {
+ "1": "1. Quartal",
+ "2": "2. Quartal",
+ "3": "3. Quartal",
+ "4": "4. Quartal"
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "1": "Q1",
+ "2": "Q2",
+ "3": "Q3",
+ "4": "Q4"
+ },
+ "narrow": {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4"
+ },
+ "wide": {
+ "1": "1. Quartal",
+ "2": "2. Quartal",
+ "3": "3. Quartal",
+ "4": "4. Quartal"
+ }
+ }
+ },
+ "dayPeriods": {
+ "format": {
+ "abbreviated": {
+ "afternoon": "nachmittags",
+ "am": "vorm.",
+ "earlyMorning": "morgens",
+ "evening": "abends",
+ "morning": "vormittags",
+ "night": "nachts",
+ "noon": "Mittag",
+ "pm": "nachm."
+ },
+ "narrow": {
+ "afternoon": "nachmittags",
+ "am": "vorm.",
+ "earlyMorning": "morgens",
+ "evening": "abends",
+ "morning": "vormittags",
+ "night": "nachts",
+ "noon": "Mittag",
+ "pm": "nachm."
+ },
+ "wide": {
+ "afternoon": "nachmittags",
+ "am": "vorm.",
+ "earlyMorning": "morgens",
+ "evening": "abends",
+ "morning": "vormittags",
+ "night": "nachts",
+ "noon": "Mittag",
+ "pm": "nachm."
+ }
+ },
+ "stand-alone": {
+ "abbreviated": {
+ "afternoon": "nachmittags",
+ "am": "vorm.",
+ "earlyMorning": "morgens",
+ "evening": "abends",
+ "morning": "vormittags",
+ "night": "nachts",
+ "noon": "Mittag",
+ "pm": "nachm."
+ },
+ "narrow": {
+ "afternoon": "nachmittags",
+ "am": "vorm.",
+ "earlyMorning": "morgens",
+ "evening": "abends",
+ "morning": "vormittags",
+ "night": "nachts",
+ "noon": "Mittag",
+ "pm": "nachm."
+ },
+ "wide": {
+ "afternoon": "Nachmittag",
+ "am": "vorm.",
+ "earlyMorning": "Morgen",
+ "evening": "Abend",
+ "morning": "Vormittag",
+ "night": "Nacht",
+ "noon": "Mittag",
+ "pm": "nachm."
+ }
+ }
+ },
+ "eras": {
+ "eraNames": {
+ "0": "v. Chr.",
+ "0-alt-variant": "vor der gewöhnlichen Zeitrechnung",
+ "1": "n. Chr.",
+ "1-alt-variant": "der gewöhnlichen Zeitrechnung"
+ },
+ "eraAbbr": {
+ "0": "v. Chr.",
+ "0-alt-variant": "v. u. Z.",
+ "1": "n. Chr.",
+ "1-alt-variant": "u. Z."
+ },
+ "eraNarrow": {
+ "0": "v. Chr.",
+ "0-alt-variant": "vdZ",
+ "1": "n. Chr.",
+ "1-alt-variant": "dZ"
+ }
+ },
+ "dateFormats": {
+ "full": "EEEE, d. MMMM y",
+ "long": "d. MMMM y",
+ "medium": "dd.MM.y",
+ "short": "dd.MM.yy"
+ },
+ "timeFormats": {
+ "full": "HH:mm:ss zzzz",
+ "long": "HH:mm:ss z",
+ "medium": "HH:mm:ss",
+ "short": "HH:mm"
+ },
+ "dateTimeFormats": {
+ "full": "{1} {0}",
+ "long": "{1} {0}",
+ "medium": "{1} {0}",
+ "short": "{1} {0}",
+ "availableFormats": {
+ "d": "d",
+ "Ed": "E, d.",
+ "Ehm": "E h:mm a",
+ "EHm": "E, HH:mm",
+ "Ehms": "E, h:mm:ss a",
+ "EHms": "E, HH:mm:ss",
+ "Gy": "y G",
+ "GyMMM": "MMM y G",
+ "GyMMMd": "d. MMM y G",
+ "GyMMMEd": "E, d. MMM y G",
+ "h": "h a",
+ "H": "HH 'Uhr'",
+ "hm": "h:mm a",
+ "Hm": "HH:mm",
+ "hms": "h:mm:ss a",
+ "Hms": "HH:mm:ss",
+ "M": "L",
+ "Md": "d.M.",
+ "MEd": "E, d.M.",
+ "MMd": "d.MM.",
+ "MMdd": "dd.MM.",
+ "MMM": "LLL",
+ "MMMd": "d. MMM",
+ "MMMEd": "E, d. MMM",
+ "MMMMdd": "dd. MMMM",
+ "MMMMEd": "E, d. MMMM",
+ "ms": "mm:ss",
+ "y": "y",
+ "yM": "M.y",
+ "yMd": "d.M.y",
+ "yMEd": "E, d.M.y",
+ "yMM": "MM.y",
+ "yMMdd": "dd.MM.y",
+ "yMMM": "MMM y",
+ "yMMMd": "d. MMM y",
+ "yMMMEd": "E, d. MMM y",
+ "yMMMM": "MMMM y",
+ "yQQQ": "QQQ y",
+ "yQQQQ": "QQQQ y"
+ },
+ "appendItems": {
+ "Day": "{0} ({2}: {1})",
+ "Day-Of-Week": "{0} {1}",
+ "Era": "{1} {0}",
+ "Hour": "{0} ({2}: {1})",
+ "Minute": "{0} ({2}: {1})",
+ "Month": "{0} ({2}: {1})",
+ "Quarter": "{0} ({2}: {1})",
+ "Second": "{0} ({2}: {1})",
+ "Timezone": "{0} {1}",
+ "Week": "{0} ({2}: {1})",
+ "Year": "{1} {0}"
+ },
+ "intervalFormats": {
+ "intervalFormatFallback": "{0} - {1}",
+ "d": {
+ "d": "d.-d."
+ },
+ "h": {
+ "a": "h a - h a",
+ "h": "h-h a"
+ },
+ "H": {
+ "H": "HH-HH 'Uhr'"
+ },
+ "hm": {
+ "a": "h:mm a - h:mm a",
+ "h": "h:mm-h:mm a",
+ "m": "h:mm-h:mm a"
+ },
+ "Hm": {
+ "H": "HH:mm-HH:mm",
+ "m": "HH:mm-HH:mm"
+ },
+ "hmv": {
+ "a": "h:mm a - h:mm a v",
+ "h": "h:mm-h:mm a v",
+ "m": "h:mm-h:mm a v"
+ },
+ "Hmv": {
+ "H": "HH:mm-HH:mm v",
+ "m": "HH:mm-HH:mm v"
+ },
+ "hv": {
+ "a": "h a - h a v",
+ "h": "h-h a v"
+ },
+ "Hv": {
+ "H": "HH-HH 'Uhr' v"
+ },
+ "M": {
+ "M": "M.-M."
+ },
+ "Md": {
+ "d": "dd.MM. - dd.MM.",
+ "M": "dd.MM. - dd.MM."
+ },
+ "MEd": {
+ "d": "E, dd.MM. - E, dd.MM.",
+ "M": "E, dd.MM. - E, dd.MM."
+ },
+ "MMM": {
+ "M": "MMM-MMM"
+ },
+ "MMMd": {
+ "d": "d.-d. MMM",
+ "M": "d. MMM - d. MMM"
+ },
+ "MMMEd": {
+ "d": "E, d. - E, d. MMM",
+ "M": "E, d. MMM - E, d. MMM"
+ },
+ "MMMM": {
+ "M": "LLLL-LLLL"
+ },
+ "y": {
+ "y": "y-y"
+ },
+ "yM": {
+ "M": "MM.y - MM.y",
+ "y": "MM.y - MM.y"
+ },
+ "yMd": {
+ "d": "dd.MM.y - dd.MM.y",
+ "M": "dd.MM.y - dd.MM.y",
+ "y": "dd.MM.y - dd.MM.y"
+ },
+ "yMEd": {
+ "d": "E, dd.MM.y - E, dd.MM.y",
+ "M": "E, dd.MM.y - E, dd.MM.y",
+ "y": "E, dd.MM.y - E, dd.MM.y"
+ },
+ "yMMM": {
+ "M": "MMM-MMM y",
+ "y": "MMM y - MMM y"
+ },
+ "yMMMd": {
+ "d": "d.-d. MMM y",
+ "M": "d. MMM - d. MMM y",
+ "y": "d. MMM y - d. MMM y"
+ },
+ "yMMMEd": {
+ "d": "E, d. - E, d. MMM y",
+ "M": "E, d. MMM - E, d. MMM y",
+ "y": "E, d. MMM y - E, d. MMM y"
+ },
+ "yMMMM": {
+ "M": "MMMM-MMMM y",
+ "y": "MMMM y - MMMM y"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+});
+
+/**
+ * CLDR supplemental data
+ */
+
+// likelySubtags
+Globalize.load({
+ "supplemental": {
+ "version": {
+ "_cldrVersion": "24",
+ "_number": "$Revision: 9305 $"
+ },
+ "generation": {
+ "_date": "$Date: 2013-09-04 09:50:17 -0500 (Wed, 04 Sep 2013) $"
+ },
+ "likelySubtags": {
+ "aa": "aa_Latn_ET",
+ "ab": "ab_Cyrl_GE",
+ "ace": "ace_Latn_ID",
+ "ady": "ady_Cyrl_RU",
+ "af": "af_Latn_ZA",
+ "agq": "agq_Latn_CM",
+ "ak": "ak_Latn_GH",
+ "alt": "alt_Cyrl_RU",
+ "am": "am_Ethi_ET",
+ "amo": "amo_Latn_NG",
+ "ar": "ar_Arab_EG",
+ "as": "as_Beng_IN",
+ "asa": "asa_Latn_TZ",
+ "ast": "ast_Latn_ES",
+ "av": "av_Cyrl_RU",
+ "awa": "awa_Deva_IN",
+ "ay": "ay_Latn_BO",
+ "az": "az_Latn_AZ",
+ "az_Arab": "az_Arab_IR",
+ "az_IR": "az_Arab_IR",
+ "az_RU": "az_Cyrl_RU",
+ "ba": "ba_Cyrl_RU",
+ "bal": "bal_Arab_PK",
+ "ban": "ban_Latn_ID",
+ "bas": "bas_Latn_CM",
+ "bax": "bax_Bamu_CM",
+ "bbc": "bbc_Latn_ID",
+ "be": "be_Cyrl_BY",
+ "bem": "bem_Latn_ZM",
+ "bez": "bez_Latn_TZ",
+ "bfq": "bfq_Taml_IN",
+ "bft": "bft_Arab_PK",
+ "bfy": "bfy_Deva_IN",
+ "bg": "bg_Cyrl_BG",
+ "bhb": "bhb_Deva_IN",
+ "bho": "bho_Deva_IN",
+ "bi": "bi_Latn_VU",
+ "bik": "bik_Latn_PH",
+ "bin": "bin_Latn_NG",
+ "bjj": "bjj_Deva_IN",
+ "bku": "bku_Latn_PH",
+ "bm": "bm_Latn_ML",
+ "bn": "bn_Beng_BD",
+ "bo": "bo_Tibt_CN",
+ "bqv": "bqv_Latn_CI",
+ "br": "br_Latn_FR",
+ "bra": "bra_Deva_IN",
+ "brx": "brx_Deva_IN",
+ "bs": "bs_Latn_BA",
+ "bss": "bss_Latn_CM",
+ "btv": "btv_Deva_PK",
+ "bua": "bua_Cyrl_RU",
+ "buc": "buc_Latn_YT",
+ "bug": "bug_Latn_ID",
+ "bya": "bya_Latn_ID",
+ "byn": "byn_Ethi_ER",
+ "ca": "ca_Latn_ES",
+ "cch": "cch_Latn_NG",
+ "ccp": "ccp_Beng_IN",
+ "ce": "ce_Cyrl_RU",
+ "ceb": "ceb_Latn_PH",
+ "cgg": "cgg_Latn_UG",
+ "ch": "ch_Latn_GU",
+ "chk": "chk_Latn_FM",
+ "chm": "chm_Cyrl_RU",
+ "chp": "chp_Latn_CA",
+ "chr": "chr_Cher_US",
+ "cja": "cja_Arab_KH",
+ "cjm": "cjm_Cham_VN",
+ "ckb": "ckb_Arab_IQ",
+ "co": "co_Latn_FR",
+ "cr": "cr_Cans_CA",
+ "crk": "crk_Cans_CA",
+ "cs": "cs_Latn_CZ",
+ "csb": "csb_Latn_PL",
+ "cv": "cv_Cyrl_RU",
+ "cy": "cy_Latn_GB",
+ "da": "da_Latn_DK",
+ "dar": "dar_Cyrl_RU",
+ "dav": "dav_Latn_KE",
+ "de": "de_Latn_DE",
+ "den": "den_Latn_CA",
+ "dgr": "dgr_Latn_CA",
+ "dje": "dje_Latn_NE",
+ "doi": "doi_Arab_IN",
+ "dsb": "dsb_Latn_DE",
+ "dua": "dua_Latn_CM",
+ "dv": "dv_Thaa_MV",
+ "dyo": "dyo_Latn_SN",
+ "dyu": "dyu_Latn_BF",
+ "dz": "dz_Tibt_BT",
+ "ebu": "ebu_Latn_KE",
+ "ee": "ee_Latn_GH",
+ "efi": "efi_Latn_NG",
+ "el": "el_Grek_GR",
+ "en": "en_Latn_US",
+ "eo": "eo_Latn_001",
+ "es": "es_Latn_ES",
+ "et": "et_Latn_EE",
+ "eu": "eu_Latn_ES",
+ "ewo": "ewo_Latn_CM",
+ "fa": "fa_Arab_IR",
+ "fan": "fan_Latn_GQ",
+ "ff": "ff_Latn_SN",
+ "fi": "fi_Latn_FI",
+ "fil": "fil_Latn_PH",
+ "fj": "fj_Latn_FJ",
+ "fo": "fo_Latn_FO",
+ "fon": "fon_Latn_BJ",
+ "fr": "fr_Latn_FR",
+ "fur": "fur_Latn_IT",
+ "fy": "fy_Latn_NL",
+ "ga": "ga_Latn_IE",
+ "gaa": "gaa_Latn_GH",
+ "gag": "gag_Latn_MD",
+ "gbm": "gbm_Deva_IN",
+ "gcr": "gcr_Latn_GF",
+ "gd": "gd_Latn_GB",
+ "gez": "gez_Ethi_ET",
+ "gil": "gil_Latn_KI",
+ "gl": "gl_Latn_ES",
+ "gn": "gn_Latn_PY",
+ "gon": "gon_Telu_IN",
+ "gor": "gor_Latn_ID",
+ "grt": "grt_Beng_IN",
+ "gsw": "gsw_Latn_CH",
+ "gu": "gu_Gujr_IN",
+ "guz": "guz_Latn_KE",
+ "gv": "gv_Latn_IM",
+ "gwi": "gwi_Latn_CA",
+ "ha": "ha_Latn_NG",
+ "ha_CM": "ha_Arab_CM",
+ "ha_SD": "ha_Arab_SD",
+ "haw": "haw_Latn_US",
+ "he": "he_Hebr_IL",
+ "hi": "hi_Deva_IN",
+ "hil": "hil_Latn_PH",
+ "hne": "hne_Deva_IN",
+ "hnn": "hnn_Latn_PH",
+ "ho": "ho_Latn_PG",
+ "hoc": "hoc_Deva_IN",
+ "hoj": "hoj_Deva_IN",
+ "hr": "hr_Latn_HR",
+ "ht": "ht_Latn_HT",
+ "hu": "hu_Latn_HU",
+ "hy": "hy_Armn_AM",
+ "ia": "ia_Latn_FR",
+ "ibb": "ibb_Latn_NG",
+ "id": "id_Latn_ID",
+ "ig": "ig_Latn_NG",
+ "ii": "ii_Yiii_CN",
+ "ik": "ik_Latn_US",
+ "ilo": "ilo_Latn_PH",
+ "in": "in_Latn_ID",
+ "inh": "inh_Cyrl_RU",
+ "is": "is_Latn_IS",
+ "it": "it_Latn_IT",
+ "iu": "iu_Cans_CA",
+ "iw": "iw_Hebr_IL",
+ "ja": "ja_Jpan_JP",
+ "jgo": "jgo_Latn_CM",
+ "ji": "ji_Hebr_UA",
+ "jmc": "jmc_Latn_TZ",
+ "jv": "jv_Latn_ID",
+ "jw": "jw_Latn_ID",
+ "ka": "ka_Geor_GE",
+ "kaa": "kaa_Cyrl_UZ",
+ "kab": "kab_Latn_DZ",
+ "kaj": "kaj_Latn_NG",
+ "kam": "kam_Latn_KE",
+ "kbd": "kbd_Cyrl_RU",
+ "kcg": "kcg_Latn_NG",
+ "kde": "kde_Latn_TZ",
+ "kdt": "kdt_Thai_TH",
+ "kea": "kea_Latn_CV",
+ "ken": "ken_Latn_CM",
+ "kfo": "kfo_Latn_CI",
+ "kfr": "kfr_Deva_IN",
+ "kg": "kg_Latn_CD",
+ "kha": "kha_Latn_IN",
+ "khb": "khb_Talu_CN",
+ "khq": "khq_Latn_ML",
+ "kht": "kht_Mymr_IN",
+ "ki": "ki_Latn_KE",
+ "kj": "kj_Latn_NA",
+ "kk": "kk_Cyrl_KZ",
+ "kk_AF": "kk_Arab_AF",
+ "kk_Arab": "kk_Arab_CN",
+ "kk_CN": "kk_Arab_CN",
+ "kk_IR": "kk_Arab_IR",
+ "kk_MN": "kk_Arab_MN",
+ "kkj": "kkj_Latn_CM",
+ "kl": "kl_Latn_GL",
+ "kln": "kln_Latn_KE",
+ "km": "km_Khmr_KH",
+ "kmb": "kmb_Latn_AO",
+ "kn": "kn_Knda_IN",
+ "ko": "ko_Kore_KR",
+ "koi": "koi_Cyrl_RU",
+ "kok": "kok_Deva_IN",
+ "kos": "kos_Latn_FM",
+ "kpe": "kpe_Latn_LR",
+ "krc": "krc_Cyrl_RU",
+ "kri": "kri_Latn_SL",
+ "krl": "krl_Latn_RU",
+ "kru": "kru_Deva_IN",
+ "ks": "ks_Arab_IN",
+ "ksb": "ksb_Latn_TZ",
+ "ksf": "ksf_Latn_CM",
+ "ksh": "ksh_Latn_DE",
+ "ku": "ku_Latn_TR",
+ "ku_Arab": "ku_Arab_IQ",
+ "ku_LB": "ku_Arab_LB",
+ "kum": "kum_Cyrl_RU",
+ "kv": "kv_Cyrl_RU",
+ "kw": "kw_Latn_GB",
+ "ky": "ky_Cyrl_KG",
+ "ky_Arab": "ky_Arab_CN",
+ "ky_CN": "ky_Arab_CN",
+ "ky_Latn": "ky_Latn_TR",
+ "ky_TR": "ky_Latn_TR",
+ "la": "la_Latn_VA",
+ "lag": "lag_Latn_TZ",
+ "lah": "lah_Arab_PK",
+ "lb": "lb_Latn_LU",
+ "lbe": "lbe_Cyrl_RU",
+ "lcp": "lcp_Thai_CN",
+ "lep": "lep_Lepc_IN",
+ "lez": "lez_Cyrl_RU",
+ "lg": "lg_Latn_UG",
+ "li": "li_Latn_NL",
+ "lif": "lif_Deva_NP",
+ "lis": "lis_Lisu_CN",
+ "lki": "lki_Arab_IR",
+ "lkt": "lkt_Latn_US",
+ "lmn": "lmn_Telu_IN",
+ "ln": "ln_Latn_CD",
+ "lo": "lo_Laoo_LA",
+ "lol": "lol_Latn_CD",
+ "lt": "lt_Latn_LT",
+ "lu": "lu_Latn_CD",
+ "lua": "lua_Latn_CD",
+ "luo": "luo_Latn_KE",
+ "luy": "luy_Latn_KE",
+ "lv": "lv_Latn_LV",
+ "lwl": "lwl_Thai_TH",
+ "mad": "mad_Latn_ID",
+ "mag": "mag_Deva_IN",
+ "mai": "mai_Deva_IN",
+ "mak": "mak_Latn_ID",
+ "man": "man_Latn_GM",
+ "man_GN": "man_Nkoo_GN",
+ "man_Nkoo": "man_Nkoo_GN",
+ "mas": "mas_Latn_KE",
+ "mdf": "mdf_Cyrl_RU",
+ "mdh": "mdh_Latn_PH",
+ "mdr": "mdr_Latn_ID",
+ "men": "men_Latn_SL",
+ "mer": "mer_Latn_KE",
+ "mfe": "mfe_Latn_MU",
+ "mg": "mg_Latn_MG",
+ "mgh": "mgh_Latn_MZ",
+ "mgo": "mgo_Latn_CM",
+ "mh": "mh_Latn_MH",
+ "mi": "mi_Latn_NZ",
+ "min": "min_Latn_ID",
+ "mk": "mk_Cyrl_MK",
+ "ml": "ml_Mlym_IN",
+ "mn": "mn_Cyrl_MN",
+ "mn_CN": "mn_Mong_CN",
+ "mn_Mong": "mn_Mong_CN",
+ "mni": "mni_Beng_IN",
+ "mnw": "mnw_Mymr_MM",
+ "mo": "mo_Latn_RO",
+ "mos": "mos_Latn_BF",
+ "mr": "mr_Deva_IN",
+ "ms": "ms_Latn_MY",
+ "ms_CC": "ms_Arab_CC",
+ "ms_ID": "ms_Arab_ID",
+ "mt": "mt_Latn_MT",
+ "mua": "mua_Latn_CM",
+ "mwr": "mwr_Deva_IN",
+ "my": "my_Mymr_MM",
+ "myv": "myv_Cyrl_RU",
+ "na": "na_Latn_NR",
+ "nap": "nap_Latn_IT",
+ "naq": "naq_Latn_NA",
+ "nb": "nb_Latn_NO",
+ "nd": "nd_Latn_ZW",
+ "nds": "nds_Latn_DE",
+ "ne": "ne_Deva_NP",
+ "new": "new_Deva_NP",
+ "ng": "ng_Latn_NA",
+ "niu": "niu_Latn_NU",
+ "nl": "nl_Latn_NL",
+ "nmg": "nmg_Latn_CM",
+ "nn": "nn_Latn_NO",
+ "nnh": "nnh_Latn_CM",
+ "no": "no_Latn_NO",
+ "nod": "nod_Lana_TH",
+ "nr": "nr_Latn_ZA",
+ "nso": "nso_Latn_ZA",
+ "nus": "nus_Latn_SD",
+ "nv": "nv_Latn_US",
+ "ny": "ny_Latn_MW",
+ "nym": "nym_Latn_TZ",
+ "nyn": "nyn_Latn_UG",
+ "oc": "oc_Latn_FR",
+ "om": "om_Latn_ET",
+ "or": "or_Orya_IN",
+ "os": "os_Cyrl_GE",
+ "pa": "pa_Guru_IN",
+ "pa_Arab": "pa_Arab_PK",
+ "pa_PK": "pa_Arab_PK",
+ "pag": "pag_Latn_PH",
+ "pam": "pam_Latn_PH",
+ "pap": "pap_Latn_AW",
+ "pau": "pau_Latn_PW",
+ "pl": "pl_Latn_PL",
+ "pon": "pon_Latn_FM",
+ "prd": "prd_Arab_IR",
+ "ps": "ps_Arab_AF",
+ "pt": "pt_Latn_BR",
+ "qu": "qu_Latn_PE",
+ "raj": "raj_Latn_IN",
+ "rcf": "rcf_Latn_RE",
+ "rej": "rej_Latn_ID",
+ "rjs": "rjs_Deva_NP",
+ "rkt": "rkt_Beng_BD",
+ "rm": "rm_Latn_CH",
+ "rn": "rn_Latn_BI",
+ "ro": "ro_Latn_RO",
+ "rof": "rof_Latn_TZ",
+ "ru": "ru_Cyrl_RU",
+ "rw": "rw_Latn_RW",
+ "rwk": "rwk_Latn_TZ",
+ "sa": "sa_Deva_IN",
+ "saf": "saf_Latn_GH",
+ "sah": "sah_Cyrl_RU",
+ "saq": "saq_Latn_KE",
+ "sas": "sas_Latn_ID",
+ "sat": "sat_Latn_IN",
+ "saz": "saz_Saur_IN",
+ "sbp": "sbp_Latn_TZ",
+ "scn": "scn_Latn_IT",
+ "sco": "sco_Latn_GB",
+ "sd": "sd_Arab_PK",
+ "sd_Deva": "sd_Deva_IN",
+ "sdh": "sdh_Arab_IR",
+ "se": "se_Latn_NO",
+ "seh": "seh_Latn_MZ",
+ "ses": "ses_Latn_ML",
+ "sg": "sg_Latn_CF",
+ "shi": "shi_Tfng_MA",
+ "shn": "shn_Mymr_MM",
+ "si": "si_Sinh_LK",
+ "sid": "sid_Latn_ET",
+ "sk": "sk_Latn_SK",
+ "sl": "sl_Latn_SI",
+ "sm": "sm_Latn_WS",
+ "sma": "sma_Latn_SE",
+ "smj": "smj_Latn_SE",
+ "smn": "smn_Latn_FI",
+ "sms": "sms_Latn_FI",
+ "sn": "sn_Latn_ZW",
+ "snk": "snk_Latn_ML",
+ "so": "so_Latn_SO",
+ "sq": "sq_Latn_AL",
+ "sr": "sr_Cyrl_RS",
+ "sr_ME": "sr_Latn_ME",
+ "sr_RO": "sr_Latn_RO",
+ "sr_RU": "sr_Latn_RU",
+ "sr_TR": "sr_Latn_TR",
+ "srn": "srn_Latn_SR",
+ "srr": "srr_Latn_SN",
+ "ss": "ss_Latn_ZA",
+ "ssy": "ssy_Latn_ER",
+ "st": "st_Latn_ZA",
+ "su": "su_Latn_ID",
+ "suk": "suk_Latn_TZ",
+ "sus": "sus_Latn_GN",
+ "sv": "sv_Latn_SE",
+ "sw": "sw_Latn_TZ",
+ "swb": "swb_Arab_YT",
+ "swc": "swc_Latn_CD",
+ "syl": "syl_Beng_BD",
+ "syr": "syr_Syrc_IQ",
+ "ta": "ta_Taml_IN",
+ "tbw": "tbw_Latn_PH",
+ "tcy": "tcy_Knda_IN",
+ "tdd": "tdd_Tale_CN",
+ "te": "te_Telu_IN",
+ "tem": "tem_Latn_SL",
+ "teo": "teo_Latn_UG",
+ "tet": "tet_Latn_TL",
+ "tg": "tg_Cyrl_TJ",
+ "tg_Arab": "tg_Arab_PK",
+ "tg_PK": "tg_Arab_PK",
+ "th": "th_Thai_TH",
+ "ti": "ti_Ethi_ET",
+ "tig": "tig_Ethi_ER",
+ "tiv": "tiv_Latn_NG",
+ "tk": "tk_Latn_TM",
+ "tkl": "tkl_Latn_TK",
+ "tl": "tl_Latn_PH",
+ "tmh": "tmh_Latn_NE",
+ "tn": "tn_Latn_ZA",
+ "to": "to_Latn_TO",
+ "tpi": "tpi_Latn_PG",
+ "tr": "tr_Latn_TR",
+ "trv": "trv_Latn_TW",
+ "ts": "ts_Latn_ZA",
+ "tsg": "tsg_Latn_PH",
+ "tt": "tt_Cyrl_RU",
+ "tts": "tts_Thai_TH",
+ "tum": "tum_Latn_MW",
+ "tvl": "tvl_Latn_TV",
+ "twq": "twq_Latn_NE",
+ "ty": "ty_Latn_PF",
+ "tyv": "tyv_Cyrl_RU",
+ "tzm": "tzm_Latn_MA",
+ "udm": "udm_Cyrl_RU",
+ "ug": "ug_Arab_CN",
+ "ug_Cyrl": "ug_Cyrl_KZ",
+ "ug_KZ": "ug_Cyrl_KZ",
+ "ug_MN": "ug_Cyrl_MN",
+ "uk": "uk_Cyrl_UA",
+ "uli": "uli_Latn_FM",
+ "umb": "umb_Latn_AO",
+ "und": "en_Latn_US",
+ "und_AD": "ca_Latn_AD",
+ "und_AE": "ar_Arab_AE",
+ "und_AF": "fa_Arab_AF",
+ "und_AL": "sq_Latn_AL",
+ "und_AM": "hy_Armn_AM",
+ "und_AO": "pt_Latn_AO",
+ "und_AQ": "und_Latn_AQ",
+ "und_AR": "es_Latn_AR",
+ "und_Arab": "ar_Arab_EG",
+ "und_Arab_CC": "ms_Arab_CC",
+ "und_Arab_CN": "ug_Arab_CN",
+ "und_Arab_GB": "ks_Arab_GB",
+ "und_Arab_ID": "ms_Arab_ID",
+ "und_Arab_IN": "ur_Arab_IN",
+ "und_Arab_KH": "cja_Arab_KH",
+ "und_Arab_MN": "kk_Arab_MN",
+ "und_Arab_MU": "ur_Arab_MU",
+ "und_Arab_NG": "ha_Arab_NG",
+ "und_Arab_PK": "ur_Arab_PK",
+ "und_Arab_TJ": "fa_Arab_TJ",
+ "und_Arab_TR": "zza_Arab_TR",
+ "und_Arab_YT": "swb_Arab_YT",
+ "und_Armi": "arc_Armi_IR",
+ "und_Armn": "hy_Armn_AM",
+ "und_AS": "sm_Latn_AS",
+ "und_AT": "de_Latn_AT",
+ "und_Avst": "ae_Avst_IR",
+ "und_AW": "nl_Latn_AW",
+ "und_AX": "sv_Latn_AX",
+ "und_AZ": "az_Latn_AZ",
+ "und_BA": "bs_Latn_BA",
+ "und_Bali": "ban_Bali_ID",
+ "und_Bamu": "bax_Bamu_CM",
+ "und_Batk": "bbc_Batk_ID",
+ "und_BD": "bn_Beng_BD",
+ "und_BE": "nl_Latn_BE",
+ "und_Beng": "bn_Beng_BD",
+ "und_BF": "fr_Latn_BF",
+ "und_BG": "bg_Cyrl_BG",
+ "und_BH": "ar_Arab_BH",
+ "und_BI": "rn_Latn_BI",
+ "und_BJ": "fr_Latn_BJ",
+ "und_BL": "fr_Latn_BL",
+ "und_BN": "ms_Latn_BN",
+ "und_BO": "es_Latn_BO",
+ "und_Bopo": "zh_Bopo_TW",
+ "und_BQ": "pap_Latn_BQ",
+ "und_BR": "pt_Latn_BR",
+ "und_Brah": "pra_Brah_IN",
+ "und_Brai": "und_Brai_FR",
+ "und_BT": "dz_Tibt_BT",
+ "und_Bugi": "bug_Bugi_ID",
+ "und_Buhd": "bku_Buhd_PH",
+ "und_BV": "und_Latn_BV",
+ "und_BY": "be_Cyrl_BY",
+ "und_Cakm": "ccp_Cakm_BD",
+ "und_Cans": "cr_Cans_CA",
+ "und_Cari": "xcr_Cari_TR",
+ "und_CD": "sw_Latn_CD",
+ "und_CF": "fr_Latn_CF",
+ "und_CG": "fr_Latn_CG",
+ "und_CH": "de_Latn_CH",
+ "und_Cham": "cjm_Cham_VN",
+ "und_Cher": "chr_Cher_US",
+ "und_CI": "fr_Latn_CI",
+ "und_CL": "es_Latn_CL",
+ "und_CM": "fr_Latn_CM",
+ "und_CN": "zh_Hans_CN",
+ "und_CO": "es_Latn_CO",
+ "und_Copt": "cop_Copt_EG",
+ "und_CP": "und_Latn_CP",
+ "und_Cprt": "grc_Cprt_CY",
+ "und_CR": "es_Latn_CR",
+ "und_CU": "es_Latn_CU",
+ "und_CV": "pt_Latn_CV",
+ "und_CW": "pap_Latn_CW",
+ "und_CY": "el_Grek_CY",
+ "und_Cyrl": "ru_Cyrl_RU",
+ "und_Cyrl_AL": "mk_Cyrl_AL",
+ "und_Cyrl_BA": "sr_Cyrl_BA",
+ "und_Cyrl_GE": "ab_Cyrl_GE",
+ "und_Cyrl_GR": "mk_Cyrl_GR",
+ "und_Cyrl_MD": "uk_Cyrl_MD",
+ "und_Cyrl_PL": "be_Cyrl_PL",
+ "und_Cyrl_RO": "bg_Cyrl_RO",
+ "und_Cyrl_SK": "uk_Cyrl_SK",
+ "und_Cyrl_TR": "kbd_Cyrl_TR",
+ "und_Cyrl_XK": "sr_Cyrl_XK",
+ "und_CZ": "cs_Latn_CZ",
+ "und_DE": "de_Latn_DE",
+ "und_Deva": "hi_Deva_IN",
+ "und_Deva_BT": "ne_Deva_BT",
+ "und_Deva_MU": "bho_Deva_MU",
+ "und_Deva_PK": "btv_Deva_PK",
+ "und_DJ": "aa_Latn_DJ",
+ "und_DK": "da_Latn_DK",
+ "und_DO": "es_Latn_DO",
+ "und_DZ": "ar_Arab_DZ",
+ "und_EA": "es_Latn_EA",
+ "und_EC": "es_Latn_EC",
+ "und_EE": "et_Latn_EE",
+ "und_EG": "ar_Arab_EG",
+ "und_Egyp": "egy_Egyp_EG",
+ "und_EH": "ar_Arab_EH",
+ "und_ER": "ti_Ethi_ER",
+ "und_ES": "es_Latn_ES",
+ "und_ET": "am_Ethi_ET",
+ "und_Ethi": "am_Ethi_ET",
+ "und_FI": "fi_Latn_FI",
+ "und_FM": "chk_Latn_FM",
+ "und_FO": "fo_Latn_FO",
+ "und_FR": "fr_Latn_FR",
+ "und_GA": "fr_Latn_GA",
+ "und_GE": "ka_Geor_GE",
+ "und_Geor": "ka_Geor_GE",
+ "und_GF": "fr_Latn_GF",
+ "und_GH": "ak_Latn_GH",
+ "und_GL": "kl_Latn_GL",
+ "und_Glag": "cu_Glag_BG",
+ "und_GN": "fr_Latn_GN",
+ "und_Goth": "got_Goth_UA",
+ "und_GP": "fr_Latn_GP",
+ "und_GQ": "es_Latn_GQ",
+ "und_GR": "el_Grek_GR",
+ "und_Grek": "el_Grek_GR",
+ "und_GS": "und_Latn_GS",
+ "und_GT": "es_Latn_GT",
+ "und_Gujr": "gu_Gujr_IN",
+ "und_Guru": "pa_Guru_IN",
+ "und_GW": "pt_Latn_GW",
+ "und_Hang": "ko_Hang_KR",
+ "und_Hani": "zh_Hani_CN",
+ "und_Hano": "hnn_Hano_PH",
+ "und_Hans": "zh_Hans_CN",
+ "und_Hant": "zh_Hant_TW",
+ "und_Hebr": "he_Hebr_IL",
+ "und_Hebr_CA": "yi_Hebr_CA",
+ "und_Hebr_GB": "yi_Hebr_GB",
+ "und_Hebr_SE": "yi_Hebr_SE",
+ "und_Hebr_UA": "yi_Hebr_UA",
+ "und_Hebr_US": "yi_Hebr_US",
+ "und_Hira": "ja_Hira_JP",
+ "und_HK": "zh_Hant_HK",
+ "und_HM": "und_Latn_HM",
+ "und_HN": "es_Latn_HN",
+ "und_HR": "hr_Latn_HR",
+ "und_HT": "ht_Latn_HT",
+ "und_HU": "hu_Latn_HU",
+ "und_IC": "es_Latn_IC",
+ "und_ID": "id_Latn_ID",
+ "und_IL": "he_Hebr_IL",
+ "und_IN": "hi_Deva_IN",
+ "und_IQ": "ar_Arab_IQ",
+ "und_IR": "fa_Arab_IR",
+ "und_IS": "is_Latn_IS",
+ "und_IT": "it_Latn_IT",
+ "und_Ital": "ett_Ital_IT",
+ "und_Java": "jv_Java_ID",
+ "und_JO": "ar_Arab_JO",
+ "und_JP": "ja_Jpan_JP",
+ "und_Jpan": "ja_Jpan_JP",
+ "und_Kali": "eky_Kali_MM",
+ "und_Kana": "ja_Kana_JP",
+ "und_KG": "ky_Cyrl_KG",
+ "und_KH": "km_Khmr_KH",
+ "und_Khar": "pra_Khar_PK",
+ "und_Khmr": "km_Khmr_KH",
+ "und_KM": "ar_Arab_KM",
+ "und_Knda": "kn_Knda_IN",
+ "und_Kore": "ko_Kore_KR",
+ "und_KP": "ko_Kore_KP",
+ "und_KR": "ko_Kore_KR",
+ "und_Kthi": "bh_Kthi_IN",
+ "und_KW": "ar_Arab_KW",
+ "und_KZ": "ru_Cyrl_KZ",
+ "und_LA": "lo_Laoo_LA",
+ "und_Lana": "nod_Lana_TH",
+ "und_Laoo": "lo_Laoo_LA",
+ "und_Latn_AF": "tk_Latn_AF",
+ "und_Latn_AM": "az_Latn_AM",
+ "und_Latn_BG": "tr_Latn_BG",
+ "und_Latn_CN": "za_Latn_CN",
+ "und_Latn_CY": "tr_Latn_CY",
+ "und_Latn_DZ": "fr_Latn_DZ",
+ "und_Latn_ET": "en_Latn_ET",
+ "und_Latn_GE": "ku_Latn_GE",
+ "und_Latn_GR": "tr_Latn_GR",
+ "und_Latn_IL": "ro_Latn_IL",
+ "und_Latn_IR": "tk_Latn_IR",
+ "und_Latn_KM": "fr_Latn_KM",
+ "und_Latn_KZ": "de_Latn_KZ",
+ "und_Latn_LB": "fr_Latn_LB",
+ "und_Latn_MA": "fr_Latn_MA",
+ "und_Latn_MK": "sq_Latn_MK",
+ "und_Latn_MO": "pt_Latn_MO",
+ "und_Latn_MR": "fr_Latn_MR",
+ "und_Latn_RU": "krl_Latn_RU",
+ "und_Latn_SY": "fr_Latn_SY",
+ "und_Latn_TN": "fr_Latn_TN",
+ "und_Latn_TW": "trv_Latn_TW",
+ "und_Latn_UA": "pl_Latn_UA",
+ "und_LB": "ar_Arab_LB",
+ "und_Lepc": "lep_Lepc_IN",
+ "und_LI": "de_Latn_LI",
+ "und_Limb": "lif_Limb_IN",
+ "und_Linb": "grc_Linb_GR",
+ "und_Lisu": "lis_Lisu_CN",
+ "und_LK": "si_Sinh_LK",
+ "und_LS": "st_Latn_LS",
+ "und_LT": "lt_Latn_LT",
+ "und_LU": "fr_Latn_LU",
+ "und_LV": "lv_Latn_LV",
+ "und_LY": "ar_Arab_LY",
+ "und_Lyci": "xlc_Lyci_TR",
+ "und_Lydi": "xld_Lydi_TR",
+ "und_MA": "ar_Arab_MA",
+ "und_Mand": "myz_Mand_IR",
+ "und_MC": "fr_Latn_MC",
+ "und_MD": "ro_Latn_MD",
+ "und_ME": "sr_Latn_ME",
+ "und_Merc": "xmr_Merc_SD",
+ "und_Mero": "xmr_Mero_SD",
+ "und_MF": "fr_Latn_MF",
+ "und_MG": "mg_Latn_MG",
+ "und_MK": "mk_Cyrl_MK",
+ "und_ML": "bm_Latn_ML",
+ "und_Mlym": "ml_Mlym_IN",
+ "und_MM": "my_Mymr_MM",
+ "und_MN": "mn_Cyrl_MN",
+ "und_MO": "zh_Hant_MO",
+ "und_Mong": "mn_Mong_CN",
+ "und_MQ": "fr_Latn_MQ",
+ "und_MR": "ar_Arab_MR",
+ "und_MT": "mt_Latn_MT",
+ "und_Mtei": "mni_Mtei_IN",
+ "und_MU": "mfe_Latn_MU",
+ "und_MV": "dv_Thaa_MV",
+ "und_MX": "es_Latn_MX",
+ "und_MY": "ms_Latn_MY",
+ "und_Mymr": "my_Mymr_MM",
+ "und_Mymr_IN": "kht_Mymr_IN",
+ "und_Mymr_TH": "mnw_Mymr_TH",
+ "und_MZ": "pt_Latn_MZ",
+ "und_NA": "af_Latn_NA",
+ "und_NC": "fr_Latn_NC",
+ "und_NE": "ha_Latn_NE",
+ "und_NI": "es_Latn_NI",
+ "und_Nkoo": "man_Nkoo_GN",
+ "und_NL": "nl_Latn_NL",
+ "und_NO": "nb_Latn_NO",
+ "und_NP": "ne_Deva_NP",
+ "und_Ogam": "sga_Ogam_IE",
+ "und_Olck": "sat_Olck_IN",
+ "und_OM": "ar_Arab_OM",
+ "und_Orkh": "otk_Orkh_MN",
+ "und_Orya": "or_Orya_IN",
+ "und_Osma": "so_Osma_SO",
+ "und_PA": "es_Latn_PA",
+ "und_PE": "es_Latn_PE",
+ "und_PF": "fr_Latn_PF",
+ "und_PG": "tpi_Latn_PG",
+ "und_PH": "fil_Latn_PH",
+ "und_Phag": "lzh_Phag_CN",
+ "und_Phli": "pal_Phli_IR",
+ "und_Phnx": "phn_Phnx_LB",
+ "und_PK": "ur_Arab_PK",
+ "und_PL": "pl_Latn_PL",
+ "und_Plrd": "hmd_Plrd_CN",
+ "und_PM": "fr_Latn_PM",
+ "und_PR": "es_Latn_PR",
+ "und_Prti": "xpr_Prti_IR",
+ "und_PS": "ar_Arab_PS",
+ "und_PT": "pt_Latn_PT",
+ "und_PW": "pau_Latn_PW",
+ "und_PY": "gn_Latn_PY",
+ "und_QA": "ar_Arab_QA",
+ "und_RE": "fr_Latn_RE",
+ "und_Rjng": "rej_Rjng_ID",
+ "und_RO": "ro_Latn_RO",
+ "und_RS": "sr_Cyrl_RS",
+ "und_RU": "ru_Cyrl_RU",
+ "und_Runr": "non_Runr_SE",
+ "und_RW": "rw_Latn_RW",
+ "und_SA": "ar_Arab_SA",
+ "und_Samr": "smp_Samr_IL",
+ "und_Sarb": "xsa_Sarb_YE",
+ "und_Saur": "saz_Saur_IN",
+ "und_SC": "fr_Latn_SC",
+ "und_SD": "ar_Arab_SD",
+ "und_SE": "sv_Latn_SE",
+ "und_Shaw": "en_Shaw_GB",
+ "und_Shrd": "sa_Shrd_IN",
+ "und_SI": "sl_Latn_SI",
+ "und_Sinh": "si_Sinh_LK",
+ "und_SJ": "nb_Latn_SJ",
+ "und_SK": "sk_Latn_SK",
+ "und_SM": "it_Latn_SM",
+ "und_SN": "fr_Latn_SN",
+ "und_SO": "so_Latn_SO",
+ "und_Sora": "srb_Sora_IN",
+ "und_SR": "nl_Latn_SR",
+ "und_ST": "pt_Latn_ST",
+ "und_Sund": "su_Sund_ID",
+ "und_SV": "es_Latn_SV",
+ "und_SY": "ar_Arab_SY",
+ "und_Sylo": "syl_Sylo_BD",
+ "und_Syrc": "syr_Syrc_IQ",
+ "und_Tagb": "tbw_Tagb_PH",
+ "und_Takr": "doi_Takr_IN",
+ "und_Tale": "tdd_Tale_CN",
+ "und_Talu": "khb_Talu_CN",
+ "und_Taml": "ta_Taml_IN",
+ "und_Tavt": "blt_Tavt_VN",
+ "und_TD": "fr_Latn_TD",
+ "und_Telu": "te_Telu_IN",
+ "und_TF": "fr_Latn_TF",
+ "und_Tfng": "zgh_Tfng_MA",
+ "und_TG": "fr_Latn_TG",
+ "und_Tglg": "fil_Tglg_PH",
+ "und_TH": "th_Thai_TH",
+ "und_Thaa": "dv_Thaa_MV",
+ "und_Thai": "th_Thai_TH",
+ "und_Thai_CN": "lcp_Thai_CN",
+ "und_Thai_KH": "kdt_Thai_KH",
+ "und_Thai_LA": "kdt_Thai_LA",
+ "und_Tibt": "bo_Tibt_CN",
+ "und_TJ": "tg_Cyrl_TJ",
+ "und_TK": "tkl_Latn_TK",
+ "und_TL": "pt_Latn_TL",
+ "und_TM": "tk_Latn_TM",
+ "und_TN": "ar_Arab_TN",
+ "und_TO": "to_Latn_TO",
+ "und_TR": "tr_Latn_TR",
+ "und_TV": "tvl_Latn_TV",
+ "und_TW": "zh_Hant_TW",
+ "und_TZ": "sw_Latn_TZ",
+ "und_UA": "uk_Cyrl_UA",
+ "und_UG": "sw_Latn_UG",
+ "und_Ugar": "uga_Ugar_SY",
+ "und_UY": "es_Latn_UY",
+ "und_UZ": "uz_Latn_UZ",
+ "und_VA": "la_Latn_VA",
+ "und_Vaii": "vai_Vaii_LR",
+ "und_VE": "es_Latn_VE",
+ "und_VN": "vi_Latn_VN",
+ "und_VU": "bi_Latn_VU",
+ "und_WF": "fr_Latn_WF",
+ "und_WS": "sm_Latn_WS",
+ "und_XK": "sq_Latn_XK",
+ "und_Xpeo": "peo_Xpeo_IR",
+ "und_Xsux": "akk_Xsux_IQ",
+ "und_YE": "ar_Arab_YE",
+ "und_Yiii": "ii_Yiii_CN",
+ "und_YT": "fr_Latn_YT",
+ "unr": "unr_Beng_IN",
+ "unr_Deva": "unr_Deva_NP",
+ "unr_NP": "unr_Deva_NP",
+ "unx": "unx_Beng_IN",
+ "ur": "ur_Arab_PK",
+ "uz": "uz_Latn_UZ",
+ "uz_AF": "uz_Arab_AF",
+ "uz_Arab": "uz_Arab_AF",
+ "uz_CN": "uz_Cyrl_CN",
+ "vai": "vai_Vaii_LR",
+ "ve": "ve_Latn_ZA",
+ "vi": "vi_Latn_VN",
+ "vo": "vo_Latn_001",
+ "vun": "vun_Latn_TZ",
+ "wa": "wa_Latn_BE",
+ "wae": "wae_Latn_CH",
+ "wal": "wal_Ethi_ET",
+ "war": "war_Latn_PH",
+ "wo": "wo_Latn_SN",
+ "xh": "xh_Latn_ZA",
+ "xog": "xog_Latn_UG",
+ "xsr": "xsr_Deva_NP",
+ "yao": "yao_Latn_MZ",
+ "yap": "yap_Latn_FM",
+ "yav": "yav_Latn_CM",
+ "yi": "yi_Hebr_UA",
+ "yo": "yo_Latn_NG",
+ "za": "za_Latn_CN",
+ "zgh": "zgh_Tfng_MA",
+ "zh": "zh_Hans_CN",
+ "zh_AU": "zh_Hant_AU",
+ "zh_BN": "zh_Hant_BN",
+ "zh_GB": "zh_Hant_GB",
+ "zh_GF": "zh_Hant_GF",
+ "zh_Hant": "zh_Hant_TW",
+ "zh_HK": "zh_Hant_HK",
+ "zh_ID": "zh_Hant_ID",
+ "zh_MO": "zh_Hant_MO",
+ "zh_MY": "zh_Hant_MY",
+ "zh_PA": "zh_Hant_PA",
+ "zh_PF": "zh_Hant_PF",
+ "zh_PH": "zh_Hant_PH",
+ "zh_SR": "zh_Hant_SR",
+ "zh_TH": "zh_Hant_TH",
+ "zh_TW": "zh_Hant_TW",
+ "zh_US": "zh_Hant_US",
+ "zh_VN": "zh_Hant_VN",
+ "zu": "zu_Latn_ZA",
+ "zza": "zza_Arab_TR"
+ }
+ }
+});
+
+// weekData
+Globalize.load({
+ "supplemental": {
+ "version": {
+ "_cldrVersion": "24",
+ "_number": "$Revision: 9270 $"
+ },
+ "generation": {
+ "_date": "$Date: 2013-08-25 16:44:03 -0500 (Sun, 25 Aug 2013) $"
+ },
+ "weekData": {
+ "minDays": {
+ "001": "1",
+ "AD": "4",
+ "AN": "4",
+ "AT": "4",
+ "AX": "4",
+ "BE": "4",
+ "BG": "4",
+ "CH": "4",
+ "CZ": "4",
+ "DE": "4",
+ "DK": "4",
+ "EE": "4",
+ "ES": "4",
+ "FI": "4",
+ "FJ": "4",
+ "FO": "4",
+ "FR": "4",
+ "GB": "4",
+ "GF": "4",
+ "GG": "4",
+ "GI": "4",
+ "GP": "4",
+ "GR": "4",
+ "GU": "1",
+ "HU": "4",
+ "IE": "4",
+ "IM": "4",
+ "IS": "4",
+ "IT": "4",
+ "JE": "4",
+ "LI": "4",
+ "LT": "4",
+ "LU": "4",
+ "MC": "4",
+ "MQ": "4",
+ "NL": "4",
+ "NO": "4",
+ "PL": "4",
+ "PT": "4",
+ "RE": "4",
+ "SE": "4",
+ "SJ": "4",
+ "SK": "4",
+ "SM": "4",
+ "UM": "1",
+ "US": "1",
+ "VA": "4",
+ "VI": "1"
+ },
+ "firstDay": {
+ "001": "mon",
+ "AD": "mon",
+ "AE": "sat",
+ "AF": "sat",
+ "AG": "sun",
+ "AI": "mon",
+ "AL": "mon",
+ "AM": "mon",
+ "AN": "mon",
+ "AR": "sun",
+ "AS": "sun",
+ "AT": "mon",
+ "AU": "sun",
+ "AX": "mon",
+ "AZ": "mon",
+ "BA": "mon",
+ "BD": "fri",
+ "BE": "mon",
+ "BG": "mon",
+ "BH": "sat",
+ "BM": "mon",
+ "BN": "mon",
+ "BR": "sun",
+ "BS": "sun",
+ "BT": "sun",
+ "BW": "sun",
+ "BY": "sun",
+ "BZ": "sun",
+ "CA": "sun",
+ "CH": "mon",
+ "CL": "mon",
+ "CM": "mon",
+ "CN": "sun",
+ "CO": "sun",
+ "CR": "mon",
+ "CY": "mon",
+ "CZ": "mon",
+ "DE": "mon",
+ "DJ": "sat",
+ "DK": "mon",
+ "DM": "sun",
+ "DO": "sun",
+ "DZ": "sat",
+ "EC": "mon",
+ "EE": "mon",
+ "EG": "sat",
+ "ES": "mon",
+ "ET": "sun",
+ "FI": "mon",
+ "FJ": "mon",
+ "FO": "mon",
+ "FR": "mon",
+ "GB": "mon",
+ "GE": "mon",
+ "GF": "mon",
+ "GP": "mon",
+ "GR": "mon",
+ "GT": "sun",
+ "GU": "sun",
+ "HK": "sun",
+ "HN": "sun",
+ "HR": "mon",
+ "HU": "mon",
+ "ID": "sun",
+ "IE": "sun",
+ "IL": "sun",
+ "IN": "sun",
+ "IQ": "sat",
+ "IR": "sat",
+ "IS": "mon",
+ "IT": "mon",
+ "JM": "sun",
+ "JO": "sat",
+ "JP": "sun",
+ "KE": "sun",
+ "KG": "mon",
+ "KH": "sun",
+ "KR": "sun",
+ "KW": "sat",
+ "KZ": "mon",
+ "LA": "sun",
+ "LB": "mon",
+ "LI": "mon",
+ "LK": "mon",
+ "LT": "mon",
+ "LU": "mon",
+ "LV": "mon",
+ "LY": "sat",
+ "MA": "sat",
+ "MC": "mon",
+ "MD": "mon",
+ "ME": "mon",
+ "MH": "sun",
+ "MK": "mon",
+ "MM": "sun",
+ "MN": "mon",
+ "MO": "sun",
+ "MQ": "mon",
+ "MT": "sun",
+ "MV": "fri",
+ "MX": "sun",
+ "MY": "mon",
+ "MZ": "sun",
+ "NI": "sun",
+ "NL": "mon",
+ "NO": "mon",
+ "NP": "sun",
+ "NZ": "sun",
+ "OM": "sat",
+ "PA": "sun",
+ "PE": "sun",
+ "PH": "sun",
+ "PK": "sun",
+ "PL": "mon",
+ "PR": "sun",
+ "PT": "mon",
+ "PY": "sun",
+ "QA": "sat",
+ "RE": "mon",
+ "RO": "mon",
+ "RS": "mon",
+ "RU": "mon",
+ "SA": "sun",
+ "SD": "sat",
+ "SE": "mon",
+ "SG": "sun",
+ "SI": "mon",
+ "SK": "mon",
+ "SM": "mon",
+ "SV": "sun",
+ "SY": "sat",
+ "TH": "sun",
+ "TJ": "mon",
+ "TM": "mon",
+ "TN": "sun",
+ "TR": "mon",
+ "TT": "sun",
+ "TW": "sun",
+ "UA": "mon",
+ "UM": "sun",
+ "US": "sun",
+ "UY": "mon",
+ "UZ": "mon",
+ "VA": "mon",
+ "VE": "sun",
+ "VI": "sun",
+ "VN": "mon",
+ "WS": "sun",
+ "XK": "mon",
+ "YE": "sun",
+ "ZA": "sun",
+ "ZW": "sun"
+ },
+ "firstDay-alt-variant": {
+ "GB": "sun"
+ },
+ "weekendStart": {
+ "001": "sat",
+ "AE": "fri",
+ "AF": "thu",
+ "BH": "fri",
+ "DZ": "thu",
+ "EG": "fri",
+ "IL": "fri",
+ "IN": "sun",
+ "IQ": "fri",
+ "IR": "thu",
+ "JO": "fri",
+ "KW": "fri",
+ "LY": "fri",
+ "MA": "fri",
+ "OM": "thu",
+ "QA": "fri",
+ "SA": "fri",
+ "SD": "fri",
+ "SY": "fri",
+ "TN": "fri",
+ "YE": "fri"
+ },
+ "weekendEnd": {
+ "001": "sun",
+ "AE": "sat",
+ "AF": "fri",
+ "BH": "sat",
+ "DZ": "fri",
+ "EG": "sat",
+ "IL": "sat",
+ "IQ": "sat",
+ "IR": "fri",
+ "JO": "sat",
+ "KW": "sat",
+ "LY": "sat",
+ "MA": "sat",
+ "OM": "fri",
+ "QA": "sat",
+ "SA": "sat",
+ "SD": "sat",
+ "SY": "sat",
+ "TN": "sat",
+ "YE": "sat"
+ }
+ }
+ }
+});
+
+// timeData
+Globalize.load({
+ "supplemental": {
+ "version": {
+ "_cldrVersion": "24",
+ "_number": "$Revision: 9270 $"
+ },
+ "generation": {
+ "_date": "$Date: 2013-08-25 16:44:03 -0500 (Sun, 25 Aug 2013) $"
+ },
+ "timeData": {
+ "001": {
+ "_allowed": "H h",
+ "_preferred": "H"
+ },
+ "AD": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "AE": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "AG": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "AL": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "AM": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "AO": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "AS": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "AT": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "AU": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "AW": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "AX": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "BB": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BD": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BE": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "BF": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "BH": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BJ": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "BL": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "BM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BN": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BR": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "BS": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BT": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "BW": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "CA": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "CD": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "CI": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "CN": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "CO": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "CP": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "CV": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "CY": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "CZ": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "DE": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "DJ": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "DK": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "DM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "DZ": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "EE": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "EG": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "EH": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "ER": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "ET": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "FI": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "FJ": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "FM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "FR": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "GA": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "GD": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "GF": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "GH": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "GL": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "GM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "GN": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "GP": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "GR": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "GU": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "GW": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "GY": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "HK": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "HR": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "IL": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "IN": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "IQ": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "IS": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "IT": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "JM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "JO": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "JP": {
+ "_allowed": "H K h",
+ "_preferred": "H"
+ },
+ "KH": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "KI": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "KN": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "KP": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "KR": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "KW": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "KY": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "LB": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "LC": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "LR": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "LS": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "LY": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MA": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MC": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "MD": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "MF": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "MH": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "ML": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "MO": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MP": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MQ": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "MR": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MW": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MY": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "MZ": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "NA": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "NC": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "NE": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "NG": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "NL": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "NZ": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "OM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "PG": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "PK": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "PM": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "PR": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "PS": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "PT": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "PW": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "QA": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "RE": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "RO": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "RU": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SA": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SB": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SD": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SE": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SG": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SI": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SJ": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SK": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SL": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SM": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SO": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SR": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SS": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "ST": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "SY": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "SZ": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "TC": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "TD": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "TG": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "TN": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "TR": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "TT": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "TW": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "UM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "US": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "VC": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "VG": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "VI": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "VU": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "WF": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "WS": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "YE": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "YT": {
+ "_allowed": "H",
+ "_preferred": "H"
+ },
+ "ZA": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "ZM": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ },
+ "ZW": {
+ "_allowed": "H h",
+ "_preferred": "h"
+ }
+ }
+ }
+});
+
+/**
+ * jQuery UI translation data
+ */
+var regions = {
+ "en": {
+ "closeText": "Done",
+ "prevText": "Prev",
+ "nextText": "Next",
+ "currentText": "Today",
+ "weekHeader": "Wk",
+ "dateFormat": "d",
+ "datePickerRole": "date picker"
+ },
+ "af": {
+ "closeText": "Selekteer",
+ "prevText": "Vorige",
+ "nextText": "Volgende",
+ "currentText": "Vandag",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "zh-TW": {
+ "closeText": "\u95dc\u9589",
+ "prevText": "&#x3c;\u4e0a\u6708",
+ "nextText": "\u4e0b\u6708&#x3e;",
+ "currentText": "\u4eca\u5929",
+ "weekHeader": "\u5468",
+ "dateFormat": "d"
+ },
+ "ar": {
+ "closeText": "\u0625\u063a\u0644\u0627\u0642",
+ "prevText": "&#x3c;\u0627\u0644\u0633\u0627\u0628\u0642",
+ "nextText": "\u0627\u0644\u062a\u0627\u0644\u064a&#x3e;",
+ "currentText": "\u0627\u0644\u064a\u0648\u0645",
+ "weekHeader": "\u0623\u0633\u0628\u0648\u0639",
+ "dateFormat": "d"
+ },
+ "az": {
+ "closeText": "Ba\u011fla",
+ "prevText": "&#x3c;Geri",
+ "nextText": "\u0130r\u0259li&#x3e;",
+ "currentText": "Bug\u00fcn",
+ "weekHeader": "Hf",
+ "dateFormat": "d"
+ },
+ "bg": {
+ "closeText": "\u0437\u0430\u0442\u0432\u043e\u0440\u0438",
+ "prevText": "&#x3c;\u043d\u0430\u0437\u0430\u0434",
+ "nextText": "\u043d\u0430\u043f\u0440\u0435\u0434&#x3e;",
+ "currentText": "\u0434\u043d\u0435\u0441",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "bs": {
+ "closeText": "Zatvori",
+ "prevText": "&#x3c;",
+ "nextText": "&#x3e;",
+ "currentText": "Danas",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "ca": {
+ "closeText": "Tancar",
+ "prevText": "&#x3c;Ant",
+ "nextText": "Seg&#x3e;",
+ "currentText": "Avui",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "cs": {
+ "closeText": "Zav\u0159\u00edt",
+ "prevText": "&#x3c;D\u0159\u00edve",
+ "nextText": "Pozd\u011bji&#x3e;",
+ "currentText": "Nyn\u00ed",
+ "weekHeader": "T\u00fdd",
+ "dateFormat": "d"
+ },
+ "da": {
+ "closeText": "Luk",
+ "prevText": "&#x3c;Forrige",
+ "nextText": "N\u00e6ste&#x3e;",
+ "currentText": "Idag",
+ "weekHeader": "Uge",
+ "dateFormat": "d"
+ },
+ "de": {
+ "closeText": "Schlie\u00dfen",
+ "prevText": "&#x3c;Zur\u00fcck",
+ "nextText": "Vor&#x3e;",
+ "currentText": "Heute",
+ "weekHeader": "Wo",
+ "dateFormat": "d"
+ },
+ "el": {
+ "closeText": "\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf",
+ "prevText": "\u03a0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf\u03c2",
+ "nextText": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf\u03c2",
+ "currentText": "\u03a4\u03c1\u03ad\u03c7\u03c9\u03bd \u039c\u03ae\u03bd\u03b1\u03c2",
+ "weekHeader": "\u0395\u03b2\u03b4",
+ "dateFormat": "d"
+ },
+ "en-GB": {
+ "closeText": "Done",
+ "prevText": "Prev",
+ "nextText": "Next",
+ "currentText": "Today",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "eo": {
+ "closeText": "Fermi",
+ "prevText": "&lt;Anta",
+ "nextText": "Sekv&gt;",
+ "currentText": "Nuna",
+ "weekHeader": "Sb",
+ "dateFormat": "dd/MM/yyyy"
+ },
+ "es": {
+ "closeText": "Cerrar",
+ "prevText": "&#x3c;Ant",
+ "nextText": "Sig&#x3e;",
+ "currentText": "Hoy",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "et": {
+ "closeText": "Sulge",
+ "prevText": "Eelnev",
+ "nextText": "J\u00e4rgnev",
+ "currentText": "T\u00e4na",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "eu": {
+ "closeText": "Egina",
+ "prevText": "&#x3c;Aur",
+ "nextText": "Hur&#x3e;",
+ "currentText": "Gaur",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "fa": {
+ "closeText": "\u0628\u0633\u062a\u0646",
+ "prevText": "&#x3c;\u0642\u0628\u0644\u064a",
+ "nextText": "\u0628\u0639\u062f\u064a&#x3e;",
+ "currentText": "\u0627\u0645\u0631\u0648\u0632",
+ "weekHeader": "\u0647\u0641",
+ "dateFormat": "d"
+ },
+ "fi": {
+ "closeText": "Sulje",
+ "prevText": "&laquo;Edellinen",
+ "nextText": "Seuraava&raquo;",
+ "currentText": "T&auml;n&auml;&auml;n",
+ "weekHeader": "Vk",
+ "dateFormat": "d"
+ },
+ "fo": {
+ "closeText": "Lat aftur",
+ "prevText": "&#x3c;Fyrra",
+ "nextText": "N\u00e6sta&#x3e;",
+ "currentText": "\u00cd dag",
+ "weekHeader": "Vk",
+ "dateFormat": "d"
+ },
+ "fr-CH": {
+ "closeText": "Fermer",
+ "prevText": "&#x3c;Pr\u00e9c",
+ "nextText": "Suiv&#x3e;",
+ "currentText": "Courant",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "fr": {
+ "closeText": "Fermer",
+ "prevText": "&#x3c;Pr\u00e9c",
+ "nextText": "Suiv&#x3e;",
+ "currentText": "Courant",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "he": {
+ "closeText": "\u05e1\u05d2\u05d5\u05e8",
+ "prevText": "&#x3c;\u05d4\u05e7\u05d5\u05d3\u05dd",
+ "nextText": "\u05d4\u05d1\u05d0&#x3e;",
+ "currentText": "\u05d4\u05d9\u05d5\u05dd",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "hr": {
+ "closeText": "Zatvori",
+ "prevText": "&#x3c;",
+ "nextText": "&#x3e;",
+ "currentText": "Danas",
+ "weekHeader": "Tje",
+ "dateFormat": "d"
+ },
+ "hu": {
+ "closeText": "bez\u00c3\u00a1r\u00c3\u00a1s",
+ "prevText": "&laquo;&nbsp;vissza",
+ "nextText": "el\u00c5\u2018re&nbsp;&raquo;",
+ "currentText": "ma",
+ "weekHeader": "H\u00c3\u00a9",
+ "dateFormat": "d"
+ },
+ "hy": {
+ "closeText": "\u00d5\u201c\u00d5\u00a1\u00d5\u00af\u00d5\u00a5\u00d5\u00ac",
+ "prevText": "&#x3c;\u00d5\u2020\u00d5\u00a1\u00d5\u00ad.",
+ "nextText": "\u00d5\u20ac\u00d5\u00a1\u00d5\u00bb.&#x3e;",
+ "currentText": "\u00d4\u00b1\u00d5\u00b5\u00d5\u00bd\u00d6\u2026\u00d6\u20ac",
+ "weekHeader": "\u00d5\u2021\u00d4\u00b2\u00d5\u008f",
+ "dateFormat": "d"
+ },
+ "id": {
+ "closeText": "Tutup",
+ "prevText": "&#x3c;mundur",
+ "nextText": "maju&#x3e;",
+ "currentText": "hari ini",
+ "weekHeader": "Mg",
+ "dateFormat": "d"
+ },
+ "is": {
+ "closeText": "Loka",
+ "prevText": "&#x3c; Fyrri",
+ "nextText": "N&aelig;sti &#x3e;",
+ "currentText": "&Iacute; dag",
+ "weekHeader": "Vika",
+ "dateFormat": "d"
+ },
+ "it": {
+ "closeText": "Chiudi",
+ "prevText": "&#x3c;Prec",
+ "nextText": "Succ&#x3e;",
+ "currentText": "Oggi",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "ja": {
+ "closeText": "\u9589\u3058\u308b",
+ "prevText": "&#x3c;\u524d",
+ "nextText": "\u6b21&#x3e;",
+ "currentText": "\u4eca\u65e5",
+ "weekHeader": "\u9031",
+ "dateFormat": "d"
+ },
+ "ko": {
+ "closeText": "\u00eb\u2039\u00ab\u00ea\u00b8\u00b0",
+ "prevText": "\u00ec\u009d\u00b4\u00ec\u00a0\u201e\u00eb\u2039\u00ac",
+ "nextText": "\u00eb\u2039\u00a4\u00ec\u009d\u0152\u00eb\u2039\u00ac",
+ "currentText": "\u00ec\u02dc\u00a4\u00eb\u0160\u02dc",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "lt": {
+ "closeText": "U\u00c5\u00bedaryti",
+ "prevText": "&#x3c;Atgal",
+ "nextText": "Pirmyn&#x3e;",
+ "currentText": "\u00c5\u00a0iandien",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "lv": {
+ "closeText": "Aizv\u00c4\u201crt",
+ "prevText": "Iepr",
+ "nextText": "N\u00c4\u0081ka",
+ "currentText": "\u00c5\u00a0odien",
+ "weekHeader": "Nav",
+ "dateFormat": "d"
+ },
+ "ms": {
+ "closeText": "Tutup",
+ "prevText": "&#x3c;Sebelum",
+ "nextText": "Selepas&#x3e;",
+ "currentText": "hari ini",
+ "weekHeader": "Mg",
+ "dateFormat": "d"
+ },
+ "nl": {
+ "closeText": "Sluiten",
+ "prevText": "\u2190",
+ "nextText": "\u2192",
+ "currentText": "Vandaag",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "no": {
+ "closeText": "Lukk",
+ "prevText": "&laquo;Forrige",
+ "nextText": "Neste&raquo;",
+ "currentText": "I dag",
+ "weekHeader": "Uke",
+ "dateFormat": "d"
+ },
+ "pl": {
+ "closeText": "Zamknij",
+ "prevText": "&#x3c;Poprzedni",
+ "nextText": "Nast\u00c4\u2122pny&#x3e;",
+ "currentText": "Dzi\u00c5\u203a",
+ "weekHeader": "Tydz",
+ "dateFormat": "d"
+ },
+ "pt-BR": {
+ "closeText": "Fechar",
+ "prevText": "&#x3c;Anterior",
+ "nextText": "Pr&oacute;ximo&#x3e;",
+ "currentText": "Hoje",
+ "weekHeader": "Sm",
+ "dateFormat": "d"
+ },
+ "ro": {
+ "closeText": "\u00cenchide",
+ "prevText": "&laquo; Luna precedent\u0103",
+ "nextText": "Luna urm\u0103toare &raquo;",
+ "currentText": "Azi",
+ "weekHeader": "S\u0103pt",
+ "dateFormat": "d"
+ },
+ "ru": {
+ "closeText": "\u00d0\u2014\u00d0\u00b0\u00d0\u00ba\u00d1\u20ac\u00d1\u2039\u00d1\u201a\u00d1\u0152",
+ "prevText": "&#x3c;\u00d0\u0178\u00d1\u20ac\u00d0\u00b5\u00d0\u00b4",
+ "nextText": "\u00d0\u00a1\u00d0\u00bb\u00d0\u00b5\u00d0\u00b4&#x3e;",
+ "currentText": "\u00d0\u00a1\u00d0\u00b5\u00d0\u00b3\u00d0\u00be\u00d0\u00b4\u00d0\u00bd\u00d1\u008f",
+ "weekHeader": "\u00d0\u009d\u00d0\u00b5",
+ "dateFormat": "d"
+ },
+ "sk": {
+ "closeText": "Zavrie\u00c5\u00a5",
+ "prevText": "&#x3c;Predch\u00c3\u00a1dzaj\u00c3\u00baci",
+ "nextText": "Nasleduj\u00c3\u00baci&#x3e;",
+ "currentText": "Dnes",
+ "weekHeader": "Ty",
+ "dateFormat": "d"
+ },
+ "sl": {
+ "closeText": "Zapri",
+ "prevText": "&lt;Prej&#x161;nji",
+ "nextText": "Naslednji&gt;",
+ "currentText": "Trenutni",
+ "weekHeader": "Teden",
+ "dateFormat": "d"
+ },
+ "sq": {
+ "closeText": "mbylle",
+ "prevText": "&#x3c;mbrapa",
+ "nextText": "P\u00ebrpara&#x3e;",
+ "currentText": "sot",
+ "weekHeader": "Ja",
+ "dateFormat": "d"
+ },
+ "sr-SR": {
+ "closeText": "Zatvori",
+ "prevText": "&#x3c;",
+ "nextText": "&#x3e;",
+ "currentText": "Danas",
+ "weekHeader": "Sed",
+ "dateFormat": "dd/MM/yyyy"
+ },
+ "sr": {
+ "closeText": "\u0417\u0430\u0442\u0432\u043e\u0440\u0438",
+ "prevText": "&#x3c;",
+ "nextText": "&#x3e;",
+ "currentText": "\u0414\u0430\u043d\u0430\u0441",
+ "weekHeader": "\u0421\u0435\u0434",
+ "dateFormat": "d"
+ },
+ "sv": {
+ "closeText": "St\u00e4ng",
+ "prevText": "&laquo;F\u00f6rra",
+ "nextText": "N\u00e4sta&raquo;",
+ "currentText": "Idag",
+ "weekHeader": "Ve",
+ "dateFormat": "d"
+ },
+ "ta": {
+ "closeText": "\u0bae\u0bc2\u0b9f\u0bc1",
+ "prevText": "\u0bae\u0bc1\u0ba9\u0bcd\u0ba9\u0bc8\u0baf\u0ba4\u0bc1",
+ "nextText": "\u0b85\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0ba4\u0bc1",
+ "currentText": "\u0b87\u0ba9\u0bcd\u0bb1\u0bc1",
+ "weekHeader": "\u041d\u0435",
+ "dateFormat": "d"
+ },
+ "th": {
+ "closeText": "\u0e1b\u0e34\u0e14",
+ "prevText": "&laquo;&nbsp;\u0e22\u0e49\u0e2d\u0e19",
+ "nextText": "\u0e16\u0e31\u0e14\u0e44\u0e1b&nbsp;&raquo;",
+ "currentText": "\u0e27\u0e31\u0e19\u0e19\u0e35\u0e49",
+ "weekHeader": "Wk",
+ "dateFormat": "d"
+ },
+ "tr": {
+ "closeText": "kapat",
+ "prevText": "&#x3c;geri",
+ "nextText": "ileri&#x3e",
+ "currentText": "bug\u00c3\u00bcn",
+ "weekHeader": "Hf",
+ "dateFormat": "d"
+ },
+ "uk": {
+ "closeText": "\u00d0\u2014\u00d0\u00b0\u00d0\u00ba\u00d1\u20ac\u00d0\u00b8\u00d1\u201a\u00d0\u00b8",
+ "prevText": "&#x3c;",
+ "nextText": "&#x3e;",
+ "currentText": "\u00d0\u00a1\u00d1\u0152\u00d0\u00be\u00d0\u00b3\u00d0\u00be\u00d0\u00b4\u00d0\u00bd\u00d1\u2013",
+ "weekHeader": "\u00d0\u009d\u00d0\u00b5",
+ "dateFormat": "d"
+ },
+ "vi": {
+ "closeText": "\u0110\u00f3ng",
+ "prevText": "&#x3c;Tr\u01b0\u1edbc",
+ "nextText": "Ti\u1ebfp&#x3e;",
+ "currentText": "H\u00f4m nay",
+ "weekHeader": "Tu",
+ "dateFormat": "d"
+ },
+ "zh-CN": {
+ "closeText": "\u00e5\u2026\u00b3\u00e9\u2014\u00ad",
+ "prevText": "&#x3c;\u00e4\u00b8\u0160\u00e6\u0153\u02c6",
+ "nextText": "\u00e4\u00b8\u2039\u00e6\u0153\u02c6&#x3e;",
+ "currentText": "\u00e4\u00bb\u0160\u00e5\u00a4\u00a9",
+ "weekHeader": "\u00e5\u2018\u00a8",
+ "dateFormat": "d"
+ },
+ "zh-HK": {
+ "closeText": "\u00e9\u2014\u0153\u00e9\u2013\u2030",
+ "prevText": "&#x3c;\u00e4\u00b8\u0160\u00e6\u0153\u02c6",
+ "nextText": "\u00e4\u00b8\u2039\u00e6\u0153\u02c6&#x3e;",
+ "currentText": "\u00e4\u00bb\u0160\u00e5\u00a4\u00a9",
+ "weekHeader": "\u00e5\u2018\u00a8",
+ "dateFormat": "d"
+ }
+};
+
+$.each( regions, function( name, value ) {
+ Globalize.loadTranslations( name, {
+ datepicker : value
+ });
+});
+
+return Globalize;
+
+} ) );
diff --git a/tests/lib/bootstrap.js b/tests/lib/bootstrap.js
index 47289494c..2829c6639 100644
--- a/tests/lib/bootstrap.js
+++ b/tests/lib/bootstrap.js
@@ -2,8 +2,11 @@
requirejs.config({
paths: {
+ "date": "../../../external/date",
"globalize": "../../../external/globalize/globalize",
- "globalize/ja-JP": "../../../external/globalize/globalize.culture.ja-JP",
+ "globalize-locales": "../../../external/localization",
+ "globalize-old": "../../../external/globalize-old/globalize",
+ "globalize-old/ja-JP": "../../../external/globalize-old/globalize.culture.ja-JP",
"jquery": jqueryUrl(),
"jquery-simulate": "../../../external/jquery-simulate/jquery.simulate",
"jshint": "../../../external/jshint/jshint",
@@ -16,7 +19,8 @@ requirejs.config({
"ui": "../../../ui"
},
shim: {
- "globalize/ja-JP": [ "globalize" ],
+ "date": [ "globalize-locales" ],
+ "globalize-old/ja-JP": [ "globalize-old" ],
"jquery-simulate": [ "jquery" ],
"qunit-assert-close": [ "qunit" ],
"testswarm": [ "qunit" ]
diff --git a/tests/unit/all.html b/tests/unit/all.html
index c8352615a..f06dad6d9 100644
--- a/tests/unit/all.html
+++ b/tests/unit/all.html
@@ -20,6 +20,7 @@
"autocomplete/autocomplete.html",
"button/button.html",
"core/core.html",
+ "calendar/calendar.html",
"datepicker/datepicker.html",
"dialog/dialog.html",
"draggable/draggable.html",
diff --git a/tests/unit/calendar/all.html b/tests/unit/calendar/all.html
new file mode 100644
index 000000000..65f71988b
--- /dev/null
+++ b/tests/unit/calendar/all.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar Test Suite</title>
+
+ <script src="../../../external/jquery/jquery.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit/qunit.css">
+ <link rel="stylesheet" href="../../../external/qunit-composite/qunit-composite.css">
+ <script src="../../../external/qunit/qunit.js"></script>
+ <script src="../../../external/qunit-composite/qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "calendar" );
+ </script>
+</head>
+<body>
+
+<div id="qunit"></div>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/tests/unit/calendar/calendar.html b/tests/unit/calendar/calendar.html
new file mode 100644
index 000000000..0d28b6351
--- /dev/null
+++ b/tests/unit/calendar/calendar.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Calendar Test Suite</title>
+
+ <script src="../../../external/requirejs/require.js"></script>
+ <script src="../../lib/css.js" data-modules="core calendar"></script>
+ <script src="../../lib/bootstrap.js" data-widget="datepicker"></script>
+</head>
+<body>
+
+<div id="qunit"></div>
+<div id="qunit-fixture">
+
+<div id="calendar"></div>
+<div id="calendar2"></div>
+
+</div>
+</body>
+</html>
diff --git a/tests/unit/calendar/common.js b/tests/unit/calendar/common.js
new file mode 100644
index 000000000..bb0f64d0d
--- /dev/null
+++ b/tests/unit/calendar/common.js
@@ -0,0 +1,26 @@
+define( [
+ "lib/common",
+ "ui/calendar",
+ "globalize-locales"
+], function( common ) {
+
+common.testWidget( "calendar", {
+ defaults: {
+ buttons: [],
+ classes: {},
+ dateFormat: { date: "short" },
+ disabled: false,
+ eachDay: $.noop,
+ max: null,
+ min: null,
+ numberOfMonths: 1,
+ showWeek: false,
+ value: null,
+
+ // callbacks
+ create: null,
+ select: null
+ }
+});
+
+} );
diff --git a/tests/unit/calendar/core.js b/tests/unit/calendar/core.js
new file mode 100644
index 000000000..92753748f
--- /dev/null
+++ b/tests/unit/calendar/core.js
@@ -0,0 +1,390 @@
+define( [
+ "jquery",
+ "./helper",
+ "globalize",
+ "ui/calendar"
+], function( $, testHelper, Globalize ) {
+
+module( "calendar: core" );
+
+test( "base structure", function() {
+ expect( 26 );
+
+ var header, title, table, thead, week, child, buttonpane,
+ element = $( "#calendar" ).calendar(),
+ dp = element.calendar( "widget" );
+
+ function step1() {
+ ok( !dp.is( ".ui-calendar-rtl" ), "Structure - not right-to-left" );
+ ok( !dp.is( ".ui-calendar-multi" ), "Structure - not multi-month" );
+ equal( dp.children().length, 2, "Structure - child count (header, calendar)" );
+
+ header = dp.children( ":first" );
+ ok( header.is( "div.ui-calendar-header" ), "Structure - header division" );
+ equal( header.children().length, 3, "Structure - header child count" );
+ ok( header.children( ":first" ).is( ".ui-calendar-prev" ) && header.children( ":first" ).html() !== "", "Structure - prev link" );
+ ok( header.children( ":eq(1)" ).is( ".ui-calendar-next" ) && header.children( ":eq(1)" ).html() !== "", "Structure - next link" );
+
+ title = header.children( ":last" ).children( ":first" );
+ ok( title.is( "div.ui-calendar-title" ) && title.html() !== "", "Structure - title division" );
+ equal( title.children().length, 2, "Structure - title child count" );
+ ok( title.children( ":first" ).is( "span.ui-calendar-month" ) && title.children( ":first" ).text() !== "", "Structure - month text" );
+ ok( title.children( ":last" ).is( "span.ui-calendar-year" ) && title.children( ":last" ).text() !== "", "Structure - year text" );
+
+ table = dp.children( ":eq(1)" );
+ ok( table.is( "table.ui-calendar-calendar" ), "Structure - month table" );
+ ok( table.children( ":first" ).is( "thead" ), "Structure - month table thead" );
+
+ thead = table.children( ":first" ).children( ":first" );
+ ok( thead.is( "tr" ), "Structure - month table title row" );
+ equal( thead.find( "th" ).length, 7, "Structure - month table title cells" );
+ ok( table.children( ":eq(1)" ).is( "tbody" ), "Structure - month table body" );
+ ok( table.children( ":eq(1)" ).children( "tr" ).length >= 4, "Structure - month table week count" );
+
+ week = table.children( ":eq(1)" ).children( ":first" );
+ ok( week.is( "tr" ), "Structure - month table week row" );
+ equal( week.children().length, 7, "Structure - week child count" );
+
+ step2();
+ }
+
+ function step2() {
+ element.calendar( "option", "buttons", {
+ "test": function() {},
+ "test button": function() {}
+ });
+
+ equal( dp.children().length, 3, "Structure buttons - child count (header, calendar, buttonpane)" );
+
+ buttonpane = dp.children( ".ui-calendar-buttonpane" );
+ equal( buttonpane.children( "div.ui-calendar-buttonset" ).length, 1, "Structure buttons - buttonset" );
+ equal( buttonpane.find( "button.ui-button:first" ).text(), "test", "Structure buttons - buttonset" );
+ equal( buttonpane.find( "button.ui-button:eq(1)" ).text(), "test button", "Structure buttons - buttonset" );
+
+ element.calendar( "destroy" );
+ step3();
+ }
+
+ function step3() {
+ // Multi-month 2
+ element = $( "#calendar" ).calendar( { numberOfMonths: 2 } );
+ dp = element.calendar( "widget" );
+
+ ok( dp.is( ".ui-calendar-multi" ), "Structure multi [2] - multi-month" );
+ equal( dp.children().length, 3, "Structure multi [2] - child count" );
+
+ child = dp.children( ":eq(2)" );
+ ok( child.is( "div.ui-calendar-row-break" ), "Structure multi [2] - row break" );
+
+ element.calendar( "destroy" );
+ }
+
+ step1();
+});
+
+test( "Localization", function() {
+ expect( 10 );
+
+ var defaultLocale = Globalize.locale(),
+ element = $( "#calendar" ),
+ date = new Date( 2014, 0, 1 ),
+ initCalendar = function() {
+ element
+ .calendar()
+ .calendar( "valueAsDate", date );
+ },
+ testLocalization = function( message ) {
+ equal(
+ element.find( ".ui-calendar-month" ).text(),
+ "Januar", message + "titlebar year"
+ );
+ equal(
+ element.find( "thead th:first" ).text(),
+ "Mo.", message + "teader first day"
+ );
+ equal(
+ element.find( "thead th:last" ).text(),
+ "So.", message + "header last day"
+ );
+ equal(
+ element.find( ".ui-calendar-prev" ).text(),
+ "<Zurück", message + "header prev"
+ );
+ equal(
+ element.find( ".ui-calendar-next" ).text(),
+ "Vor>", message + "header next"
+ );
+ };
+
+ Globalize.locale( "de-DE" );
+ initCalendar();
+ testLocalization( "Init: " );
+ element.calendar( "destroy" );
+
+ Globalize.locale( defaultLocale.locale );
+ initCalendar();
+ Globalize.locale( "de-DE" );
+ element.calendar( "refresh" );
+ testLocalization( "After init: " );
+
+ Globalize.locale( defaultLocale.locale );
+});
+
+asyncTest( "keyboard handling", function() {
+ expect( 10 );
+
+ var element = $( "#calendar" );
+
+ function step1() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper
+ .focusGrid( element )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2013, 12 - 1, 31 ),
+ "Keystroke left to switch to previous day"
+ );
+ element.calendar( "destroy" );
+ step2();
+ }, 50 );
+ }
+
+ function step2() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2014, 1 - 1, 2 ),
+ "Keystroke right to switch to next day"
+ );
+ step3();
+ }
+
+ function step3() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element ).simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2013, 12 - 1, 25 ),
+ "Keystroke up to move to the previous week"
+ );
+ element.calendar( "destroy" );
+ step4();
+ }, 50 );
+ }
+
+ function step4() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element ).simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2014, 1 - 1, 8 ),
+ "Keystroke down to move to the next week"
+ );
+ element.calendar( "destroy" );
+ step5();
+ }, 50 );
+ }
+
+ function step5() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element ).simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2013, 12 - 1, 1 ),
+ "Keystroke Page Up moves date to previous month"
+ );
+ element.calendar( "destroy" );
+ step6();
+ }, 50 );
+ }
+
+ function step6() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP, altKey: true } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2013, 1 - 1, 1 ),
+ "Keystroke Page Up + ALT moves date to previous year"
+ );
+ element.calendar( "destroy" );
+ step7();
+ }, 50 );
+ }
+
+ function step7() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element ).simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2014, 2 - 1, 1 ),
+ "Keystroke Page Down moves date to next month"
+ );
+ element.calendar( "destroy" );
+ step8();
+ }, 50 );
+ }
+
+ function step8() {
+ element.calendar({ value: new Date( 2014, 1 - 1, 1 ) });
+
+ testHelper.focusGrid( element )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN, altKey: true } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2015, 1 - 1, 1 ),
+ "Keystroke Page Down + ALT moves date to next year"
+ );
+ element.calendar( "destroy" );
+ step9();
+ }, 50 );
+ }
+
+ // Check for moving to short months
+ function step9() {
+ element.calendar({ value: new Date( 2014, 3 - 1, 31 ) });
+
+ testHelper.focusGrid( element ).simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2014, 2 - 1, 28 ),
+ "Keystroke Page Up and short months"
+ );
+ element.calendar( "destroy" );
+ step10();
+ }, 50 );
+ }
+
+ function step10() {
+ element.calendar({ value: new Date( 2016, 1 - 1, 30 ) });
+
+ testHelper.focusGrid( element ).simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2016, 2 - 1, 29 ),
+ "Keystroke Page Down and leap years"
+ );
+ element.calendar( "destroy" );
+ start();
+ }, 50 );
+ }
+
+ step1();
+});
+
+asyncTest( "mouse", function() {
+ expect( 6 );
+
+ var element = $( "#calendar" ).calendar(),
+ date = new Date();
+
+ function step1() {
+ $( "tbody button:contains(10)", element ).simulate( "mousedown" );
+ date.setDate( 10 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date,
+ "Mouse click"
+ );
+
+ element.calendar( "option", "value", new Date( 2008, 2 - 1, 4) );
+ $( ".ui-calendar-calendar tbody button:contains(12)", element ).simulate( "mousedown" );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2008, 2 - 1, 12 ),
+ "Mouse click - preset"
+ );
+
+ // Previous/next
+ element.calendar( "option", "value", new Date( 2008, 2 - 1, 4) );
+ $( ".ui-calendar-prev", element ).simulate( "click" );
+ $( ".ui-calendar-calendar tbody button:contains(16)", element ).simulate( "mousedown" );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2008, 1 - 1, 16 ),
+ "Mouse click - previous"
+ );
+
+ element.calendar( "option", "value", new Date( 2008, 2 - 1, 4) );
+ $( ".ui-calendar-next", element ).simulate( "click" );
+ $( ".ui-calendar-calendar tbody button:contains(18)", element ).simulate( "mousedown" );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2008, 3 - 1, 18 ),
+ "Mouse click - next"
+ );
+
+ step2();
+ }
+
+ // Previous/next with minimum/maximum
+ function step2() {
+ element.calendar( "destroy" );
+ element.calendar({
+ value: new Date( 2008, 3 - 1, 4),
+ min: new Date( 2008, 2 - 1, 2 ),
+ max: new Date( 2008, 2 - 1, 26 )
+ });
+
+ $( ".ui-calendar-prev", element ).simulate( "click" );
+ $( "tbody button:contains(16)", element ).simulate( "mousedown" );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2008, 2 - 1, 16 ),
+ "Mouse click - previous + min/max"
+ );
+ step3();
+ }
+
+ function step3() {
+ element.calendar( "destroy" );
+ element.calendar({
+ value: new Date( 2008, 1 - 1, 4),
+ min: new Date( 2008, 2 - 1, 2 ),
+ max: new Date( 2008, 2 - 1, 26 )
+ });
+
+ $( ".ui-calendar-next", element ).simulate( "click" );
+ $( "tbody button:contains(18)", element ).simulate( "mousedown" );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ new Date( 2008, 2 - 1, 18 ),
+ "Mouse click - next + min/max"
+ );
+ start();
+ }
+
+ step1();
+});
+
+} );
diff --git a/tests/unit/calendar/events.js b/tests/unit/calendar/events.js
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/unit/calendar/events.js
diff --git a/tests/unit/calendar/helper.js b/tests/unit/calendar/helper.js
new file mode 100644
index 000000000..a82e96705
--- /dev/null
+++ b/tests/unit/calendar/helper.js
@@ -0,0 +1,31 @@
+define( [
+ "jquery",
+ "lib/helper"
+], function( $, helper ) {
+
+return $.extend( helper, {
+ addMonths: function( date, offset ) {
+ var maxDay = 32 - new Date( date.getFullYear(), date.getMonth() + offset, 32 ).getDate();
+ date.setDate( Math.min( date.getDate(), maxDay ) );
+ date.setMonth( date.getMonth() + offset );
+ return date;
+ },
+ equalsDate: function( d1, d2, message ) {
+ if ( !d1 || !d2 ) {
+ ok( false, message + " - missing date" );
+ return;
+ }
+ d1 = new Date( d1.getFullYear(), d1.getMonth(), d1.getDate() );
+ d2 = new Date( d2.getFullYear(), d2.getMonth(), d2.getDate() );
+ equal( d1.toString(), d2.toString(), message );
+ },
+ focusGrid: function( element ) {
+ element.find( ":tabbable" ).last().simulate( "focus" );
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.TAB } );
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.TAB } );
+
+ return $( document.activeElement );
+ }
+} );
+
+} );
diff --git a/tests/unit/calendar/methods.js b/tests/unit/calendar/methods.js
new file mode 100644
index 000000000..e28d30d6b
--- /dev/null
+++ b/tests/unit/calendar/methods.js
@@ -0,0 +1,145 @@
+define( [
+ "jquery",
+ "./helper",
+ "ui/calendar"
+], function( $, testHelper ) {
+
+module( "calendar: methods" );
+
+test( "destroy", function( assert ) {
+ expect( 1 );
+
+ assert.domEqual( "#calendar", function() {
+ $( "#calendar" ).calendar().calendar( "destroy" );
+ });
+});
+
+test( "enable / disable", function() {
+ expect( 8 );
+
+ var element = $( "#calendar" ).calendar();
+
+ element.calendar( "disable" );
+ ok( element.calendar( "option", "disabled" ), "disabled option is set" );
+ ok( element.hasClass( "ui-calendar-disabled" ), "has disabled widget class name" );
+ ok( element.hasClass( "ui-state-disabled" ), "has disabled state class name" );
+ equal( element.attr( "aria-disabled" ), "true", "has ARIA disabled" );
+
+ element.calendar( "enable" );
+ ok( !element.calendar( "option", "disabled" ), "enabled after enable() call" );
+ ok( !element.hasClass( "ui-calendar-disabled" ), "no longer has disabled widget class name" );
+ ok( !element.hasClass( "ui-state-disabled" ), "no longer has disabled state class name" );
+ equal( element.attr( "aria-disabled" ), "false", "no longer has ARIA disabled" );
+});
+
+test( "widget", function() {
+ expect( 1 );
+
+ var element = $( "#calendar" ).calendar(),
+ widget = element.calendar( "widget" );
+
+ strictEqual( widget[ 0 ], element[ 0 ] );
+});
+
+test( "value", function() {
+ expect( 3 );
+ var element = $( "#calendar" ).calendar();
+
+ element.calendar( "value", "1/1/14" );
+ ok( element.find( "button[data-timestamp]:first" )
+ .hasClass( "ui-state-active" ),
+ "first day marked as selected"
+ );
+ equal( element.calendar( "value" ), "1/1/14", "getter" );
+
+ element.calendar( "value", "abc" );
+ equal( element.calendar( "value" ), "1/1/14", "Setting invalid values should be ignored." );
+});
+
+test( "valueAsDate", function() {
+ expect( 11 );
+
+ var minDate, maxDate, dateAndTimeToSet, dateAndTimeClone,
+ element = $( "#calendar" ).calendar(),
+ date1 = new Date( 2008, 6 - 1, 4 ),
+ date2;
+
+ element.calendar( "valueAsDate", new Date( 2014, 0, 1 ) );
+ ok( element.find( "button[data-timestamp]:first" )
+ .hasClass( "ui-state-active" ),
+ "First day marked as selected"
+ );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2014, 0, 1 ), "Getter" );
+
+ element.calendar( "destroy" );
+
+ element.calendar();
+ equal( element.calendar( "valueAsDate" ), null, "Set date - default" );
+
+ element.calendar( "valueAsDate", date1 );
+ testHelper.equalsDate(element.calendar( "valueAsDate" ), date1, "Set date - 2008-06-04" );
+
+ // With minimum/maximum
+ element = $( "#calendar" ).calendar();
+ date1 = new Date( 2008, 1 - 1, 4 );
+ date2 = new Date( 2008, 6 - 1, 4 );
+ minDate = new Date( 2008, 2 - 1, 29 );
+ maxDate = new Date( 2008, 3 - 1, 28 );
+
+ element
+ .calendar( "option", { min: minDate } )
+ .calendar( "valueAsDate", date2 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date2, "Set date min/max - value > min"
+ );
+
+ element.calendar( "valueAsDate", date1 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date2,
+ "Set date min/max - value < min"
+ );
+
+ element
+ .calendar( "option", { max: maxDate, min: null } )
+ .calendar( "valueAsDate", date1 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date1,
+ "Set date min/max - value < max"
+ );
+
+ element.calendar( "valueAsDate", date2 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date1,
+ "Set date min/max - value > max"
+ );
+
+ element
+ .calendar( "option", { min: minDate } )
+ .calendar( "valueAsDate", date1 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date1,
+ "Set date min/max - value < min"
+ );
+
+ element.calendar( "valueAsDate", date2 );
+ testHelper.equalsDate(
+ element.calendar( "valueAsDate" ),
+ date1, "Set date min/max - value > max"
+ );
+
+ dateAndTimeToSet = new Date( 2008, 3 - 1, 28, 1, 11, 0 );
+ dateAndTimeClone = new Date( 2008, 3 - 1, 28, 1, 11, 0 );
+ element.calendar( "valueAsDate", dateAndTimeToSet );
+ equal(
+ dateAndTimeToSet.getTime(),
+ dateAndTimeClone.getTime(),
+ "Date object passed should not be changed by valueAsDate"
+ );
+});
+
+} );
diff --git a/tests/unit/calendar/options.js b/tests/unit/calendar/options.js
new file mode 100644
index 000000000..c6049fce3
--- /dev/null
+++ b/tests/unit/calendar/options.js
@@ -0,0 +1,323 @@
+define( [
+ "jquery",
+ "./helper",
+ "ui/calendar"
+], function( $, testHelper ) {
+
+module( "calendar: options" );
+
+test("buttons", function() {
+ expect( 21 );
+
+ var button, i, newButtons,
+ buttons = {
+ "Ok": function( event ) {
+ ok(true, "button click fires callback" );
+ equal( this, element[ 0 ], "context of callback" );
+ equal( event.target, button[ 0 ], "event target" );
+ },
+ "Cancel": function( event ) {
+ ok( true, "button click fires callback" );
+ equal( this, element[ 0 ], "context of callback" );
+ equal( event.target, button[ 1 ], "event target" );
+ }
+ },
+ element = $( "#calendar" ).calendar({ buttons: buttons });
+
+ button = element.calendar( "widget" ).find( ".ui-calendar-buttonpane button" );
+ equal( button.length, 2, "number of buttons" );
+
+ i = 0;
+ $.each( buttons, function( key ) {
+ equal( button.eq( i ).text(), key, "text of button " + ( i + 1 ) );
+ i++;
+ });
+
+ ok( button.parent().hasClass( "ui-calendar-buttonset" ), "buttons in container" );
+ ok(
+ element.calendar( "widget" ).hasClass( "ui-calendar-buttons" ),
+ "calendar wrapper adds class about having buttons"
+ );
+
+ button.trigger( "click" );
+
+ newButtons = {
+ "Close": function( event ) {
+ ok( true, "button click fires callback" );
+ equal( this, element[ 0 ], "context of callback" );
+ equal( event.target, button[ 0 ], "event target" );
+ }
+ };
+
+ deepEqual(
+ element.calendar( "option", "buttons" ),
+ buttons,
+ ".calendar('option', 'buttons') getter"
+ );
+ element.calendar( "option", "buttons", newButtons );
+ deepEqual(
+ element.calendar( "option", "buttons" ),
+ newButtons,
+ ".calendar('option', 'buttons', ...) setter"
+ );
+
+ button = element.calendar( "widget" ).find( ".ui-calendar-buttonpane button" );
+ equal( button.length, 1, "number of buttons after setter" );
+ button.trigger( "click" );
+
+ i = 0;
+ $.each( newButtons, function( key ) {
+ equal( button.eq( i ).text(), key, "text of button " + ( i + 1 ) );
+ i += 1;
+ });
+
+ element.calendar( "option", "buttons", null );
+ button = element.calendar( "widget" ).find( ".ui-calendar-buttonpane button" );
+ equal( button.length, 0, "all buttons have been removed" );
+ equal( element.find( ".ui-calendar-buttonset" ).length, 0, "buttonset has been removed" );
+ equal( element.hasClass( "ui-calendar-buttons" ), false, "calendar element removes class about having buttons" );
+
+ element.remove();
+});
+
+test( "buttons - advanced", function() {
+ expect( 7 );
+
+ var buttons,
+ element = $( "#calendar" ).calendar({
+ buttons: [{
+ text: "a button",
+ "class": "additional-class",
+ id: "my-button-id",
+ click: function() {
+ equal( this, element[ 0 ], "correct context" );
+ },
+ icons: {
+ primary: "ui-icon-cancel"
+ },
+ showText: false
+ }]
+ });
+
+ buttons = element.calendar( "widget" ).find( ".ui-calendar-buttonpane button" );
+ equal( buttons.length, 1, "correct number of buttons" );
+ equal( buttons.attr( "id" ), "my-button-id", "correct id" );
+ equal ( buttons.text(), "a button", "correct label" );
+ ok( buttons.hasClass( "additional-class" ), "additional classes added" );
+ deepEqual( buttons.button( "option", "icons" ), { primary: "ui-icon-cancel", secondary: null } );
+ equal( buttons.button( "option", "text" ), false );
+ buttons.click();
+
+ element.remove();
+});
+
+test( "dateFormat", function() {
+ expect( 2 );
+ var element = $( "#calendar" ).calendar();
+
+ element.calendar( "value", "1/1/14" );
+
+ element.calendar( "widget" ).find( "td[id]:first button" ).trigger( "mousedown" );
+ equal( element.calendar( "value" ), "1/1/14", "default formatting" );
+
+ element.calendar( "option", "dateFormat", { date: "full" } );
+ equal( element.calendar( "value" ), "Wednesday, January 1, 2014", "updated formatting" );
+});
+
+test( "eachDay", function() {
+ expect( 5 );
+ var timestamp,
+ input = $( "#calendar" ).calendar(),
+ picker = input.calendar( "widget" ),
+ firstCell = picker.find( "td[id]:first" );
+
+ equal( firstCell.find( "button" ).length, 1, "days are selectable by default" );
+ timestamp = parseInt( firstCell.find( "button" ).attr( "data-timestamp" ), 10 );
+ equal( new Date( timestamp ).getDate(), 1, "first available day is the 1st by default" );
+
+ // Do not render the 1st of the month
+ input.calendar( "option", "eachDay", function( day ) {
+ if ( day.date === 1 ) {
+ day.render = false;
+ }
+ });
+ firstCell = picker.find( "td[id]:first" );
+ timestamp = parseInt( firstCell.find( "button" ).attr( "data-timestamp" ), 10 );
+ equal( new Date( timestamp ).getDate(), 2, "first available day is the 2nd" );
+
+ // Display the 1st of the month but make it not selectable.
+ input.calendar( "option", "eachDay", function( day ) {
+ if ( day.date === 1 ) {
+ day.selectable = false;
+ }
+ });
+ firstCell = picker.find( "td[id]:first" );
+ ok( firstCell.find( "button" ).prop( "disabled" ), "the 1st is not selectable" );
+
+ input.calendar( "option", "eachDay", function( day ) {
+ if ( day.date === 1 ) {
+ day.extraClasses = "ui-custom";
+ }
+ });
+ ok( picker.find( "td[id]:first button" ).hasClass( "ui-custom" ), "extraClasses applied" );
+
+ input.calendar( "destroy" );
+});
+
+test( "showWeek", function() {
+ expect( 7 );
+ var input = $( "#calendar" ).calendar(),
+ container = input.calendar( "widget" );
+
+ equal( container.find( "thead th" ).length, 7, "just 7 days, no column cell" );
+ equal( container.find( ".ui-calendar-week-col" ).length, 0,
+ "no week column cells present" );
+ input.calendar( "destroy" );
+
+ input = $( "#calendar" ).calendar({ showWeek: true });
+ container = input.calendar( "widget" );
+ equal( container.find( "thead th" ).length, 8, "7 days + a column cell" );
+ ok( container.find( "thead th:first" ).is( ".ui-calendar-week-col" ),
+ "first cell should have ui-datepicker-week-col class name" );
+ equal( container.find( ".ui-calendar-week-col" ).length,
+ container.find( "tr" ).length, "one week cell for each week" );
+ input.calendar( "destroy" );
+
+ input = $( "#calendar" ).calendar();
+ container = input.calendar( "widget" );
+ equal( container.find( "thead th" ).length, 7, "no week column" );
+ input.calendar( "option", "showWeek", true );
+ equal( container.find( "thead th" ).length, 8, "supports changing option after init" );
+});
+
+test( "min / max", function() {
+ expect( 7 );
+
+ // With existing date
+ var element = $( "#calendar" ).calendar(),
+ minDate = new Date( 2008, 2 - 1, 29 ),
+ maxDate = new Date( 2008, 12 - 1, 7 );
+
+ element
+ .calendar( "option", { min: minDate } )
+ .calendar( "value", "6/4/08" );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > min" );
+
+ element
+ .calendar( "option", { min: minDate } )
+ .calendar( "value", "1/4/08" );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < min" );
+
+ element
+ .calendar( "option", { min: null } )
+ .calendar( "value", "6/4/08" )
+ .calendar( "option", { max: maxDate } );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < max" );
+
+ element
+ .calendar( "option", { max: maxDate } )
+ .calendar( "value", "1/4/09" );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - setDate > max" );
+
+ element
+ .calendar( "option", { min: minDate, max: maxDate } )
+ .calendar( "value", "1/4/08" );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value < min" );
+
+ element
+ .calendar( "option", { min: minDate, max: maxDate } )
+ .calendar( "value", "6/4/08" );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > min, < max" );
+
+ element
+ .calendar( "option", { min: minDate, max: maxDate } )
+ .calendar( "value", "1/4/09" );
+ testHelper.equalsDate( element.calendar( "valueAsDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - value > max" );});
+
+/*
+// TODO: Move this to $.date, Globalize or calendar widget
+test( "daylightSaving", function() {
+ expect( 25 );
+ var inp = testHelper.init( "#inp" ),
+ dp = $( "#ui-datepicker-div" );
+ ok(true, "Daylight saving - " + new Date());
+ // Australia, Sydney - AM change, southern hemisphere
+ inp.val( "04/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(6) a", dp).simulate( "click" );
+ equal(inp.val(), "04/05/2008", "Daylight saving - Australia 04/05/2008" );
+ inp.val( "04/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(7) a", dp).simulate( "click" );
+ equal(inp.val(), "04/06/2008", "Daylight saving - Australia 04/06/2008" );
+ inp.val( "04/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(8) a", dp).simulate( "click" );
+ equal(inp.val(), "04/07/2008", "Daylight saving - Australia 04/07/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(6) a", dp).simulate( "click" );
+ equal(inp.val(), "10/04/2008", "Daylight saving - Australia 10/04/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(7) a", dp).simulate( "click" );
+ equal(inp.val(), "10/05/2008", "Daylight saving - Australia 10/05/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(8) a", dp).simulate( "click" );
+ equal(inp.val(), "10/06/2008", "Daylight saving - Australia 10/06/2008" );
+ // Brasil, Brasilia - midnight change, southern hemisphere
+ inp.val( "02/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(20) a", dp).simulate( "click" );
+ equal(inp.val(), "02/16/2008", "Daylight saving - Brasil 02/16/2008" );
+ inp.val( "02/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(21) a", dp).simulate( "click" );
+ equal(inp.val(), "02/17/2008", "Daylight saving - Brasil 02/17/2008" );
+ inp.val( "02/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(22) a", dp).simulate( "click" );
+ equal(inp.val(), "02/18/2008", "Daylight saving - Brasil 02/18/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(13) a", dp).simulate( "click" );
+ equal(inp.val(), "10/11/2008", "Daylight saving - Brasil 10/11/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(14) a", dp).simulate( "click" );
+ equal(inp.val(), "10/12/2008", "Daylight saving - Brasil 10/12/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(15) a", dp).simulate( "click" );
+ equal(inp.val(), "10/13/2008", "Daylight saving - Brasil 10/13/2008" );
+ // Lebanon, Beirut - midnight change, northern hemisphere
+ inp.val( "03/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(34) a", dp).simulate( "click" );
+ equal(inp.val(), "03/29/2008", "Daylight saving - Lebanon 03/29/2008" );
+ inp.val( "03/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(35) a", dp).simulate( "click" );
+ equal(inp.val(), "03/30/2008", "Daylight saving - Lebanon 03/30/2008" );
+ inp.val( "03/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(36) a", dp).simulate( "click" );
+ equal(inp.val(), "03/31/2008", "Daylight saving - Lebanon 03/31/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(27) a", dp).simulate( "click" );
+ equal(inp.val(), "10/25/2008", "Daylight saving - Lebanon 10/25/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(28) a", dp).simulate( "click" );
+ equal(inp.val(), "10/26/2008", "Daylight saving - Lebanon 10/26/2008" );
+ inp.val( "10/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(29) a", dp).simulate( "click" );
+ equal(inp.val(), "10/27/2008", "Daylight saving - Lebanon 10/27/2008" );
+ // US, Eastern - AM change, northern hemisphere
+ inp.val( "03/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(13) a", dp).simulate( "click" );
+ equal(inp.val(), "03/08/2008", "Daylight saving - US 03/08/2008" );
+ inp.val( "03/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(14) a", dp).simulate( "click" );
+ equal(inp.val(), "03/09/2008", "Daylight saving - US 03/09/2008" );
+ inp.val( "03/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(15) a", dp).simulate( "click" );
+ equal(inp.val(), "03/10/2008", "Daylight saving - US 03/10/2008" );
+ inp.val( "11/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(6) a", dp).simulate( "click" );
+ equal(inp.val(), "11/01/2008", "Daylight saving - US 11/01/2008" );
+ inp.val( "11/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(7) a", dp).simulate( "click" );
+ equal(inp.val(), "11/02/2008", "Daylight saving - US 11/02/2008" );
+ inp.val( "11/01/2008" ).calendar( "show" );
+ $( ".ui-calendar-calendar td:eq(8) a", dp).simulate( "click" );
+ equal(inp.val(), "11/03/2008", "Daylight saving - US 11/03/2008" );
+ });
+ */
+
+} );
diff --git a/tests/unit/date/all.html b/tests/unit/date/all.html
new file mode 100644
index 000000000..5248d7ace
--- /dev/null
+++ b/tests/unit/date/all.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Date Test Suite</title>
+
+ <script src="../../../external/jquery/jquery.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit/qunit.css">
+ <link rel="stylesheet" href="../../../external/qunit-composite/qunit-composite.css">
+ <script src="../../../external/qunit/qunit.js"></script>
+ <script src="../../../external/qunit-composite/qunit-composite.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "date" );
+ </script>
+</head>
+<body>
+
+<div id="qunit"></div>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/tests/unit/date/core.js b/tests/unit/date/core.js
new file mode 100644
index 000000000..e6dc16dcf
--- /dev/null
+++ b/tests/unit/date/core.js
@@ -0,0 +1,197 @@
+define( [
+ "jquery",
+ "globalize",
+ "date"
+], function( $, Globalize ) {
+
+module( "date: core" );
+
+test( "Instantiation", function() {
+ expect( 2 );
+ ok( new $.date() instanceof $.date, "constructor function" );
+ ok( $.date() instanceof $.date, "instantiation without new" );
+});
+
+test( "Check Sets and Gets", 6, function() {
+ var date = $.date();
+ equal( date.setYear( 2012 ).year(), 2012, "Set year and retrieve" );
+ equal( date.setMonth( 9 ).month(), 9, "Set month and retrieve" );
+ equal( date.setDay( 15 ).day(), 15, "Set day and retrieve" );
+ equal( date.setFullDate( 2012, 9, 15 ).year(), 2012, "Set full date and retrieve year" );
+ equal( date.month(), 9, "Set full date and retrieve month" );
+ equal( date.day(), 15, "Set full date and retrieve day" );
+});
+
+test( "Date Adjustments - Normal Use Cases", 10, function() {
+ var date = $.date();
+
+ // Use October 15, 2012
+ date.setFullDate( 2012, 9, 15 );
+ equal( date.adjust( "D", 1 ).day(), 16, "Add 1 day" );
+ equal( date.adjust( "D", -1 ).day(), 15, "Subtract 1 day" );
+ equal( date.adjust( "M", 1 ).month(), 10, "Add 1 month" );
+ equal( date.adjust( "M", -1 ).month(), 9, "Subtract 1 month" );
+ equal( date.adjust( "Y", 1 ).year(), 2013, "Add 1 year" );
+ equal( date.adjust( "Y", -1 ).year(), 2012, "Subtract 1 year" );
+
+ // Check changing one value impact another. Ex: Day impacts month
+ // Use April 30th 2012
+ date.setFullDate( 2012, 3, 30 );
+ equal( date.adjust( "D", 1 ).month(), 4, "Add 1 day to change month from April to May" );
+ equal( date.adjust( "D", -1 ).month(), 3, "Subtract 1 day to change month from May to April" );
+
+ // Use December 31st 2012
+ date.setFullDate( 2012, 11, 31 );
+ equal( date.adjust( "D", 1 ).year(), 2013, "Add 1 day to change year from 2012 to 2013" );
+ equal( date.adjust( "D", -1 ).year(), 2012,
+ "Subtract 1 day to change month from 2013 to 2012" );
+});
+
+test( "Date Adjustments - Month Overflow Edge Cases", 2, function() {
+ var date = $.date();
+
+ // Use May 31 2012
+ date.setFullDate( 2012, 4, 31 );
+ equal( date.adjust( "M", 1 ).day(), 30,
+ "Add 1 month from May to June sets days to 30, last day in June (prevent Overflow)" );
+ equal( date.adjust( "M", -1 ).day(), 30,
+ "Subtract 1 month from June to May sets days to 30 in May" );
+});
+
+test( "Date Adjustments - Leap Year Edge Cases", 1, function() {
+ var date = $.date();
+
+ // Use February 29 2012 a Leap year
+ date.setFullDate( 2012, 1, 29 );
+ equal( date.adjust( "Y", 1 ).day(), 28,
+ "Feb 29 2012, add a year to convert to Feb 28, 2013" );
+});
+
+test( "List days of Week", 2, function() {
+ var date = $.date(),
+ offset0 = [
+ { "fullname": "Sunday", "shortname": "Su" },
+ { "fullname": "Monday", "shortname": "Mo" },
+ { "fullname": "Tuesday", "shortname": "Tu" },
+ { "fullname": "Wednesday", "shortname": "We" },
+ { "fullname": "Thursday", "shortname": "Th" },
+ { "fullname": "Friday", "shortname": "Fr" },
+ { "fullname": "Saturday", "shortname": "Sa" }
+ ],
+ offset1 = [
+ { "fullname": "Montag", "shortname": "Mo." },
+ { "fullname": "Dienstag", "shortname": "Di." },
+ { "fullname": "Mittwoch", "shortname": "Mi." },
+ { "fullname": "Donnerstag", "shortname": "Do." },
+ { "fullname": "Freitag", "shortname": "Fr." },
+ { "fullname": "Samstag", "shortname": "Sa." },
+ { "fullname": "Sonntag", "shortname": "So." }
+ ];
+
+ deepEqual( date.weekdays(), offset0, "Get weekdays with start of day on 0 (English)" );
+ Globalize.locale( "de-DE" );
+ deepEqual( date.weekdays(), offset1, "Get weekdays with start of day on 1 (Germany)" );
+
+ // Revert Globalize changes back to English
+ Globalize.locale( "en" );
+});
+
+test( "Leap Year Check", 8, function() {
+ var date = $.date();
+ ok( date.setYear( 2008 ).isLeapYear(), "2008 is a Leap Year" );
+ ok( !date.setYear( 2009 ).isLeapYear(), "2009 is not a Leap Year" );
+ ok( !date.setYear( 2010 ).isLeapYear(), "2010 is not a Leap Year" );
+ ok( !date.setYear( 2011 ).isLeapYear(), "2011 is not a Leap Year" );
+ ok( date.isLeapYear( 2012 ), "2012 is a Leap Year" );
+ ok( !date.isLeapYear( 2013 ), "2013 is not a Leap Year" );
+ ok( !date.isLeapYear( 2014 ), "2014 is not a Leap year" );
+ ok( !date.isLeapYear( 2015 ), "2015 is not a Leap year" );
+});
+
+test( "Days in Month", 3, function() {
+ var date = $.date();
+ date.setFullDate( 2012, 1, 1 );
+ equal( date.daysInMonth(), 29, "Leap Year implicit check for 29 days" );
+ equal( date.daysInMonth( 2012, 1 ), 29, "Leap Year explicit check for 29 days" );
+ equal( date.daysInMonth( 2011, 3 ), 30, "April has 30 days" );
+});
+
+test( "Month Name", 2, function() {
+ var date = $.date();
+ equal( date.setMonth( 3 ).monthName(), "April", "Month name return April (English)" );
+ Globalize.locale( "de-DE" );
+ equal( date.setMonth( 2 ).monthName(), "März", "Month name return March (German)" );
+ Globalize.locale( "en" );
+});
+
+test( "Clone", 2, function() {
+ var date = $.date(),
+ date2 = date.clone();
+ ok( date2, "Created cloned object" );
+ notEqual( date.adjust( "Y", 1 ).year(), date2.year(), "Object manipulated independently" );
+});
+
+test( "Days", 1, function() {
+ //TODO needs work
+ var date = $.date();
+ date.eachDay = function( day ) {
+ if ( day.lead && day.date > 20 ) {
+ day.selectable = false;
+ day.render = true;
+ day.title = "These are the days of last month";
+ day.extraClasses = "ui-state-disabled";
+ }
+ if ( day.lead && day.date < 3 ) {
+ day.selectable = true;
+ day.render = true;
+ day.extraClasses = "ui-state-disabled";
+ }
+ if ( day.date === 1 ) {
+ day.extraClasses = "ui-state-error";
+ day.title = "Something bad explaining the error highlight";
+ }
+ if ( day.today ) {
+ day.title = "A good day!";
+ }
+ };
+ ok( date.days(), "Date days() returns");
+});
+
+test( "Months", 5, function(){
+ var date = $.date(),
+ firstMonth = date.months( 1 )[ 0 ],
+ lastMonth = date.months( 1 )[ 1 ];
+
+ ok( firstMonth.first );
+ ok( !lastMonth.first );
+ ok( lastMonth.last );
+ ok( !lastMonth.first );
+
+ ok( firstMonth.month() === lastMonth.month() - 1 );
+});
+
+test( "Equal", 4, function() {
+ var date = $.date();
+ date.setFullDate( 2012, 9, 16 );
+ ok( date.equal( new Date( 2012, 9, 16 ) ), "Does date equal provide date" );
+ ok( !date.equal( new Date( 2011, 9, 16 ) ), "Does date year not equal provide date" );
+ ok( !date.equal( new Date( 2012, 8, 16 ) ), "Does date month not equal provide date" );
+ ok( !date.equal( new Date( 2012, 9, 15 ) ), "Does date day not equal provide date" );
+});
+
+test( "Date", 1, function() {
+ var date = $.date();
+ ok( date.date() instanceof Date, "Date returned" );
+});
+
+test( "Format", 4, function() {
+ var date = $.date();
+ date.setFullDate( 2012, 9, 16 );
+ equal( date.format({ date: "short" }), "10/16/12", "Checking default US format" );
+ equal( date.format({ pattern: "yyyy/MM/dd" }), "2012/10/16", "Checking yyyy/MM/dd format" );
+ equal( date.format({ pattern: "yy/dd/MM" }), "12/16/10", "Checking yy/dd/MM format" );
+ equal( date.format({ pattern: "MMMM dd, yyyy" }), "October 16, 2012",
+ "Checking MMMM dd, yyyy format" );
+});
+
+} );
diff --git a/tests/unit/date/date.html b/tests/unit/date/date.html
new file mode 100644
index 000000000..1d9ee6c1f
--- /dev/null
+++ b/tests/unit/date/date.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Date Test Suite</title>
+
+ <script src="../../../external/requirejs/require.js"></script>
+ <script src="../../lib/css.js"></script>
+ <script src="../../lib/bootstrap.js" data-modules="core"></script>
+</head>
+<body>
+
+<div id="qunit"></div>
+<div id="qunit-fixture">
+ <div><input type="text" id="inp"><input type="text" id="alt"><div id="inl"></div></div>
+ <p><input type="text" id="inp2"></p>
+</div>
+</body>
+</html>
diff --git a/tests/unit/datepicker/common.js b/tests/unit/datepicker/common.js
index 1eecc85cb..bd7aca89e 100644
--- a/tests/unit/datepicker/common.js
+++ b/tests/unit/datepicker/common.js
@@ -1,7 +1,35 @@
-/*
-TestHelpers.commonWidgetTests( "datepicker", {
+define( [
+ "lib/common",
+ "ui/datepicker",
+ "globalize-locales"
+], function( common ) {
+
+common.testWidget( "datepicker", {
defaults: {
- disabled: false
+ appendTo: null,
+ buttons: [],
+ classes: {},
+ dateFormat: { date: "short" },
+ disabled: false,
+ eachDay: $.noop,
+ max: null,
+ min: null,
+ numberOfMonths: 1,
+ position: {
+ my: "left top",
+ at: "left bottom"
+ },
+ show: true,
+ showWeek: false,
+ hide: true,
+
+ // callbacks
+ beforeOpen: null,
+ close: null,
+ create: null,
+ open: null,
+ select: null
}
});
-*/
+
+} );
diff --git a/tests/unit/datepicker/core.js b/tests/unit/datepicker/core.js
index 446f6757e..a9f5b0abf 100644
--- a/tests/unit/datepicker/core.js
+++ b/tests/unit/datepicker/core.js
@@ -1,530 +1,173 @@
define( [
"jquery",
- "lib/common",
"./helper",
- "ui/datepicker",
- "ui/i18n/datepicker-he"
-], function( $, common, testHelper ) {
+ "ui/datepicker"
+], function( $, testHelper ) {
-module( "datepicker: core", {
- setup: function() {
- $( "body" ).trigger( "focus" );
- }
-});
-
-common.testJshint( "datepicker" );
-
-test("initialization - Reinitialization after body had been emptied.", function() {
- expect( 1 );
- var bodyContent = $("body").children(), inp = $("#inp");
- $("#inp").datepicker();
- $("body").empty().append(inp);
- $("#inp").datepicker();
- ok( $("#"+$.datepicker._mainDivId).length===1, "Datepicker container added" );
- $("body").empty().append(bodyContent); // Returning to initial state for later tests
-});
-
-test( "widget method - empty collection", function() {
- expect( 1 );
- $( "#nonExist" ).datepicker(); // should create nothing
- ok( !$( "#ui-datepicker-div" ).length, "Non init on empty collection" );
-});
-
-test("widget method", function() {
- expect( 1 );
- var actual = $("#inp").datepicker().datepicker("widget")[0];
- deepEqual($("body > #ui-datepicker-div:last-child")[0], actual);
-});
-
-asyncTest( "baseStructure", function() {
- expect( 58 );
- var header, title, table, thead, week, panel, inl, child,
- inp = testHelper.initNewInput(),
- dp = $( "#ui-datepicker-div" );
-
- function step1() {
- testHelper.onFocus( inp, function() {
- ok( dp.is( ":visible" ), "Structure - datepicker visible" );
- ok( !dp.is( ".ui-datepicker-rtl" ), "Structure - not right-to-left" );
- ok( !dp.is( ".ui-datepicker-multi" ), "Structure - not multi-month" );
- equal( dp.children().length, 2, "Structure - child count" );
-
- header = dp.children( ":first" );
- ok( header.is( "div.ui-datepicker-header" ), "Structure - header division" );
- equal( header.children().length, 3, "Structure - header child count" );
- ok( header.children( ":first" ).is( "a.ui-datepicker-prev" ) && header.children( ":first" ).html() !== "", "Structure - prev link" );
- ok( header.children( ":eq(1)" ).is( "a.ui-datepicker-next" ) && header.children( ":eq(1)" ).html() !== "", "Structure - next link" );
-
- title = header.children( ":last" );
- ok( title.is( "div.ui-datepicker-title" ) && title.html() !== "","Structure - title division" );
- equal( title.children().length, 2, "Structure - title child count" );
- ok( title.children( ":first" ).is( "span.ui-datepicker-month" ) && title.children( ":first" ).text() !== "", "Structure - month text" );
- ok( title.children( ":last" ).is( "span.ui-datepicker-year" ) && title.children( ":last" ).text() !== "", "Structure - year text" );
-
- table = dp.children( ":eq(1)" );
- ok( table.is( "table.ui-datepicker-calendar" ), "Structure - month table" );
- ok( table.children( ":first" ).is( "thead" ), "Structure - month table thead" );
-
- thead = table.children( ":first" ).children( ":first" );
- ok( thead.is( "tr" ), "Structure - month table title row" );
- equal( thead.find( "th" ).length, 7, "Structure - month table title cells" );
- ok( table.children( ":eq(1)" ).is( "tbody" ), "Structure - month table body" );
- ok( table.children( ":eq(1)" ).children( "tr" ).length >= 4, "Structure - month table week count" );
-
- week = table.children( ":eq(1)" ).children( ":first" );
- ok( week.is( "tr" ), "Structure - month table week row" );
- equal( week.children().length, 7, "Structure - week child count" );
- ok( week.children( ":first" ).is( "td.ui-datepicker-week-end" ), "Structure - month table first day cell" );
- ok( week.children( ":last" ).is( "td.ui-datepicker-week-end" ), "Structure - month table second day cell" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step2();
- });
- }
-
- function step2() {
- // Editable month/year and button panel
- inp = testHelper.initNewInput({
- changeMonth: true,
- changeYear: true,
- showButtonPanel: true
- });
- testHelper.onFocus( inp, function() {
- title = dp.find( "div.ui-datepicker-title" );
- ok( title.children( ":first" ).is( "select.ui-datepicker-month" ), "Structure - month selector" );
- ok( title.children( ":last" ).is( "select.ui-datepicker-year" ), "Structure - year selector" );
-
- panel = dp.children( ":last" );
- ok( panel.is( "div.ui-datepicker-buttonpane" ), "Structure - button panel division" );
- equal( panel.children().length, 2, "Structure - button panel child count" );
- ok( panel.children( ":first" ).is( "button.ui-datepicker-current" ), "Structure - today button" );
- ok( panel.children( ":last" ).is( "button.ui-datepicker-close" ), "Structure - close button" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step3();
- });
- }
-
- function step3() {
- // Multi-month 2
- inp = testHelper.initNewInput({ numberOfMonths: 2 });
- testHelper.onFocus( inp, function() {
- ok( dp.is( ".ui-datepicker-multi" ), "Structure multi [2] - multi-month" );
- equal( dp.children().length, 3, "Structure multi [2] - child count" );
-
- child = dp.children( ":first" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2] - first month division" );
-
- child = dp.children( ":eq(1)" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2] - second month division" );
-
- child = dp.children( ":eq(2)" );
- ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2] - row break" );
- ok( dp.is( ".ui-datepicker-multi-2" ), "Structure multi [2] - multi-2" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step4();
- });
- }
-
- function step4() {
- // Multi-month 3
- inp = testHelper.initNewInput({ numberOfMonths: 3 });
- testHelper.onFocus( inp, function() {
- ok( dp.is( ".ui-datepicker-multi-3" ), "Structure multi [3] - multi-3" );
- ok( !dp.is( ".ui-datepicker-multi-2" ), "Structure multi [3] - Trac #6704" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step5();
- });
- }
+module( "datepicker: core" );
- function step5() {
- // Multi-month [2, 2]
- inp = testHelper.initNewInput({ numberOfMonths: [ 2, 2 ] });
- testHelper.onFocus( inp, function() {
- ok( dp.is( ".ui-datepicker-multi" ), "Structure multi - multi-month" );
- equal( dp.children().length, 6, "Structure multi [2,2] - child count" );
+test( "input's value determines starting date", function() {
+ expect( 3 );
- child = dp.children( ":first" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2,2] - first month division" );
+ var input = $( "#datepicker" ).val( "1/1/14" ).datepicker(),
+ picker = input.datepicker( "widget" );
- child = dp.children( ":eq(1)" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2,2] - second month division" );
+ input.datepicker( "open" );
- child = dp.children( ":eq(2)" );
- ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2,2] - row break" );
+ equal( picker.find( ".ui-calendar-month" ).html(), "January", "correct month displayed" );
+ equal( picker.find( ".ui-calendar-year" ).html(), "2014", "correct year displayed" );
+ equal( picker.find( ".ui-state-active" ).html(), "1", "correct day highlighted" );
- child = dp.children( ":eq(3)" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2,2] - third month division" );
-
- child = dp.children( ":eq(4)" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2,2] - fourth month division" );
-
- child = dp.children( ":eq(5)" );
- ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2,2] - row break" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
-
- // Inline
- inl = testHelper.init( "#inl" );
- dp = inl.children();
-
- ok( dp.is( ".ui-datepicker-inline" ), "Structure inline - main div" );
- ok( !dp.is( ".ui-datepicker-rtl" ), "Structure inline - not right-to-left" );
- ok( !dp.is( ".ui-datepicker-multi" ), "Structure inline - not multi-month" );
- equal( dp.children().length, 2, "Structure inline - child count" );
-
- header = dp.children( ":first" );
- ok( header.is( "div.ui-datepicker-header" ), "Structure inline - header division" );
- equal( header.children().length, 3, "Structure inline - header child count" );
-
- table = dp.children( ":eq(1)" );
- ok( table.is( "table.ui-datepicker-calendar" ), "Structure inline - month table" );
- ok( table.children( ":first" ).is( "thead" ), "Structure inline - month table thead" );
- ok( table.children( ":eq(1)" ).is( "tbody" ), "Structure inline - month table body" );
-
- inl.datepicker( "destroy" );
-
- // Inline multi-month
- inl = testHelper.init( "#inl", { numberOfMonths: 2 } );
- dp = inl.children();
+ input.val( "" ).datepicker( "destroy" );
+});
- ok( dp.is( ".ui-datepicker-inline" ) && dp.is( ".ui-datepicker-multi" ), "Structure inline multi - main div" );
- equal( dp.children().length, 3, "Structure inline multi - child count" );
+asyncTest( "base structure", function() {
+ expect( 5 );
- child = dp.children( ":first" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure inline multi - first month division" );
+ var input = testHelper.initNewInput(),
+ widget = input.datepicker( "widget" );
- child = dp.children( ":eq(1)" );
- ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure inline multi - second month division" );
+ input.focus();
- child = dp.children( ":eq(2)" );
- ok( child.is( "div.ui-datepicker-row-break" ), "Structure inline multi - row break" );
+ setTimeout(function() {
+ ok( widget.is( ":visible" ), "Datepicker visible" );
+ equal( widget.children().length, 2, "Child count" );
+ ok( widget.is( ".ui-calendar" ), "Class ui-calendar" );
+ ok( widget.is( ".ui-datepicker" ), "Class ui-datepicker" );
+ ok( widget.is( ".ui-front" ), "Class ui-front" );
- inl.datepicker( "destroy" );
- start();
- });
- }
-
- step1();
+ input.datepicker( "close" );
+ start();
+ }, 50 );
});
-asyncTest( "customStructure", function() {
- expect( 20 );
- var header, panel, title, thead,
- inp = testHelper.initNewInput( $.datepicker.regional.he ),
- dp = $( "#ui-datepicker-div" );
+asyncTest( "Keyboard handling: input", function() {
+ expect( 10 );
+ var picker, instance,
+ input = $( "#datepicker" ).datepicker();
function step1() {
- inp.datepicker( "option", "showButtonPanel", true );
-
- testHelper.onFocus( inp, function() {
- ok( dp.is( ".ui-datepicker-rtl" ), "Structure RTL - right-to-left" );
+ testHelper.init( input );
+ picker = input.datepicker( "widget" );
- header = dp.children( ":first" );
- ok( header.is( "div.ui-datepicker-header" ), "Structure RTL - header division" );
- equal( header.children().length, 3, "Structure RTL - header child count" );
- ok( header.children( ":first" ).is( "a.ui-datepicker-next" ), "Structure RTL - prev link" );
- ok( header.children( ":eq(1)" ).is( "a.ui-datepicker-prev" ), "Structure RTL - next link" );
+ ok( !picker.is( ":visible" ), "datepicker closed" );
- panel = dp.children( ":last" );
- ok( panel.is( "div.ui-datepicker-buttonpane" ), "Structure RTL - button division" );
- equal( panel.children().length, 2, "Structure RTL - button panel child count" );
- ok( panel.children( ":first" ).is( "button.ui-datepicker-close" ), "Structure RTL - close button" );
- ok( panel.children( ":last" ).is( "button.ui-datepicker-current" ), "Structure RTL - today button" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
+ input.val( "" ).simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ setTimeout(function() {
+ ok( picker.is( ":visible" ), "Keystroke down opens datepicker" );
+ input.datepicker( "destroy" );
step2();
- });
+ }, 100 );
}
- // Hide prev/next
function step2() {
- inp = testHelper.initNewInput({
- hideIfNoPrevNext: true,
- minDate: new Date( 2008, 2 - 1, 4 ),
- maxDate: new Date( 2008, 2 - 1, 14 )
- });
- inp.val( "02/10/2008" );
-
- testHelper.onFocus( inp, function() {
- header = dp.children( ":first" );
- ok( header.is( "div.ui-datepicker-header" ), "Structure hide prev/next - header division" );
- equal( header.children().length, 1, "Structure hide prev/next - links child count" );
- ok( header.children( ":first" ).is( "div.ui-datepicker-title" ), "Structure hide prev/next - title division" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step3();
- });
- }
-
- // Changeable Month with read-only year
- function step3() {
- inp = testHelper.initNewInput({ changeMonth: true });
-
- testHelper.onFocus( inp, function() {
- title = dp.children( ":first" ).children( ":last" );
- equal( title.children().length, 2, "Structure changeable month - title child count" );
- ok( title.children( ":first" ).is( "select.ui-datepicker-month" ), "Structure changeable month - month selector" );
- ok( title.children( ":last" ).is( "span.ui-datepicker-year" ), "Structure changeable month - read-only year" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step4();
- });
- }
-
- // Changeable year with read-only month
- function step4() {
- inp = testHelper.initNewInput({ changeYear: true });
+ testHelper.init( input );
+ picker = input.datepicker( "widget" );
- testHelper.onFocus( inp, function() {
- title = dp.children( ":first" ).children( ":last" );
- equal( title.children().length, 2, "Structure changeable year - title child count" );
- ok( title.children( ":first" ).is( "span.ui-datepicker-month" ), "Structure changeable year - read-only month" );
- ok( title.children( ":last" ).is( "select.ui-datepicker-year" ), "Structure changeable year - year selector" );
+ ok( !picker.is( ":visible" ), "datepicker closed" );
- inp.datepicker( "hide" ).datepicker( "destroy" );
- step5();
- });
+ input.val( "" ).simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ setTimeout(function() {
+ ok( picker.is( ":visible" ), "Keystroke up opens datepicker" );
+ input.datepicker( "destroy" );
+ step3();
+ }, 100 );
}
- // Read-only first day of week
- function step5() {
- inp = testHelper.initNewInput({ changeFirstDay: false });
-
- testHelper.onFocus( inp, function() {
- thead = dp.find( ".ui-datepicker-calendar thead tr" );
- equal( thead.children().length, 7, "Structure read-only first day - thead child count" );
- equal( thead.find( "a" ).length, 0, "Structure read-only first day - thead links count" );
-
- inp.datepicker( "hide" ).datepicker( "destroy" );
- start();
- });
+ function step3() {
+ testHelper.init( input );
+ instance = input.datepicker( "instance" );
+
+ // Enter = Select preset date
+ input
+ .val( "1/1/14" )
+ .datepicker( "refresh" )
+ .datepicker( "open" )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ testHelper.equalsDate( input.datepicker( "valueAsDate" ), new Date( 2014, 0, 1 ),
+ "Keystroke enter - preset" );
+
+ input
+ .val( "" )
+ .datepicker( "open" );
+ ok( instance.isOpen, "datepicker is open before escape" );
+
+ input.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ ok( !instance.isOpen, "escape closes the datepicker" );
+
+ input
+ .val( "1/1/14" )
+ .datepicker( "open" )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ testHelper.equalsDate( input.datepicker( "valueAsDate" ), new Date( 2014, 0, 1 ),
+ "Keystroke esc - preset" );
+
+ input
+ .val( "1/1/14" )
+ .datepicker( "open" )
+ .simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ testHelper.equalsDate( input.datepicker( "valueAsDate" ), new Date( 2014, 0, 1 ),
+ "Keystroke esc - abandoned" );
+
+ input
+ .val( "1/2/14" )
+ .simulate( "keyup" );
+ testHelper.equalsDate( input.datepicker( "valueAsDate" ), new Date( 2014, 0, 2 ),
+ "Picker updated as user types into input" );
+
+ input.datepicker( "destroy" );
+ start();
}
- // TODO: figure out why this setTimeout is needed in IE,
- // it only is necessary when the previous baseStructure tests runs first
- // Support: IE
- setTimeout( step1 );
+ step1();
});
-test("keystrokes", function() {
- expect( 26 );
- var inp = testHelper.init("#inp"),
- date = new Date();
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke enter");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
- "Keystroke enter - preset");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+home");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
- ok(inp.datepicker("getDate") == null, "Keystroke ctrl+end");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- ok(inp.datepicker("getDate") == null, "Keystroke esc");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
- "Keystroke esc - preset");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
- "Keystroke esc - abandoned");
- // Moving by day or week
- inp.val("").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.LEFT}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() - 1);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+left");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.LEFT}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 1);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke left");
- inp.val("").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.RIGHT}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 1);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+right");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.RIGHT}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() - 1);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke right");
- inp.val("").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() - 7);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+up");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 7);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke up");
- inp.val("").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 7);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke ctrl+down");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() - 7);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Keystroke down");
- // Moving by month or year
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 1 - 1, 4),
- "Keystroke pgup");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 3 - 1, 4),
- "Keystroke pgdn");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2007, 2 - 1, 4),
- "Keystroke ctrl+pgup");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2009, 2 - 1, 4),
- "Keystroke ctrl+pgdn");
- // Check for moving to short months
- inp.val("03/31/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 29),
- "Keystroke pgup - Feb");
- inp.val("01/30/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 29),
- "Keystroke pgdn - Feb");
- inp.val("02/29/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2007, 2 - 1, 28),
- "Keystroke ctrl+pgup - Feb");
- inp.val("02/29/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2009, 2 - 1, 28),
- "Keystroke ctrl+pgdn - Feb");
- // Goto current
- inp.datepicker("option", {gotoCurrent: true}).
- datepicker("hide").val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
- "Keystroke ctrl+home");
- // Change steps
- inp.datepicker("option", {stepMonths: 2, gotoCurrent: false}).
- datepicker("hide").val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2007, 12 - 1, 4),
- "Keystroke pgup step 2");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 4 - 1, 4),
- "Keystroke pgdn step 2");
+// TODO: implement
+test( "ARIA", function() {
+ expect( 0 );
});
-test("mouse", function() {
- expect( 15 );
- var inl,
- inp = testHelper.init("#inp"),
- dp = $("#ui-datepicker-div"),
- date = new Date();
- inp.val("").datepicker("show");
- $(".ui-datepicker-calendar tbody a:contains(10)", dp).simulate("click", {});
- date.setDate(10);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Mouse click");
- inp.val("02/04/2008").datepicker("show");
- $(".ui-datepicker-calendar tbody a:contains(12)", dp).simulate("click", {});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 12),
- "Mouse click - preset");
- inp.val("02/04/2008").datepicker("show");
- inp.val("").datepicker("show");
- $("button.ui-datepicker-close", dp).simulate("click", {});
- ok(inp.datepicker("getDate") == null, "Mouse click - close");
- inp.val("02/04/2008").datepicker("show");
- $("button.ui-datepicker-close", dp).simulate("click", {});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
- "Mouse click - close + preset");
- inp.val("02/04/2008").datepicker("show");
- $("a.ui-datepicker-prev", dp).simulate("click", {});
- $("button.ui-datepicker-close", dp).simulate("click", {});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 4),
- "Mouse click - abandoned");
- // Current/previous/next
- inp.val("02/04/2008").datepicker("option", {showButtonPanel: true}).datepicker("show");
- $(".ui-datepicker-current", dp).simulate("click", {});
- $(".ui-datepicker-calendar tbody a:contains(14)", dp).simulate("click", {});
- date.setDate(14);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Mouse click - current");
- inp.val("02/04/2008").datepicker("show");
- $(".ui-datepicker-prev", dp).simulate("click");
- $(".ui-datepicker-calendar tbody a:contains(16)", dp).simulate("click");
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 1 - 1, 16),
- "Mouse click - previous");
- inp.val("02/04/2008").datepicker("show");
- $(".ui-datepicker-next", dp).simulate("click");
- $(".ui-datepicker-calendar tbody a:contains(18)", dp).simulate("click");
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 3 - 1, 18),
- "Mouse click - next");
- // Previous/next with minimum/maximum
- inp.datepicker("option", {minDate: new Date(2008, 2 - 1, 2),
- maxDate: new Date(2008, 2 - 1, 26)}).val("02/04/2008").datepicker("show");
- $(".ui-datepicker-prev", dp).simulate("click");
- $(".ui-datepicker-calendar tbody a:contains(16)", dp).simulate("click");
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 16),
- "Mouse click - previous + min/max");
- inp.val("02/04/2008").datepicker("show");
- $(".ui-datepicker-next", dp).simulate("click");
- $(".ui-datepicker-calendar tbody a:contains(18)", dp).simulate("click");
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 2 - 1, 18),
- "Mouse click - next + min/max");
- // Inline
- inl = testHelper.init("#inl");
- dp = $(".ui-datepicker-inline", inl);
- date = new Date();
- inl.datepicker("setDate", date);
- $(".ui-datepicker-calendar tbody a:contains(10)", dp).simulate("click", {});
- date.setDate(10);
- testHelper.equalsDate(inl.datepicker("getDate"), date, "Mouse click inline");
- inl.datepicker("option", {showButtonPanel: true}).datepicker("setDate", new Date(2008, 2 - 1, 4));
- $(".ui-datepicker-calendar tbody a:contains(12)", dp).simulate("click", {});
- testHelper.equalsDate(inl.datepicker("getDate"), new Date(2008, 2 - 1, 12), "Mouse click inline - preset");
- inl.datepicker("option", {showButtonPanel: true});
- $(".ui-datepicker-current", dp).simulate("click", {});
- $(".ui-datepicker-calendar tbody a:contains(14)", dp).simulate("click", {});
- date.setDate(14);
- testHelper.equalsDate(inl.datepicker("getDate"), date, "Mouse click inline - current");
- inl.datepicker("setDate", new Date(2008, 2 - 1, 4));
- $(".ui-datepicker-prev", dp).simulate("click");
- $(".ui-datepicker-calendar tbody a:contains(16)", dp).simulate("click");
- testHelper.equalsDate(inl.datepicker("getDate"), new Date(2008, 1 - 1, 16),
- "Mouse click inline - previous");
- inl.datepicker("setDate", new Date(2008, 2 - 1, 4));
- $(".ui-datepicker-next", dp).simulate("click");
- $(".ui-datepicker-calendar tbody a:contains(18)", dp).simulate("click");
- testHelper.equalsDate(inl.datepicker("getDate"), new Date(2008, 3 - 1, 18),
- "Mouse click inline - next");
+asyncTest( "mouse", function() {
+ expect( 4 );
+
+ var input = testHelper.init( $( "#datepicker" ).val( "" ) ),
+ picker = input.datepicker( "widget" );
+
+ input.datepicker( "open" );
+
+ setTimeout(function() {
+ input.val( "4/4/08" ).datepicker( "refresh" ).datepicker( "open" );
+ $( ".ui-calendar-calendar tbody button:contains(12)", picker ).simulate( "mousedown", {} );
+ testHelper.equalsDate(
+ input.datepicker( "valueAsDate" ),
+ new Date( 2008, 4 - 1, 12 ),
+ "Mouse click - preset"
+ );
+
+ input.val( "" ).datepicker( "refresh" );
+ input.simulate( "click" );
+ strictEqual( input.datepicker( "valueAsDate" ), null, "Mouse click - close" );
+
+ input.val( "4/4/08" ).datepicker( "refresh" ).datepicker( "open" );
+ input.simulate( "click" );
+ testHelper.equalsDate(
+ input.datepicker( "valueAsDate" ),
+ new Date( 2008, 4 - 1, 4 ),
+ "Mouse click - close + preset"
+ );
+
+ input.val( "4/4/08" ).datepicker( "refresh" ).datepicker( "open" );
+ picker.find( "a.ui-calendar-prev" ).simulate( "click" );
+ input.simulate( "click" );
+ testHelper.equalsDate(
+ input.datepicker( "valueAsDate" ),
+ new Date( 2008, 4 - 1, 4 ),
+ "Mouse click - abandoned"
+ );
+
+ start();
+ }, 100 );
});
} );
diff --git a/tests/unit/datepicker/datepicker.html b/tests/unit/datepicker/datepicker.html
index 26d8de3e0..3b20272b1 100644
--- a/tests/unit/datepicker/datepicker.html
+++ b/tests/unit/datepicker/datepicker.html
@@ -5,7 +5,7 @@
<title>jQuery UI Datepicker Test Suite</title>
<script src="../../../external/requirejs/require.js"></script>
- <script src="../../lib/css.js" data-modules="core datepicker"></script>
+ <script src="../../lib/css.js" data-modules="core calendar datepicker"></script>
<script src="../../lib/bootstrap.js" data-widget="datepicker"></script>
</head>
<body>
@@ -13,8 +13,8 @@
<div id="qunit"></div>
<div id="qunit-fixture">
-<div><input type="text" id="inp"><input type="text" id="alt"><div id="inl"></div></div>
-<p><input type="text" id="inp2"></p>
+<input type="text" id="datepicker">
+<input type="text" id="datepicker2">
</div>
</body>
diff --git a/tests/unit/datepicker/events.js b/tests/unit/datepicker/events.js
index 634fb6b79..dcadfecf9 100644
--- a/tests/unit/datepicker/events.js
+++ b/tests/unit/datepicker/events.js
@@ -4,151 +4,135 @@ define( [
"ui/datepicker"
], function( $, testHelper ) {
-module("datepicker: events");
-
-var selectedThis = null,
-selectedDate = null,
-selectedInst = null;
-
-function callback(date, inst) {
- selectedThis = this;
- selectedDate = date;
- selectedInst = inst;
-}
-
-function callback2(year, month, inst) {
- selectedThis = this;
- selectedDate = year + "/" + month;
- selectedInst = inst;
-}
-
-test("events", function() {
- expect( 26 );
- var dateStr, newMonthYear, inp2,
- inp = testHelper.init("#inp", {onSelect: callback}),
- date = new Date();
- // onSelect
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- equal(selectedThis, inp[0], "Callback selected this");
- equal(selectedInst, $.data(inp[0], testHelper.PROP_NAME), "Callback selected inst");
- equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
- "Callback selected date");
- inp.val("").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 7);
- equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
- "Callback selected date - ctrl+down");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", date),
- "Callback selected date - esc");
- dateStr = "02/04/2008";
- inp.val(dateStr).datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- equal(dateStr, selectedDate,
- "onSelect is called after enter keydown");
- // onChangeMonthYear
- inp.datepicker("option", {onChangeMonthYear: callback2, onSelect: null}).
- val("").datepicker("show");
- newMonthYear = function(date) {
- return date.getFullYear() + "/" + (date.getMonth() + 1);
- };
- date = new Date();
- date.setDate(1);
- inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP});
- date.setMonth(date.getMonth() - 1);
- equal(selectedThis, inp[0], "Callback change month/year this");
- equal(selectedInst, $.data(inp[0], testHelper.PROP_NAME), "Callback change month/year inst");
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year date - pgup");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
- date.setMonth(date.getMonth() + 1);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year date - pgdn");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
- date.setFullYear(date.getFullYear() - 1);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year date - ctrl+pgup");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.HOME});
- date.setFullYear(date.getFullYear() + 1);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year date - ctrl+home");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
- date.setFullYear(date.getFullYear() + 1);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year date - ctrl+pgdn");
- inp.datepicker("setDate", new Date(2007, 1 - 1, 26));
- equal(selectedDate, "2007/1", "Callback change month/year date - setDate");
- selectedDate = null;
- inp.datepicker("setDate", new Date(2007, 1 - 1, 12));
- ok(selectedDate == null, "Callback change month/year date - setDate no change");
- // onChangeMonthYear step by 2
- inp.datepicker("option", {stepMonths: 2}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.PAGE_UP});
- date.setMonth(date.getMonth() - 14);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year by 2 date - pgup");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
- date.setMonth(date.getMonth() - 12);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year by 2 date - ctrl+pgup");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
- date.setMonth(date.getMonth() + 2);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year by 2 date - pgdn");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
- date.setMonth(date.getMonth() + 12);
- equal(selectedDate, newMonthYear(date),
- "Callback change month/year by 2 date - ctrl+pgdn");
- // onClose
- inp.datepicker("option", {onClose: callback, onChangeMonthYear: null, stepMonths: 1}).
- val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- equal(selectedThis, inp[0], "Callback close this");
- equal(selectedInst, $.data(inp[0], testHelper.PROP_NAME), "Callback close inst");
- equal(selectedDate, "", "Callback close date - esc");
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- equal(selectedDate, $.datepicker.formatDate("mm/dd/yy", new Date()),
- "Callback close date - enter");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- equal(selectedDate, "02/04/2008", "Callback close date - preset");
- inp.val("02/04/2008").datepicker("show").
- simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
- equal(selectedDate, "", "Callback close date - ctrl+end");
-
- inp2 = testHelper.init("#inp2");
- inp2.datepicker().datepicker("option", {onClose: callback}).datepicker("show");
- inp.datepicker("show");
- equal(selectedThis, inp2[0], "Callback close this");
-});
+module( "datepicker: events" );
-test("beforeShowDay-getDate", function() {
+test( "beforeOpen", function() {
expect( 3 );
- var inp = testHelper.init("#inp", {beforeShowDay: function() { inp.datepicker("getDate"); return [true, ""]; }}),
- dp = $("#ui-datepicker-div");
- inp.val("01/01/2010").datepicker("show");
- // contains non-breaking space
- equal($("div.ui-datepicker-title").text(),
- // support: IE <9, jQuery <1.8
- // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways
- $( "<span>January&#xa0;2010</span>" ).text(), "Initial month");
- $("a.ui-datepicker-next", dp).trigger( "click" );
- $("a.ui-datepicker-next", dp).trigger( "click" );
- // contains non-breaking space
- equal($("div.ui-datepicker-title").text(),
- $( "<span>March&#xa0;2010</span>" ).text(), "After next clicks");
- inp.datepicker("hide").datepicker("show");
- $("a.ui-datepicker-prev", dp).trigger( "click" );
- $("a.ui-datepicker-prev", dp).trigger( "click" );
- // contains non-breaking space
- equal($("div.ui-datepicker-title").text(),
- $( "<span>November&#xa0;2009</span>" ).text(), "After prev clicks");
- inp.datepicker("hide");
+
+ var input = testHelper.init( "#datepicker", {
+ beforeOpen: function() {
+ ok( true, "beforeOpen event fired before open" );
+ ok( input.datepicker( "widget" ).is( ":hidden" ), "calendar hidden on beforeOpen" );
+ },
+ open: function() {
+ ok( input.datepicker( "widget" ).is( ":visible" ), "calendar open on open" );
+ }
+ });
+
+ input
+ .datepicker( "open" )
+ .datepicker( "close" )
+ .datepicker( "option", {
+ beforeOpen: function() {
+ return false;
+ },
+ open: function() {
+ ok( false, "calendar should not open when openBefore is canceled" );
+ }
+ })
+ .datepicker( "open" );
+});
+
+test( "close", function() {
+ expect( 4 );
+
+ var shouldFire,
+ input = testHelper.init( "#datepicker", {
+ close: function() {
+ ok( shouldFire, "close event fired" );
+ }
+ });
+
+ shouldFire = false;
+ input.datepicker( "open" );
+ shouldFire = true;
+ input.datepicker( "close" );
+
+ shouldFire = false;
+ input.datepicker( "open" );
+ shouldFire = true;
+ $( "body" ).trigger( "mousedown" );
+
+ shouldFire = false;
+ input.datepicker( "open" );
+ shouldFire = true;
+ input.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+
+ shouldFire = false;
+ input.datepicker( "open" );
+ shouldFire = true;
+ input.datepicker( "widget" ).find( "tbody tr:first button:first" ).simulate( "mousedown" );
+});
+
+test( "open", function() {
+ expect( 2 );
+
+ var input = testHelper.init( "#datepicker", {
+ open: function() {
+ ok( true, "open event fired on open" );
+ ok( widget.is( ":visible" ), "calendar open on open" );
+ }
+ }),
+ widget = input.datepicker( "widget" );
+
+ input.datepicker( "open" );
+});
+
+asyncTest( "select", function() {
+ expect( 4 );
+
+ var input = testHelper.init( "#datepicker", {
+ select: function( event ) {
+ ok( true, "select event fired " + message );
+ equal(
+ event.originalEvent.type,
+ "calendarselect",
+ "select originalEvent " + message
+ );
+ }
+ }),
+ widget = input.datepicker( "widget" ),
+ message = "";
+
+ function step1() {
+ message = "on calendar cell click";
+ input
+ .simulate( "focus" )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ setTimeout(function() {
+ widget.find( "tbody tr:first button:first" ).simulate( "mousedown" );
+ input.datepicker( "close" );
+ step2();
+ }, 100 );
+ }
+
+ function step2() {
+ message = "on calendar cell enter";
+ input
+ .simulate( "focus" )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ setTimeout(function() {
+ $( document.activeElement )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ input.datepicker( "close" );
+ step3();
+ }, 100 );
+ }
+
+ function step3() {
+ message = "on calendar escape (not expected)";
+ input
+ .simulate( "focus" )
+ .simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ setTimeout(function() {
+ $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ input.datepicker( "close" );
+ start();
+ }, 100 );
+ }
+
+ step1();
});
} );
diff --git a/tests/unit/datepicker/helper.js b/tests/unit/datepicker/helper.js
index 4cd9b48ff..7cc21bb66 100644
--- a/tests/unit/datepicker/helper.js
+++ b/tests/unit/datepicker/helper.js
@@ -5,34 +5,30 @@ define( [
], function( $, helper ) {
return $.extend( helper, {
- addMonths: function(date, offset) {
- var maxDay = 32 - new Date(date.getFullYear(), date.getMonth() + offset, 32).getDate();
- date.setDate(Math.min(date.getDate(), maxDay));
- date.setMonth(date.getMonth() + offset);
+ addMonths: function( date, offset ) {
+ var maxDay = 32 - new Date( date.getFullYear(), date.getMonth() + offset, 32 ).getDate();
+ date.setDate( Math.min( date.getDate(), maxDay ) );
+ date.setMonth( date.getMonth() + offset );
return date;
},
-
- equalsDate: function(d1, d2, message) {
- if (!d1 || !d2) {
- ok(false, message + " - missing date");
+ equalsDate: function( d1, d2, message ) {
+ if ( !d1 || !d2 ) {
+ ok( false, message + " - missing date" );
return;
}
- d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
- d2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
- equal(d1.toString(), d2.toString(), message);
+ d1 = new Date( d1.getFullYear(), d1.getMonth(), d1.getDate() );
+ d2 = new Date( d2.getFullYear(), d2.getMonth(), d2.getDate() );
+ equal( d1.toString(), d2.toString(), message );
},
-
init: function( id, options ) {
- $.datepicker.setDefaults( $.datepicker.regional[ "" ] );
- return $( id ).datepicker( $.extend( { showAnim: "" }, options || {} ) );
+ options = $.extend( { show: false, hide: false }, options || {} );
+ return $( id ).datepicker( options );
},
-
initNewInput: function( options ) {
- var id = $( "<input>" ).appendTo( "#qunit-fixture" );
- return this.init( id, options );
- },
-
- PROP_NAME: "datepicker"
+ options = $.extend( { show: false, hide: false }, options || {} );
+ return $( "<input>" ).datepicker( options )
+ .appendTo( "#qunit-fixture" );
+ }
} );
} );
diff --git a/tests/unit/datepicker/methods.js b/tests/unit/datepicker/methods.js
index 14fefacc2..db3762fff 100644
--- a/tests/unit/datepicker/methods.js
+++ b/tests/unit/datepicker/methods.js
@@ -4,123 +4,125 @@ define( [
"ui/datepicker"
], function( $, testHelper ) {
-module("datepicker: methods");
-
-test("destroy", function() {
- expect( 33 );
- var inl,
- inp = testHelper.init("#inp");
- ok(inp.is(".hasDatepicker"), "Default - marker class set");
- ok($.data(inp[0], testHelper.PROP_NAME), "Default - instance present");
- ok(inp.next().is("#alt"), "Default - button absent");
- inp.datepicker("destroy");
- inp = $("#inp");
- ok(!inp.is(".hasDatepicker"), "Default - marker class cleared");
- ok(!$.data(inp[0], testHelper.PROP_NAME), "Default - instance absent");
- ok(inp.next().is("#alt"), "Default - button absent");
- // With button
- inp= testHelper.init("#inp", {showOn: "both"});
- ok(inp.is(".hasDatepicker"), "Button - marker class set");
- ok($.data(inp[0], testHelper.PROP_NAME), "Button - instance present");
- ok(inp.next().text() === "...", "Button - button added");
- inp.datepicker("destroy");
- inp = $("#inp");
- ok(!inp.is(".hasDatepicker"), "Button - marker class cleared");
- ok(!$.data(inp[0], testHelper.PROP_NAME), "Button - instance absent");
- ok(inp.next().is("#alt"), "Button - button removed");
- // With append text
- inp = testHelper.init("#inp", {appendText: "Testing"});
- ok(inp.is(".hasDatepicker"), "Append - marker class set");
- ok($.data(inp[0], testHelper.PROP_NAME), "Append - instance present");
- ok(inp.next().text() === "Testing", "Append - append text added");
- inp.datepicker("destroy");
- inp = $("#inp");
- ok(!inp.is(".hasDatepicker"), "Append - marker class cleared");
- ok(!$.data(inp[0], testHelper.PROP_NAME), "Append - instance absent");
- ok(inp.next().is("#alt"), "Append - append text removed");
- // With both
- inp= testHelper.init("#inp", {showOn: "both", buttonImageOnly: true,
- buttonImage: "images/calendar.gif", appendText: "Testing"});
- ok(inp.is(".hasDatepicker"), "Both - marker class set");
- ok($.data(inp[0], testHelper.PROP_NAME), "Both - instance present");
- ok(inp.next()[0].nodeName.toLowerCase() === "img", "Both - button added");
- ok(inp.next().next().text() === "Testing", "Both - append text added");
- inp.datepicker("destroy");
- inp = $("#inp");
- ok(!inp.is(".hasDatepicker"), "Both - marker class cleared");
- ok(!$.data(inp[0], testHelper.PROP_NAME), "Both - instance absent");
- ok(inp.next().is("#alt"), "Both - button and append text absent");
- // Inline
- inl = testHelper.init("#inl");
- ok(inl.is(".hasDatepicker"), "Inline - marker class set");
- ok(inl.html() !== "", "Inline - datepicker present");
- ok($.data(inl[0], testHelper.PROP_NAME), "Inline - instance present");
- ok(inl.next().length === 0 || inl.next().is("p"), "Inline - button absent");
- inl.datepicker("destroy");
- inl = $("#inl");
- ok(!inl.is(".hasDatepicker"), "Inline - marker class cleared");
- ok(inl.html() === "", "Inline - datepicker absent");
- ok(!$.data(inl[0], testHelper.PROP_NAME), "Inline - instance absent");
- ok(inl.next().length === 0 || inl.next().is("p"), "Inline - button absent");
+module( "datepicker: methods" );
+
+test( "destroy", function( assert ) {
+ expect( 3 );
+
+ var input = $( "#datepicker" );
+ assert.domEqual( input, function() {
+ input.datepicker();
+ ok( input.attr( "aria-owns" ), "aria-owns attribute added" );
+ ok( input.attr( "aria-haspopup" ), "aria-haspopup attribute added" );
+ input.datepicker( "destroy" );
+ });
+});
+
+test( "enable / disable", function() {
+ expect( 10 );
+
+ var input = testHelper.init( "#datepicker" ),
+ calendar = input.datepicker( "widget" );
+
+ input.datepicker( "disable" );
+ ok( input.datepicker( "option", "disabled" ), "disabled option is set" );
+ ok( calendar.hasClass( "ui-datepicker-disabled" ), "has disabled widget class name" );
+ ok( input.hasClass( "ui-state-disabled" ), "has disabled state class name" );
+ equal( input.attr( "aria-disabled" ), "true", "has ARIA disabled" );
+ equal( input.attr( "disabled" ), "disabled", "input disabled" );
+
+ input.datepicker( "enable" );
+ ok( !input.datepicker( "option", "disabled" ), "enabled after enable() call" );
+ ok( !calendar.hasClass( "ui-datepicker-disabled" ), "no longer has disabled widget class name" );
+ ok( !input.hasClass( "ui-state-disabled" ), "no longer has disabled state class name" );
+ equal( input.attr( "aria-disabled" ), "false", "no longer has ARIA disabled" );
+ equal( input.attr( "disabled" ), undefined, "input no longer disabled" );
+});
+
+test( "widget", function() {
+ expect( 1 );
+
+ var actual = $( "#datepicker" ).datepicker().datepicker( "widget" );
+ deepEqual( $( "body > .ui-front" )[ 0 ], actual[ 0 ] );
+ actual.remove();
+});
+
+test( "open / close", function() {
+ expect( 7 );
+
+ var input = testHelper.initNewInput({ show: false, hide: false }),
+ calendar = input.datepicker( "widget" );
+
+ ok( calendar.is( ":hidden" ), "calendar hidden on init" );
+
+ input.datepicker( "open" );
+ ok( calendar.is( ":visible" ), "open: calendar visible" );
+ equal( calendar.attr( "aria-hidden" ), "false", "open: calendar aria-hidden" );
+ equal( calendar.attr( "aria-expanded" ), "true", "close: calendar aria-expanded" );
+
+ input.datepicker( "close" );
+ ok( !calendar.is( ":visible" ), "close: calendar hidden" );
+ equal( calendar.attr( "aria-hidden" ), "true", "close: calendar aria-hidden" );
+ equal( calendar.attr( "aria-expanded" ), "false", "close: calendar aria-expanded" );
});
-test("enableDisable", function() {
- expect( 33 );
- var inl, dp,
- inp = testHelper.init("#inp");
- ok(!inp.datepicker("isDisabled"), "Enable/disable - initially marked as enabled");
- ok(!inp[0].disabled, "Enable/disable - field initially enabled");
- inp.datepicker("disable");
- ok(inp.datepicker("isDisabled"), "Enable/disable - now marked as disabled");
- ok(inp[0].disabled, "Enable/disable - field now disabled");
- inp.datepicker("enable");
- ok(!inp.datepicker("isDisabled"), "Enable/disable - now marked as enabled");
- ok(!inp[0].disabled, "Enable/disable - field now enabled");
- inp.datepicker("destroy");
- // With a button
- inp = testHelper.init("#inp", {showOn: "button"});
- ok(!inp.datepicker("isDisabled"), "Enable/disable button - initially marked as enabled");
- ok(!inp[0].disabled, "Enable/disable button - field initially enabled");
- ok(!inp.next("button")[0].disabled, "Enable/disable button - button initially enabled");
- inp.datepicker("disable");
- ok(inp.datepicker("isDisabled"), "Enable/disable button - now marked as disabled");
- ok(inp[0].disabled, "Enable/disable button - field now disabled");
- ok(inp.next("button")[0].disabled, "Enable/disable button - button now disabled");
- inp.datepicker("enable");
- ok(!inp.datepicker("isDisabled"), "Enable/disable button - now marked as enabled");
- ok(!inp[0].disabled, "Enable/disable button - field now enabled");
- ok(!inp.next("button")[0].disabled, "Enable/disable button - button now enabled");
- inp.datepicker("destroy");
- // With an image button
- inp = testHelper.init("#inp", {showOn: "button", buttonImageOnly: true,
- buttonImage: "images/calendar.gif"});
- ok(!inp.datepicker("isDisabled"), "Enable/disable image - initially marked as enabled");
- ok(!inp[0].disabled, "Enable/disable image - field initially enabled");
- ok(parseFloat(inp.next("img").css("opacity")) === 1, "Enable/disable image - image initially enabled");
- inp.datepicker("disable");
- ok(inp.datepicker("isDisabled"), "Enable/disable image - now marked as disabled");
- ok(inp[0].disabled, "Enable/disable image - field now disabled");
- ok(parseFloat(inp.next("img").css("opacity")) !== 1, "Enable/disable image - image now disabled");
- inp.datepicker("enable");
- ok(!inp.datepicker("isDisabled"), "Enable/disable image - now marked as enabled");
- ok(!inp[0].disabled, "Enable/disable image - field now enabled");
- ok(parseFloat(inp.next("img").css("opacity")) === 1, "Enable/disable image - image now enabled");
- inp.datepicker("destroy");
- // Inline
- inl = testHelper.init("#inl", {changeYear: true});
- dp = $(".ui-datepicker-inline", inl);
- ok(!inl.datepicker("isDisabled"), "Enable/disable inline - initially marked as enabled");
- ok(!dp.children().is(".ui-state-disabled"), "Enable/disable inline - not visually disabled initially");
- ok(!dp.find("select").prop("disabled"), "Enable/disable inline - form element enabled initially");
- inl.datepicker("disable");
- ok(inl.datepicker("isDisabled"), "Enable/disable inline - now marked as disabled");
- ok(dp.children().is(".ui-state-disabled"), "Enable/disable inline - visually disabled");
- ok(dp.find("select").prop("disabled"), "Enable/disable inline - form element disabled");
- inl.datepicker("enable");
- ok(!inl.datepicker("isDisabled"), "Enable/disable inline - now marked as enabled");
- ok(!dp.children().is(".ui-state-disabled"), "Enable/disable inline - not visiually disabled");
- ok(!dp.find("select").prop("disabled"), "Enable/disable inline - form element enabled");
- inl.datepicker("destroy");
+test( "value", function() {
+ expect( 4 );
+
+ var input = $( "#datepicker" ).datepicker(),
+ picker = input.datepicker( "widget" );
+
+ input.datepicker( "value", "1/1/14" );
+ equal( input.val(), "1/1/14", "input's value set" );
+
+ input.datepicker( "open" );
+ ok(
+ picker.find( "button[data-timestamp]" ).eq( 0 ).hasClass( "ui-state-active" ),
+ "first day marked as selected"
+ );
+ equal( input.datepicker( "value" ), "1/1/14", "getter" );
+
+ input.val( "abc" );
+ strictEqual( input.datepicker( "value" ), null, "Invalid values should return null." );
+});
+
+test( "valueAsDate", function() {
+ expect( 6 );
+
+ var input = testHelper.init( "#datepicker" ),
+ picker = input.datepicker( "widget" ),
+ date1 = new Date( 2008, 6 - 1, 4 );
+
+ input.datepicker( "valueAsDate", new Date( 2014, 0, 1 ) );
+ equal( input.val(), "1/1/14", "Input's value set" );
+ ok(
+ picker.find( "button[data-timestamp]" ).eq( 0 ).hasClass( "ui-state-active" ),
+ "First day marked as selected"
+ );
+ testHelper.equalsDate( input.datepicker( "valueAsDate" ), new Date( 2014, 0, 1 ), "Getter" );
+
+ input.val( "a/b/c" );
+ equal( input.datepicker( "valueAsDate" ), null, "Invalid dates return null" );
+
+ input.val( "" ).datepicker( "destroy" );
+ input = testHelper.init( "#datepicker" );
+
+ strictEqual( input.datepicker( "valueAsDate" ), null, "Set date - default" );
+ input.datepicker( "valueAsDate", date1 );
+ testHelper.equalsDate( input.datepicker( "valueAsDate" ), date1, "Set date - 2008-06-04" );
+});
+
+test( "isValid", function() {
+ expect( 2 );
+ var input = $( "#datepicker" ).datepicker();
+
+ input.val( "1/1/14" );
+ ok( input.datepicker( "isValid" ) );
+
+ input.val( "1/1/abc" );
+ ok( !input.datepicker( "isValid" ) );
+
+ input.datepicker( "destroy" );
});
} );
diff --git a/tests/unit/datepicker/options.js b/tests/unit/datepicker/options.js
index 573b29b32..32979eac8 100644
--- a/tests/unit/datepicker/options.js
+++ b/tests/unit/datepicker/options.js
@@ -1,1127 +1,136 @@
define( [
"jquery",
"./helper",
- "ui/datepicker",
- "ui/i18n/datepicker-fr",
- "ui/i18n/datepicker-he",
- "ui/i18n/datepicker-zh-CN"
+ "ui/datepicker"
], function( $, testHelper ) {
-module("datepicker: options");
-
-test("setDefaults", function() {
- expect( 3 );
- testHelper.init("#inp");
- equal($.datepicker._defaults.showOn, "focus", "Initial showOn");
- $.datepicker.setDefaults({showOn: "button"});
- equal($.datepicker._defaults.showOn, "button", "Change default showOn");
- $.datepicker.setDefaults({showOn: "focus"});
- equal($.datepicker._defaults.showOn, "focus", "Restore showOn");
-});
-
-test("option", function() {
- expect( 17 );
- var inp = testHelper.init("#inp"),
- inst = $.data(inp[0], testHelper.PROP_NAME);
- // Set option
- equal(inst.settings.showOn, null, "Initial setting showOn");
- equal($.datepicker._get(inst, "showOn"), "focus", "Initial instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Initial default showOn");
- inp.datepicker("option", "showOn", "button");
- equal(inst.settings.showOn, "button", "Change setting showOn");
- equal($.datepicker._get(inst, "showOn"), "button", "Change instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
- inp.datepicker("option", {showOn: "both"});
- equal(inst.settings.showOn, "both", "Change setting showOn");
- equal($.datepicker._get(inst, "showOn"), "both", "Change instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
- inp.datepicker("option", "showOn", undefined);
- equal(inst.settings.showOn, null, "Clear setting showOn");
- equal($.datepicker._get(inst, "showOn"), "focus", "Restore instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
- // Get option
- inp = testHelper.init("#inp");
- equal(inp.datepicker("option", "showOn"), "focus", "Initial setting showOn");
- inp.datepicker("option", "showOn", "button");
- equal(inp.datepicker("option", "showOn"), "button", "Change instance showOn");
- inp.datepicker("option", "showOn", undefined);
- equal(inp.datepicker("option", "showOn"), "focus", "Reset instance showOn");
- deepEqual(inp.datepicker("option", "all"), {showAnim: ""}, "Get instance settings");
- deepEqual(inp.datepicker("option", "defaults"), $.datepicker._defaults,
- "Get default settings");
-});
-
-test( "disabled", function() {
- expect(8);
- var inp = testHelper.init("#inp");
- ok(!inp.datepicker("isDisabled"), "Initially marked as enabled");
- ok(!inp[0].disabled, "Field initially enabled");
- inp.datepicker("option", "disabled", true);
- ok(inp.datepicker("isDisabled"), "Marked as disabled");
- ok(inp[0].disabled, "Field now disabled");
- inp.datepicker("option", "disabled", false);
- ok(!inp.datepicker("isDisabled"), "Marked as enabled");
- ok(!inp[0].disabled, "Field now enabled");
- inp.datepicker("destroy");
-
- inp = testHelper.init("#inp", { disabled: true });
- ok(inp.datepicker("isDisabled"), "Initially marked as disabled");
- ok(inp[0].disabled, "Field initially disabled");
-});
-
-test("change", function() {
- expect( 12 );
- var inp = testHelper.init("#inp"),
- inst = $.data(inp[0], testHelper.PROP_NAME);
- equal(inst.settings.showOn, null, "Initial setting showOn");
- equal($.datepicker._get(inst, "showOn"), "focus", "Initial instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Initial default showOn");
- inp.datepicker("change", "showOn", "button");
- equal(inst.settings.showOn, "button", "Change setting showOn");
- equal($.datepicker._get(inst, "showOn"), "button", "Change instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
- inp.datepicker("change", {showOn: "both"});
- equal(inst.settings.showOn, "both", "Change setting showOn");
- equal($.datepicker._get(inst, "showOn"), "both", "Change instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
- inp.datepicker("change", "showOn", undefined);
- equal(inst.settings.showOn, null, "Clear setting showOn");
- equal($.datepicker._get(inst, "showOn"), "focus", "Restore instance showOn");
- equal($.datepicker._defaults.showOn, "focus", "Retain default showOn");
-});
-
-(function() {
- var url = window.location.search;
- url = decodeURIComponent( url.slice( url.indexOf( "swarmURL=" ) + 9 ) );
-
- // TODO: This test occassionally fails in IE in TestSwarm
- if ( $.ui.ie && url && url.indexOf( "http" ) === 0 ) {
- return;
- }
-
- asyncTest( "invocation", function() {
- var button, image,
- isOldIE = $.ui.ie && ( !document.documentMode || document.documentMode < 9 ),
- body = $( "body" );
-
- expect( isOldIE ? 25 : 29 );
-
- function step0() {
- var inp = testHelper.initNewInput(),
- dp = $( "#ui-datepicker-div" );
-
- button = inp.siblings( "button" );
- ok( button.length === 0, "Focus - button absent" );
- image = inp.siblings( "img" );
- ok( image.length === 0, "Focus - image absent" );
-
- testHelper.onFocus( inp, function() {
- ok( dp.is( ":visible" ), "Focus - rendered on focus" );
- inp.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
- ok( !dp.is( ":visible" ), "Focus - hidden on exit" );
- step1();
- });
- }
-
- function step1() {
-
- var inp = testHelper.initNewInput(),
- dp = $( "#ui-datepicker-div" );
-
- testHelper.onFocus( inp, function() {
- ok( dp.is( ":visible" ), "Focus - rendered on focus" );
- body.simulate( "mousedown", {} );
- ok( !dp.is( ":visible" ), "Focus - hidden on external click" );
- inp.datepicker( "hide" ).datepicker( "destroy" );
-
- step2();
- });
+module( "datepicker: options" );
+
+test( "appendTo", function() {
+ expect( 6 );
+ var container,
+ detached = $( "<div>" ),
+ input = $( "#datepicker" );
+
+ input.datepicker();
+ container = input.datepicker( "widget" ).parent()[ 0 ];
+ equal( container, document.body, "defaults to body" );
+ input.datepicker( "destroy" );
+
+ input.datepicker({ appendTo: "#qunit-fixture" });
+ container = input.datepicker( "widget" ).parent()[ 0 ];
+ equal( container, $( "#qunit-fixture" )[ 0 ], "child of specified element" );
+ input.datepicker( "destroy" );
+
+ input.datepicker({ appendTo: "#does-not-exist" });
+ container = input.datepicker( "widget" ).parent()[ 0 ];
+ equal( container, document.body, "set to body if element does not exist" );
+ input.datepicker( "destroy" );
+
+ input.datepicker()
+ .datepicker( "option", "appendTo", "#qunit-fixture" );
+ container = input.datepicker( "widget" ).parent()[ 0 ];
+ equal( container, $( "#qunit-fixture" )[ 0 ], "modified after init" );
+ input.datepicker( "destroy" );
+
+ input.datepicker({ appendTo: detached });
+ container = input.datepicker( "widget" ).parent()[ 0 ];
+ equal( container, detached[ 0 ], "detached jQuery object" );
+ input.datepicker( "destroy" );
+
+ input.datepicker({ appendTo: detached[ 0 ] });
+ container = input.datepicker( "widget" ).parent()[ 0 ];
+ equal( container, detached[ 0 ], "detached DOM element" );
+ input.datepicker( "destroy" );
+});
+
+test( "Pass-through options", function() {
+ expect( 9 );
+
+ var options = {
+ buttons: { "Test": $.noop },
+ dateFormat: { date: "full" },
+ disabled: true,
+ eachDay: function( day ) { day; },
+ max: new Date( 2000, 0, 1 ),
+ min: new Date( 2000, 0, 2 ),
+ numberOfMonths: 3,
+ showWeek: true
+ },
+ input = $( "#datepicker" ).val( "1/1/14" ).datepicker(),
+ datepickerInstance = input.datepicker( "instance" );
+
+ $.each( options, function( key, value ) {
+ input.datepicker( "option", key, value );
+
+ deepEqual(
+ datepickerInstance.calendar.calendar( "option", key ),
+ value,
+ "option " + key + ": correct value"
+ );
+
+ if ( key === "dateFormat" ) {
+ equal( input.val(), "Wednesday, January 1, 2014", "option " + key + ": updated format" );
}
-
- function step2() {
- var inp = testHelper.initNewInput({
- showOn: "button",
- buttonText: "Popup"
- }),
- dp = $( "#ui-datepicker-div" );
-
- ok( !dp.is( ":visible" ), "Button - initially hidden" );
- button = inp.siblings( "button" );
- image = inp.siblings( "img" );
- ok( button.length === 1, "Button - button present" );
- ok( image.length === 0, "Button - image absent" );
- equal( button.text(), "Popup", "Button - button text" );
-
- testHelper.onFocus( inp, function() {
- ok( !dp.is( ":visible" ), "Button - not rendered on focus" );
- button.trigger( "click" );
- ok( dp.is( ":visible" ), "Button - rendered on button click" );
- button.trigger( "click" );
- ok( !dp.is( ":visible" ), "Button - hidden on second button click" );
- inp.datepicker( "hide" ).datepicker( "destroy" );
-
- step3();
- });
- }
-
- function step3() {
- var inp = testHelper.initNewInput({
- showOn: "button",
- buttonImageOnly: true,
- buttonImage: "images/calendar.gif",
- buttonText: "Cal"
- }),
- dp = $( "#ui-datepicker-div" );
-
- ok( !dp.is( ":visible" ), "Image button - initially hidden" );
- button = inp.siblings( "button" );
- ok( button.length === 0, "Image button - button absent" );
- image = inp.siblings( "img" );
- ok( image.length === 1, "Image button - image present" );
- ok( /images\/calendar\.gif$/.test( image.attr( "src" ) ), "Image button - image source" );
- equal( image.attr( "title" ), "Cal", "Image button - image text" );
-
- testHelper.onFocus( inp, function() {
- ok( !dp.is( ":visible" ), "Image button - not rendered on focus" );
- image.trigger( "click" );
- ok( dp.is( ":visible" ), "Image button - rendered on image click" );
- image.trigger( "click" );
- ok( !dp.is( ":visible" ), "Image button - hidden on second image click" );
- inp.datepicker( "hide" ).datepicker( "destroy" );
-
- step4();
- });
- }
-
- function step4() {
- var inp = testHelper.initNewInput({
- showOn: "both",
- buttonImage: "images/calendar.gif"
- }),
- dp = $( "#ui-datepicker-div" );
-
- ok( !dp.is( ":visible" ), "Both - initially hidden" );
- button = inp.siblings( "button" );
- ok( button.length === 1, "Both - button present" );
- image = inp.siblings( "img" );
- ok( image.length === 0, "Both - image absent" );
- image = button.children( "img" );
- ok( image.length === 1, "Both - button image present" );
-
- // TODO: This test occasionally fails to focus in IE8 in BrowserStack
- if ( !isOldIE ) {
- testHelper.onFocus( inp, function() {
- ok( dp.is( ":visible" ), "Both - rendered on focus" );
- body.simulate( "mousedown", {} );
- ok( !dp.is( ":visible" ), "Both - hidden on external click" );
- button.trigger( "click" );
- ok( dp.is( ":visible" ), "Both - rendered on button click" );
- button.trigger( "click" );
- ok( !dp.is( ":visible" ), "Both - hidden on second button click" );
- inp.datepicker( "hide" ).datepicker( "destroy" );
-
- start();
- });
- } else {
- start();
- }
- }
-
- step0();
});
-})();
-
-test("otherMonths", function() {
- expect( 8 );
- var inp = testHelper.init("#inp"),
- pop = $("#ui-datepicker-div");
- inp.val("06/01/2009").datepicker("show");
- equal(pop.find("tbody").text(),
- // support: IE <9, jQuery <1.8
- // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways
- $( "<span>\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0</span>" ).text(),
- "Other months - none");
- ok(pop.find("td:last *").length === 0, "Other months - no content");
- inp.datepicker("hide").datepicker("option", "showOtherMonths", true).datepicker("show");
- equal(pop.find("tbody").text(), "311234567891011121314151617181920212223242526272829301234",
- "Other months - show");
- ok(pop.find("td:last span").length === 1, "Other months - span content");
- inp.datepicker("hide").datepicker("option", "selectOtherMonths", true).datepicker("show");
- equal(pop.find("tbody").text(), "311234567891011121314151617181920212223242526272829301234",
- "Other months - select");
- ok(pop.find("td:last a").length === 1, "Other months - link content");
- inp.datepicker("hide").datepicker("option", "showOtherMonths", false).datepicker("show");
- equal(pop.find("tbody").text(),
- // support: IE <9, jQuery <1.8
- // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways
- $( "<span>\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0</span>" ).text(),
- "Other months - none");
- ok(pop.find("td:last *").length === 0, "Other months - no content");
-});
-
-test("defaultDate", function() {
- expect( 16 );
- var inp = testHelper.init("#inp"),
- date = new Date();
- inp.val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date null");
-
- // Numeric values
- inp.datepicker("option", {defaultDate: -2}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() - 2);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date -2");
-
- date = new Date();
- inp.datepicker("option", {defaultDate: 3}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 3);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date 3");
-
- date = new Date();
- inp.datepicker("option", {defaultDate: 1 / "a"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date NaN");
-
- // String offset values
- inp.datepicker("option", {defaultDate: "-1d"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() - 1);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date -1d");
- inp.datepicker("option", {defaultDate: "+3D"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 4);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date +3D");
- inp.datepicker("option", {defaultDate: " -2 w "}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = new Date();
- date.setDate(date.getDate() - 14);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date -2 w");
- inp.datepicker("option", {defaultDate: "+1 W"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setDate(date.getDate() + 21);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date +1 W");
- inp.datepicker("option", {defaultDate: " -1 m "}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = testHelper.addMonths(new Date(), -1);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date -1 m");
- inp.datepicker("option", {defaultDate: "+2M"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = testHelper.addMonths(new Date(), 2);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date +2M");
- inp.datepicker("option", {defaultDate: "-2y"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = new Date();
- date.setFullYear(date.getFullYear() - 2);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date -2y");
- inp.datepicker("option", {defaultDate: "+1 Y "}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date.setFullYear(date.getFullYear() + 3);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date +1 Y");
- inp.datepicker("option", {defaultDate: "+1M +10d"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = testHelper.addMonths(new Date(), 1);
- date.setDate(date.getDate() + 10);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date +1M +10d");
- // String date values
- inp.datepicker("option", {defaultDate: "07/04/2007"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = new Date(2007, 7 - 1, 4);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date 07/04/2007");
- inp.datepicker("option", {dateFormat: "yy-mm-dd", defaultDate: "2007-04-02"}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = new Date(2007, 4 - 1, 2);
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date 2007-04-02");
- // Date value
- date = new Date(2007, 1 - 1, 26);
- inp.datepicker("option", {dateFormat: "mm/dd/yy", defaultDate: date}).
- datepicker("hide").val("").datepicker("show").
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date, "Default date 01/26/2007");
-});
-
-test("miscellaneous", function() {
- expect( 19 );
- var curYear, longNames, shortNames, date,
- dp = $("#ui-datepicker-div"),
- inp = testHelper.init("#inp");
- // Year range
- function genRange(start, offset) {
- var i = start,
- range = "";
- for (; i < start + offset; i++) {
- range += i;
- }
- return range;
- }
- curYear = new Date().getFullYear();
- inp.val("02/04/2008").datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), "2008", "Year range - read-only default");
- inp.datepicker("hide").datepicker("option", {changeYear: true}).datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), genRange(2008 - 10, 21), "Year range - changeable default");
- inp.datepicker("hide").datepicker("option", {yearRange: "c-6:c+2", changeYear: true}).datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), genRange(2008 - 6, 9), "Year range - c-6:c+2");
- inp.datepicker("hide").datepicker("option", {yearRange: "2000:2010", changeYear: true}).datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), genRange(2000, 11), "Year range - 2000:2010");
- inp.datepicker("hide").datepicker("option", {yearRange: "-5:+3", changeYear: true}).datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), genRange(curYear - 5, 9), "Year range - -5:+3");
- inp.datepicker("hide").datepicker("option", {yearRange: "2000:-5", changeYear: true}).datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), genRange(2000, curYear - 2004), "Year range - 2000:-5");
- inp.datepicker("hide").datepicker("option", {yearRange: "", changeYear: true}).datepicker("show");
- equal(dp.find(".ui-datepicker-year").text(), genRange(curYear, 1), "Year range - -6:+2");
-
- // Navigation as date format
- inp.datepicker("option", {showButtonPanel: true});
- equal(dp.find(".ui-datepicker-prev").text(), "Prev", "Navigation prev - default");
- equal(dp.find(".ui-datepicker-current").text(), "Today", "Navigation current - default");
- equal(dp.find(".ui-datepicker-next").text(), "Next", "Navigation next - default");
- inp.datepicker("hide").datepicker("option", {navigationAsDateFormat: true, prevText: "< M", currentText: "MM", nextText: "M >"}).
- val("02/04/2008").datepicker("show");
- longNames = $.datepicker.regional[""].monthNames;
- shortNames = $.datepicker.regional[""].monthNamesShort;
- date = new Date();
- equal(dp.find(".ui-datepicker-prev").text(), "< " + shortNames[0], "Navigation prev - as date format");
- equal(dp.find(".ui-datepicker-current").text(),
- longNames[date.getMonth()], "Navigation current - as date format");
- equal(dp.find(".ui-datepicker-next").text(),
- shortNames[2] + " >", "Navigation next - as date format");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN});
- equal(dp.find(".ui-datepicker-prev").text(),
- "< " + shortNames[1], "Navigation prev - as date format + pgdn");
- equal(dp.find(".ui-datepicker-current").text(),
- longNames[date.getMonth()], "Navigation current - as date format + pgdn");
- equal(dp.find(".ui-datepicker-next").text(),
- shortNames[3] + " >", "Navigation next - as date format + pgdn");
- inp.datepicker("hide").datepicker("option", {gotoCurrent: true}).
- val("02/04/2008").datepicker("show");
- equal(dp.find(".ui-datepicker-prev").text(),
- "< " + shortNames[0], "Navigation prev - as date format + goto current");
- equal(dp.find(".ui-datepicker-current").text(),
- longNames[1], "Navigation current - as date format + goto current");
- equal(dp.find(".ui-datepicker-next").text(),
- shortNames[2] + " >", "Navigation next - as date format + goto current");
});
-test("minMax", function() {
- expect( 23 );
- var date,
- inp = testHelper.init("#inp"),
- dp = $("#ui-datepicker-div"),
- lastYear = new Date(2007, 6 - 1, 4),
- nextYear = new Date(2009, 6 - 1, 4),
- minDate = new Date(2008, 2 - 1, 29),
- maxDate = new Date(2008, 12 - 1, 7);
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), lastYear,
- "Min/max - null, null - ctrl+pgup");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), nextYear,
- "Min/max - null, null - ctrl+pgdn");
- inp.datepicker("option", {minDate: minDate}).
- datepicker("hide").val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), minDate,
- "Min/max - 02/29/2008, null - ctrl+pgup");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), nextYear,
- "Min/max - 02/29/2008, null - ctrl+pgdn");
- inp.datepicker("option", {maxDate: maxDate}).
- datepicker("hide").val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), minDate,
- "Min/max - 02/29/2008, 12/07/2008 - ctrl+pgup");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), maxDate,
- "Min/max - 02/29/2008, 12/07/2008 - ctrl+pgdn");
- inp.datepicker("option", {minDate: null}).
- datepicker("hide").val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), lastYear,
- "Min/max - null, 12/07/2008 - ctrl+pgup");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), maxDate,
- "Min/max - null, 12/07/2008 - ctrl+pgdn");
- // Relative dates
- date = new Date();
- date.setDate(date.getDate() - 7);
- inp.datepicker("option", {minDate: "-1w", maxDate: "+1 M +10 D "}).
- datepicker("hide").val("").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date,
- "Min/max - -1w, +1 M +10 D - ctrl+pgup");
- date = testHelper.addMonths(new Date(), 1);
- date.setDate(date.getDate() + 10);
- inp.val("").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- testHelper.equalsDate(inp.datepicker("getDate"), date,
- "Min/max - -1w, +1 M +10 D - ctrl+pgdn");
- // With existing date
- inp = testHelper.init("#inp");
- inp.val("06/04/2008").datepicker("option", {minDate: minDate});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 6 - 1, 4), "Min/max - setDate > min");
- inp.datepicker("option", {minDate: null}).val("01/04/2008").datepicker("option", {minDate: minDate});
- testHelper.equalsDate(inp.datepicker("getDate"), minDate, "Min/max - setDate < min");
- inp.datepicker("option", {minDate: null}).val("06/04/2008").datepicker("option", {maxDate: maxDate});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 6 - 1, 4), "Min/max - setDate < max");
- inp.datepicker("option", {maxDate: null}).val("01/04/2009").datepicker("option", {maxDate: maxDate});
- testHelper.equalsDate(inp.datepicker("getDate"), maxDate, "Min/max - setDate > max");
- inp.datepicker("option", {maxDate: null}).val("01/04/2008").datepicker("option", {minDate: minDate, maxDate: maxDate});
- testHelper.equalsDate(inp.datepicker("getDate"), minDate, "Min/max - setDate < min");
- inp.datepicker("option", {maxDate: null}).val("06/04/2008").datepicker("option", {minDate: minDate, maxDate: maxDate});
- testHelper.equalsDate(inp.datepicker("getDate"), new Date(2008, 6 - 1, 4), "Min/max - setDate > min, < max");
- inp.datepicker("option", {maxDate: null}).val("01/04/2009").datepicker("option", {minDate: minDate, maxDate: maxDate});
- testHelper.equalsDate(inp.datepicker("getDate"), maxDate, "Min/max - setDate > max");
-
- inp.datepicker("option", {yearRange: "-0:+1"}).val("01/01/" + new Date().getFullYear());
- ok(dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - previous button disabled at 1/1/minYear");
- inp.datepicker("setDate", "12/30/" + new Date().getFullYear());
- ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled at 12/30/maxYear");
-
- inp.datepicker("option", {
- minDate: new Date(1900, 0, 1),
- maxDate: "-7Y",
- yearRange: "1900:-7"
- }).val( "" );
- ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - relative - next button disabled");
- ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - relative - prev button enabled");
-
- inp.datepicker("option", {
- minDate: new Date(1900, 0, 1),
- maxDate: "1/25/2007",
- yearRange: "1900:2007"
- }).val( "" );
- ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - absolute - next button disabled");
- ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - absolute - prev button enabled");
-});
-
-test("setDate", function() {
- expect( 24 );
- var inl, alt, minDate, maxDate, dateAndTimeToSet, dateAndTimeClone,
- inp = testHelper.init("#inp"),
- date1 = new Date(2008, 6 - 1, 4),
- date2 = new Date();
- ok(inp.datepicker("getDate") == null, "Set date - default");
- inp.datepicker("setDate", date1);
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date - 2008-06-04");
- date1 = new Date();
- date1.setDate(date1.getDate() + 7);
- inp.datepicker("setDate", +7);
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date - +7");
- date2.setFullYear(date2.getFullYear() + 2);
- inp.datepicker("setDate", "+2y");
- testHelper.equalsDate(inp.datepicker("getDate"), date2, "Set date - +2y");
- inp.datepicker("setDate", date1, date2);
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date - two dates");
- inp.datepicker("setDate");
- ok(inp.datepicker("getDate") == null, "Set date - null");
- // Relative to current date
- date1 = new Date();
- date1.setDate(date1.getDate() + 7);
- inp.datepicker("setDate", "c +7");
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date - c +7");
- date1.setDate(date1.getDate() + 7);
- inp.datepicker("setDate", "c+7");
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date - c+7");
- date1.setDate(date1.getDate() - 21);
- inp.datepicker("setDate", "c -3 w");
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date - c -3 w");
- // Inline
- inl = testHelper.init("#inl");
- date1 = new Date(2008, 6 - 1, 4);
- date2 = new Date();
- testHelper.equalsDate(inl.datepicker("getDate"), date2, "Set date inline - default");
- inl.datepicker("setDate", date1);
- testHelper.equalsDate(inl.datepicker("getDate"), date1, "Set date inline - 2008-06-04");
- date1 = new Date();
- date1.setDate(date1.getDate() + 7);
- inl.datepicker("setDate", +7);
- testHelper.equalsDate(inl.datepicker("getDate"), date1, "Set date inline - +7");
- date2.setFullYear(date2.getFullYear() + 2);
- inl.datepicker("setDate", "+2y");
- testHelper.equalsDate(inl.datepicker("getDate"), date2, "Set date inline - +2y");
- inl.datepicker("setDate", date1, date2);
- testHelper.equalsDate(inl.datepicker("getDate"), date1, "Set date inline - two dates");
- inl.datepicker("setDate");
- ok(inl.datepicker("getDate") == null, "Set date inline - null");
- // Alternate field
- alt = $("#alt");
- inp.datepicker("option", {altField: "#alt", altFormat: "yy-mm-dd"});
- date1 = new Date(2008, 6 - 1, 4);
- inp.datepicker("setDate", date1);
- equal(inp.val(), "06/04/2008", "Set date alternate - 06/04/2008");
- equal(alt.val(), "2008-06-04", "Set date alternate - 2008-06-04");
- // With minimum/maximum
- inp = testHelper.init("#inp");
- date1 = new Date(2008, 1 - 1, 4);
- date2 = new Date(2008, 6 - 1, 4);
- minDate = new Date(2008, 2 - 1, 29);
- maxDate = new Date(2008, 3 - 1, 28);
- inp.val("").datepicker("option", {minDate: minDate}).datepicker("setDate", date2);
- testHelper.equalsDate(inp.datepicker("getDate"), date2, "Set date min/max - setDate > min");
- inp.datepicker("setDate", date1);
- testHelper.equalsDate(inp.datepicker("getDate"), minDate, "Set date min/max - setDate < min");
- inp.val("").datepicker("option", {maxDate: maxDate, minDate: null}).datepicker("setDate", date1);
- testHelper.equalsDate(inp.datepicker("getDate"), date1, "Set date min/max - setDate < max");
- inp.datepicker("setDate", date2);
- testHelper.equalsDate(inp.datepicker("getDate"), maxDate, "Set date min/max - setDate > max");
- inp.val("").datepicker("option", {minDate: minDate}).datepicker("setDate", date1);
- testHelper.equalsDate(inp.datepicker("getDate"), minDate, "Set date min/max - setDate < min");
- inp.datepicker("setDate", date2);
- testHelper.equalsDate(inp.datepicker("getDate"), maxDate, "Set date min/max - setDate > max");
- dateAndTimeToSet = new Date(2008, 3 - 1, 28, 1, 11, 0);
- dateAndTimeClone = new Date(2008, 3 - 1, 28, 1, 11, 0);
- inp.datepicker("setDate", dateAndTimeToSet);
- equal(dateAndTimeToSet.getTime(), dateAndTimeClone.getTime(), "Date object passed should not be changed by setDate");
-});
-
-test("altField", function() {
- expect( 10 );
- var inp = testHelper.init("#inp"),
- alt = $("#alt");
- // No alternate field set
- alt.val("");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- equal(inp.val(), "06/04/2008", "Alt field - dp - enter");
- equal(alt.val(), "", "Alt field - alt not set");
- // Alternate field set
- alt.val("");
- inp.datepicker("option", {altField: "#alt", altFormat: "yy-mm-dd"}).
- val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- equal(inp.val(), "06/04/2008", "Alt field - dp - enter");
- equal(alt.val(), "2008-06-04", "Alt field - alt - enter");
- // Move from initial date
- alt.val("");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- equal(inp.val(), "07/04/2008", "Alt field - dp - pgdn");
- equal(alt.val(), "2008-07-04", "Alt field - alt - pgdn");
- // Alternate field set - closed
- alt.val("");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {keyCode: $.ui.keyCode.PAGE_DOWN}).
- simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE});
- equal(inp.val(), "06/04/2008", "Alt field - dp - pgdn/esc");
- equal(alt.val(), "", "Alt field - alt - pgdn/esc");
- // Clear date and alternate
- alt.val("");
- inp.val("06/04/2008").datepicker("show");
- inp.simulate("keydown", {ctrlKey: true, keyCode: $.ui.keyCode.END});
- equal(inp.val(), "", "Alt field - dp - ctrl+end");
- equal(alt.val(), "", "Alt field - alt - ctrl+end");
-});
-
-test("autoSize", function() {
- expect( 15 );
- var inp = testHelper.init("#inp");
- equal(inp.prop("size"), 20, "Auto size - default");
- inp.datepicker("option", "autoSize", true);
- equal(inp.prop("size"), 10, "Auto size - mm/dd/yy");
- inp.datepicker("option", "dateFormat", "m/d/yy");
- equal(inp.prop("size"), 10, "Auto size - m/d/yy");
- inp.datepicker("option", "dateFormat", "D M d yy");
- equal(inp.prop("size"), 15, "Auto size - D M d yy");
- inp.datepicker("option", "dateFormat", "DD, MM dd, yy");
- equal(inp.prop("size"), 29, "Auto size - DD, MM dd, yy");
-
- // French
- inp.datepicker("option", $.extend({autoSize: false}, $.datepicker.regional.fr));
- equal(inp.prop("size"), 29, "Auto size - fr - default");
- inp.datepicker("option", "autoSize", true);
- equal(inp.prop("size"), 10, "Auto size - fr - dd/mm/yy");
- inp.datepicker("option", "dateFormat", "m/d/yy");
- equal(inp.prop("size"), 10, "Auto size - fr - m/d/yy");
- inp.datepicker("option", "dateFormat", "D M d yy");
- equal(inp.prop("size"), 18, "Auto size - fr - D M d yy");
- inp.datepicker("option", "dateFormat", "DD, MM dd, yy");
- equal(inp.prop("size"), 28, "Auto size - fr - DD, MM dd, yy");
-
- // Hebrew
- inp.datepicker("option", $.extend({autoSize: false}, $.datepicker.regional.he));
- equal(inp.prop("size"), 28, "Auto size - he - default");
- inp.datepicker("option", "autoSize", true);
- equal(inp.prop("size"), 10, "Auto size - he - dd/mm/yy");
- inp.datepicker("option", "dateFormat", "m/d/yy");
- equal(inp.prop("size"), 10, "Auto size - he - m/d/yy");
- inp.datepicker("option", "dateFormat", "D M d yy");
- equal(inp.prop("size"), 16, "Auto size - he - D M d yy");
- inp.datepicker("option", "dateFormat", "DD, MM dd, yy");
- equal(inp.prop("size"), 23, "Auto size - he - DD, MM dd, yy");
-});
-
-test("daylightSaving", function() {
- expect( 25 );
- var inp = testHelper.init("#inp"),
- dp = $("#ui-datepicker-div");
- ok(true, "Daylight saving - " + new Date());
- // Australia, Sydney - AM change, southern hemisphere
- inp.val("04/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(6) a", dp).simulate("click");
- equal(inp.val(), "04/05/2008", "Daylight saving - Australia 04/05/2008");
- inp.val("04/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(7) a", dp).simulate("click");
- equal(inp.val(), "04/06/2008", "Daylight saving - Australia 04/06/2008");
- inp.val("04/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(8) a", dp).simulate("click");
- equal(inp.val(), "04/07/2008", "Daylight saving - Australia 04/07/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(6) a", dp).simulate("click");
- equal(inp.val(), "10/04/2008", "Daylight saving - Australia 10/04/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(7) a", dp).simulate("click");
- equal(inp.val(), "10/05/2008", "Daylight saving - Australia 10/05/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(8) a", dp).simulate("click");
- equal(inp.val(), "10/06/2008", "Daylight saving - Australia 10/06/2008");
- // Brasil, Brasilia - midnight change, southern hemisphere
- inp.val("02/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(20) a", dp).simulate("click");
- equal(inp.val(), "02/16/2008", "Daylight saving - Brasil 02/16/2008");
- inp.val("02/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(21) a", dp).simulate("click");
- equal(inp.val(), "02/17/2008", "Daylight saving - Brasil 02/17/2008");
- inp.val("02/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(22) a", dp).simulate("click");
- equal(inp.val(), "02/18/2008", "Daylight saving - Brasil 02/18/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(13) a", dp).simulate("click");
- equal(inp.val(), "10/11/2008", "Daylight saving - Brasil 10/11/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(14) a", dp).simulate("click");
- equal(inp.val(), "10/12/2008", "Daylight saving - Brasil 10/12/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(15) a", dp).simulate("click");
- equal(inp.val(), "10/13/2008", "Daylight saving - Brasil 10/13/2008");
- // Lebanon, Beirut - midnight change, northern hemisphere
- inp.val("03/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(34) a", dp).simulate("click");
- equal(inp.val(), "03/29/2008", "Daylight saving - Lebanon 03/29/2008");
- inp.val("03/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(35) a", dp).simulate("click");
- equal(inp.val(), "03/30/2008", "Daylight saving - Lebanon 03/30/2008");
- inp.val("03/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(36) a", dp).simulate("click");
- equal(inp.val(), "03/31/2008", "Daylight saving - Lebanon 03/31/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(27) a", dp).simulate("click");
- equal(inp.val(), "10/25/2008", "Daylight saving - Lebanon 10/25/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(28) a", dp).simulate("click");
- equal(inp.val(), "10/26/2008", "Daylight saving - Lebanon 10/26/2008");
- inp.val("10/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(29) a", dp).simulate("click");
- equal(inp.val(), "10/27/2008", "Daylight saving - Lebanon 10/27/2008");
- // US, Eastern - AM change, northern hemisphere
- inp.val("03/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(13) a", dp).simulate("click");
- equal(inp.val(), "03/08/2008", "Daylight saving - US 03/08/2008");
- inp.val("03/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(14) a", dp).simulate("click");
- equal(inp.val(), "03/09/2008", "Daylight saving - US 03/09/2008");
- inp.val("03/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(15) a", dp).simulate("click");
- equal(inp.val(), "03/10/2008", "Daylight saving - US 03/10/2008");
- inp.val("11/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(6) a", dp).simulate("click");
- equal(inp.val(), "11/01/2008", "Daylight saving - US 11/01/2008");
- inp.val("11/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(7) a", dp).simulate("click");
- equal(inp.val(), "11/02/2008", "Daylight saving - US 11/02/2008");
- inp.val("11/01/2008").datepicker("show");
- $(".ui-datepicker-calendar td:eq(8) a", dp).simulate("click");
- equal(inp.val(), "11/03/2008", "Daylight saving - US 11/03/2008");
-});
-
-var beforeShowThis = null,
- beforeShowInput = null,
- beforeShowInst = null,
- beforeShowDayThis = null,
- beforeShowDayOK = true;
-
-function beforeAll(input, inst) {
- beforeShowThis = this;
- beforeShowInput = input;
- beforeShowInst = inst;
- return {currentText: "Current"};
-}
-
-function beforeDay(date) {
- beforeShowDayThis = this;
- beforeShowDayOK &= (date > new Date(2008, 1 - 1, 26) &&
- date < new Date(2008, 3 - 1, 6));
- return [(date.getDate() % 2 === 0), (date.getDate() % 10 === 0 ? "day10" : ""),
- (date.getDate() % 3 === 0 ? "Divisble by 3" : "")];
-}
-
-test("callbacks", function() {
- expect( 13 );
- // Before show
- var dp, day20, day21,
- inp = testHelper.init("#inp", {beforeShow: beforeAll}),
- inst = $.data(inp[0], "datepicker");
- equal($.datepicker._get(inst, "currentText"), "Today", "Before show - initial");
- inp.val("02/04/2008").datepicker("show");
- equal($.datepicker._get(inst, "currentText"), "Current", "Before show - changed");
- ok(beforeShowThis.id === inp[0].id, "Before show - this OK");
- ok(beforeShowInput.id === inp[0].id, "Before show - input OK");
- deepEqual(beforeShowInst, inst, "Before show - inst OK");
- inp.datepicker("hide").datepicker("destroy");
- // Before show day
- inp = testHelper.init("#inp", {beforeShowDay: beforeDay});
- dp = $("#ui-datepicker-div");
- inp.val("02/04/2008").datepicker("show");
- ok(beforeShowDayThis.id === inp[0].id, "Before show day - this OK");
- ok(beforeShowDayOK, "Before show day - dates OK");
- day20 = dp.find(".ui-datepicker-calendar td:contains('20')");
- day21 = dp.find(".ui-datepicker-calendar td:contains('21')");
- ok(!day20.is(".ui-datepicker-unselectable"), "Before show day - unselectable 20");
- ok(day21.is(".ui-datepicker-unselectable"), "Before show day - unselectable 21");
- ok(day20.is(".day10"), "Before show day - CSS 20");
- ok(!day21.is(".day10"), "Before show day - CSS 21");
- ok(!day20.attr("title"), "Before show day - title 20");
- ok(day21.attr("title") === "Divisble by 3", "Before show day - title 21");
- inp.datepicker("hide").datepicker("destroy");
-});
-
-test("beforeShowDay - tooltips with quotes", function() {
- expect( 1 );
- var inp, dp;
- inp = testHelper.init("#inp", {
- beforeShowDay: function() {
- return [ true, "", "'" ];
- }
- });
- dp = $("#ui-datepicker-div");
-
- inp.datepicker("show");
- equal( dp.find( ".ui-datepicker-calendar td:contains('9')").attr( "title" ), "'" );
- inp.datepicker("hide").datepicker("destroy");
-});
-
-test("localisation", function() {
- expect( 24 );
- var dp, month, day, date,
- inp = testHelper.init("#inp", $.datepicker.regional.fr);
- inp.datepicker("option", {dateFormat: "DD, d MM yy", showButtonPanel:true, changeMonth:true, changeYear:true}).val("").datepicker("show");
- dp = $("#ui-datepicker-div");
- equal($(".ui-datepicker-close", dp).text(), "Fermer", "Localisation - close");
- $(".ui-datepicker-close", dp).simulate("mouseover");
- equal($(".ui-datepicker-prev", dp).text(), "Précédent", "Localisation - previous");
- equal($(".ui-datepicker-current", dp).text(), "Aujourd'hui", "Localisation - current");
- equal($(".ui-datepicker-next", dp).text(), "Suivant", "Localisation - next");
- month = 0;
- $(".ui-datepicker-month option", dp).each(function() {
- equal($(this).text(), $.datepicker.regional.fr.monthNamesShort[month],
- "Localisation - month " + month);
- month++;
- });
- day = 1;
- $(".ui-datepicker-calendar th", dp).each(function() {
- equal($(this).text(), $.datepicker.regional.fr.dayNamesMin[day],
- "Localisation - day " + day);
- day = (day + 1) % 7;
+asyncTest( "position", function(assert) {
+ expect( 3 );
+ var input = $( "<input>" ).datepicker().appendTo( "body" ).css({
+ position: "absolute",
+ top: 0,
+ left: 0
+ }),
+ container = input.datepicker( "widget" );
+
+ input.datepicker( "open" );
+ setTimeout(function() {
+ assert.close( input.offset().left, container.offset().left, 1, "left sides line up by default" );
+ assert.close( container.offset().top, input.offset().top + input.outerHeight(), 1,
+ "datepicker directly under input by default" );
+
+ // Change the position option using option()
+ input.datepicker( "option", "position", {
+ my: "left top",
+ at: "right bottom"
+ });
+ assert.close( container.offset().left, input.offset().left + input.outerWidth(), 1,
+ "datepicker on right hand side of input after position change" );
+
+ input.remove();
+ start();
});
- inp.simulate("keydown", {keyCode: $.ui.keyCode.ENTER});
- date = new Date();
- equal(inp.val(), $.datepicker.regional.fr.dayNames[date.getDay()] + ", " +
- date.getDate() + " " + $.datepicker.regional.fr.monthNames[date.getMonth()] +
- " " + date.getFullYear(), "Localisation - formatting");
-});
-
-test("noWeekends", function() {
- expect( 31 );
- var i, date;
- for (i = 1; i <= 31; i++) {
- date = new Date(2001, 1 - 1, i);
- deepEqual($.datepicker.noWeekends(date), [(i + 1) % 7 >= 2, ""],
- "No weekends " + date);
- }
-});
-
-test("iso8601Week", function() {
- expect( 12 );
- var date = new Date(2000, 12 - 1, 31);
- equal($.datepicker.iso8601Week(date), 52, "ISO 8601 week " + date);
- date = new Date(2001, 1 - 1, 1);
- equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
- date = new Date(2001, 1 - 1, 7);
- equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
- date = new Date(2001, 1 - 1, 8);
- equal($.datepicker.iso8601Week(date), 2, "ISO 8601 week " + date);
- date = new Date(2003, 12 - 1, 28);
- equal($.datepicker.iso8601Week(date), 52, "ISO 8601 week " + date);
- date = new Date(2003, 12 - 1, 29);
- equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
- date = new Date(2004, 1 - 1, 4);
- equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
- date = new Date(2004, 1 - 1, 5);
- equal($.datepicker.iso8601Week(date), 2, "ISO 8601 week " + date);
- date = new Date(2009, 12 - 1, 28);
- equal($.datepicker.iso8601Week(date), 53, "ISO 8601 week " + date);
- date = new Date(2010, 1 - 1, 3);
- equal($.datepicker.iso8601Week(date), 53, "ISO 8601 week " + date);
- date = new Date(2010, 1 - 1, 4);
- equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
- date = new Date(2010, 1 - 1, 10);
- equal($.datepicker.iso8601Week(date), 1, "ISO 8601 week " + date);
-});
-
-test("parseDate", function() {
- expect( 26 );
- testHelper.init("#inp");
- var currentYear, gmtDate, fr, settings, zh;
- ok($.datepicker.parseDate("d m y", "") == null, "Parse date empty");
- testHelper.equalsDate($.datepicker.parseDate("d m y", "3 2 01"),
- new Date(2001, 2 - 1, 3), "Parse date d m y");
- testHelper.equalsDate($.datepicker.parseDate("dd mm yy", "03 02 2001"),
- new Date(2001, 2 - 1, 3), "Parse date dd mm yy");
- testHelper.equalsDate($.datepicker.parseDate("d m y", "13 12 01"),
- new Date(2001, 12 - 1, 13), "Parse date d m y");
- testHelper.equalsDate($.datepicker.parseDate("dd mm yy", "13 12 2001"),
- new Date(2001, 12 - 1, 13), "Parse date dd mm yy");
- testHelper.equalsDate($.datepicker.parseDate("y-o", "01-34"),
- new Date(2001, 2 - 1, 3), "Parse date y-o");
- testHelper.equalsDate($.datepicker.parseDate("yy-oo", "2001-347"),
- new Date(2001, 12 - 1, 13), "Parse date yy-oo");
- testHelper.equalsDate($.datepicker.parseDate("oo yy", "348 2004"),
- new Date(2004, 12 - 1, 13), "Parse date oo yy");
- testHelper.equalsDate($.datepicker.parseDate("D d M y", "Sat 3 Feb 01"),
- new Date(2001, 2 - 1, 3), "Parse date D d M y");
- testHelper.equalsDate($.datepicker.parseDate("d MM DD yy", "3 February Saturday 2001"),
- new Date(2001, 2 - 1, 3), "Parse date dd MM DD yy");
- testHelper.equalsDate($.datepicker.parseDate("DD, MM d, yy", "Saturday, February 3, 2001"),
- new Date(2001, 2 - 1, 3), "Parse date DD, MM d, yy");
- testHelper.equalsDate($.datepicker.parseDate("'day' d 'of' MM (''DD''), yy",
- "day 3 of February ('Saturday'), 2001"), new Date(2001, 2 - 1, 3),
- "Parse date 'day' d 'of' MM (''DD''), yy");
- currentYear = new Date().getFullYear();
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000) + "-02-03"),
- new Date(currentYear, 2 - 1, 3), "Parse date y-m-d - default cutuff");
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 10) + "-02-03"),
- new Date(currentYear+10, 2 - 1, 3), "Parse date y-m-d - default cutuff");
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 11) + "-02-03"),
- new Date(currentYear-89, 2 - 1, 3), "Parse date y-m-d - default cutuff");
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", "80-02-03", {shortYearCutoff: 80}),
- new Date(2080, 2 - 1, 3), "Parse date y-m-d - cutoff 80");
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", "81-02-03", {shortYearCutoff: 80}),
- new Date(1981, 2 - 1, 3), "Parse date y-m-d - cutoff 80");
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 60) + "-02-03", {shortYearCutoff: "+60"}),
- new Date(currentYear + 60, 2 - 1, 3), "Parse date y-m-d - cutoff +60");
- testHelper.equalsDate($.datepicker.parseDate("y-m-d", (currentYear - 2000 + 61) + "-02-03", {shortYearCutoff: "+60"}),
- new Date(currentYear - 39, 2 - 1, 3), "Parse date y-m-d - cutoff +60");
- gmtDate = new Date(2001, 2 - 1, 3);
- gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset());
- testHelper.equalsDate($.datepicker.parseDate("@", "981158400000"), gmtDate, "Parse date @");
- testHelper.equalsDate($.datepicker.parseDate("!", "631167552000000000"), gmtDate, "Parse date !");
-
- fr = $.datepicker.regional.fr;
- settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames,
- monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames};
- testHelper.equalsDate($.datepicker.parseDate("D d M y", "Lun. 9 avr. 01", settings),
- new Date(2001, 4 - 1, 9), "Parse date D M y with settings");
- testHelper.equalsDate($.datepicker.parseDate("d MM DD yy", "9 Avril Lundi 2001", settings),
- new Date(2001, 4 - 1, 9), "Parse date d MM DD yy with settings");
- testHelper.equalsDate($.datepicker.parseDate("DD, MM d, yy", "Lundi, Avril 9, 2001", settings),
- new Date(2001, 4 - 1, 9), "Parse date DD, MM d, yy with settings");
- testHelper.equalsDate($.datepicker.parseDate("'jour' d 'de' MM (''DD''), yy", "jour 9 de Avril ('Lundi'), 2001", settings),
- new Date(2001, 4 - 1, 9), "Parse date 'jour' d 'de' MM (''DD''), yy with settings");
-
- zh = $.datepicker.regional["zh-CN"];
- testHelper.equalsDate($.datepicker.parseDate("yy M d", "2011 十一月 22", zh),
- new Date(2011, 11 - 1, 22), "Parse date yy M d with zh-CN");
-});
-
-test("parseDateErrors", function() {
- expect( 18 );
- testHelper.init("#inp");
- var fr, settings;
- function expectError(expr, value, error) {
- try {
- expr();
- ok(false, "Parsed error " + value);
- }
- catch (e) {
- equal(e, error, "Parsed error " + value);
- }
- }
- expectError(function() { $.datepicker.parseDate(null, "Sat 2 01"); },
- "Sat 2 01", "Invalid arguments");
- expectError(function() { $.datepicker.parseDate("d m y", null); },
- "null", "Invalid arguments");
- expectError(function() { $.datepicker.parseDate("d m y", "Sat 2 01"); },
- "Sat 2 01 - d m y", "Missing number at position 0");
- expectError(function() { $.datepicker.parseDate("dd mm yy", "Sat 2 01"); },
- "Sat 2 01 - dd mm yy", "Missing number at position 0");
- expectError(function() { $.datepicker.parseDate("d m y", "3 Feb 01"); },
- "3 Feb 01 - d m y", "Missing number at position 2");
- expectError(function() { $.datepicker.parseDate("dd mm yy", "3 Feb 01"); },
- "3 Feb 01 - dd mm yy", "Missing number at position 2");
- expectError(function() { $.datepicker.parseDate("mm dd yy", "2 1 01"); },
- "2 1 01 - dd mm yy", "Missing number at position 4");
- expectError(function() { $.datepicker.parseDate("d m y", "3 2 AD01"); },
- "3 2 AD01 - d m y", "Missing number at position 4");
- expectError(function() { $.datepicker.parseDate("d m yy", "3 2 AD01"); },
- "3 2 AD01 - dd mm yy", "Missing number at position 4");
- expectError(function() { $.datepicker.parseDate("y-o", "01-D01"); },
- "2001-D01 - y-o", "Missing number at position 3");
- expectError(function() { $.datepicker.parseDate("yy-oo", "2001-D01"); },
- "2001-D01 - yy-oo", "Missing number at position 5");
- expectError(function() { $.datepicker.parseDate("D d M y", "D7 3 Feb 01"); },
- "D7 3 Feb 01 - D d M y", "Unknown name at position 0");
- expectError(function() { $.datepicker.parseDate("D d M y", "Sat 3 M2 01"); },
- "Sat 3 M2 01 - D d M y", "Unknown name at position 6");
- expectError(function() { $.datepicker.parseDate("DD, MM d, yy", "Saturday- Feb 3, 2001"); },
- "Saturday- Feb 3, 2001 - DD, MM d, yy", "Unexpected literal at position 8");
- expectError(function() { $.datepicker.parseDate("'day' d 'of' MM (''DD''), yy",
- "day 3 of February (\"Saturday\"), 2001"); },
- "day 3 of Mon2 ('Day7'), 2001", "Unexpected literal at position 19");
- expectError(function() { $.datepicker.parseDate("d m y", "29 2 01"); },
- "29 2 01 - d m y", "Invalid date");
- fr = $.datepicker.regional.fr;
- settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames,
- monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames};
- expectError(function() { $.datepicker.parseDate("D d M y", "Mon 9 Avr 01", settings); },
- "Mon 9 Avr 01 - D d M y", "Unknown name at position 0");
- expectError(function() { $.datepicker.parseDate("D d M y", "Lun. 9 Apr 01", settings); },
- "Lun. 9 Apr 01 - D d M y", "Unknown name at position 7");
-});
-
-test("Ticket #7244: date parser does not fail when too many numbers are passed into the date function", function() {
- expect( 4 );
- var date;
- try{
- date = $.datepicker.parseDate("dd/mm/yy", "18/04/19881");
- ok(false, "Did not properly detect an invalid date");
- }catch(e){
- ok("invalid date detected");
- }
-
- try {
- date = $.datepicker.parseDate("dd/mm/yy", "18/04/1988 @ 2:43 pm");
- equal(date.getDate(), 18);
- equal(date.getMonth(), 3);
- equal(date.getFullYear(), 1988);
- } catch(e) {
- ok(false, "Did not properly parse date with extra text separated by whitespace");
- }
});
-test("formatDate", function() {
- expect( 16 );
- testHelper.init("#inp");
- var gmtDate, fr, settings;
- equal($.datepicker.formatDate("d m y", new Date(2001, 2 - 1, 3)),
- "3 2 01", "Format date d m y");
- equal($.datepicker.formatDate("dd mm yy", new Date(2001, 2 - 1, 3)),
- "03 02 2001", "Format date dd mm yy");
- equal($.datepicker.formatDate("d m y", new Date(2001, 12 - 1, 13)),
- "13 12 01", "Format date d m y");
- equal($.datepicker.formatDate("dd mm yy", new Date(2001, 12 - 1, 13)),
- "13 12 2001", "Format date dd mm yy");
- equal($.datepicker.formatDate("yy-o", new Date(2001, 2 - 1, 3)),
- "2001-34", "Format date yy-o");
- equal($.datepicker.formatDate("yy-oo", new Date(2001, 2 - 1, 3)),
- "2001-034", "Format date yy-oo");
- equal($.datepicker.formatDate("D M y", new Date(2001, 2 - 1, 3)),
- "Sat Feb 01", "Format date D M y");
- equal($.datepicker.formatDate("DD MM yy", new Date(2001, 2 - 1, 3)),
- "Saturday February 2001", "Format date DD MM yy");
- equal($.datepicker.formatDate("DD, MM d, yy", new Date(2001, 2 - 1, 3)),
- "Saturday, February 3, 2001", "Format date DD, MM d, yy");
- equal($.datepicker.formatDate("'day' d 'of' MM (''DD''), yy",
- new Date(2001, 2 - 1, 3)), "day 3 of February ('Saturday'), 2001",
- "Format date 'day' d 'of' MM ('DD'), yy");
- gmtDate = new Date(2001, 2 - 1, 3);
- gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset());
- equal($.datepicker.formatDate("@", gmtDate), "981158400000", "Format date @");
- equal($.datepicker.formatDate("!", gmtDate), "631167552000000000", "Format date !");
- fr = $.datepicker.regional.fr;
- settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames,
- monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames};
- equal($.datepicker.formatDate("D M y", new Date(2001, 4 - 1, 9), settings),
- "lun. avr. 01", "Format date D M y with settings");
- equal($.datepicker.formatDate("DD MM yy", new Date(2001, 4 - 1, 9), settings),
- "lundi avril 2001", "Format date DD MM yy with settings");
- equal($.datepicker.formatDate("DD, MM d, yy", new Date(2001, 4 - 1, 9), settings),
- "lundi, avril 9, 2001", "Format date DD, MM d, yy with settings");
- equal($.datepicker.formatDate("'jour' d 'de' MM (''DD''), yy",
- new Date(2001, 4 - 1, 9), settings), "jour 9 de avril ('lundi'), 2001",
- "Format date 'jour' d 'de' MM (''DD''), yy with settings");
-});
-
-// TODO: Fix this test so it isn't mysteriously flaky in Browserstack on certain OS/Browser combos
-// test("Ticket 6827: formatDate day of year calculation is wrong during day lights savings time", function(){
-// expect( 1 );
-// var time = $.datepicker.formatDate("oo", new Date("2010/03/30 12:00:00 CDT"));
-// equal(time, "089");
-// });
-
-test( "Ticket 7602: Stop datepicker from appearing with beforeShow event handler", function() {
+test( "Stop datepicker from appearing with beforeOpen event handler", function() {
expect( 3 );
- var inp, dp;
-
- inp = testHelper.init( "#inp", {
- beforeShow: function() {
- }
+ var input = testHelper.init( "#datepicker", {
+ beforeOpen: function() {}
});
- dp = $( "#ui-datepicker-div" );
- inp.datepicker( "show" );
- equal( dp.css( "display" ), "block", "beforeShow returns nothing" );
- inp.datepicker( "hide" ).datepicker( "destroy" );
- inp = testHelper.init( "#inp", {
- beforeShow: function() {
+ input.datepicker( "open" );
+ ok( input.datepicker( "widget" ).is( ":visible" ), "beforeOpen returns nothing" );
+ input.datepicker( "close" ).datepicker( "destroy" );
+
+ input = testHelper.init( "#datepicker", {
+ beforeOpen: function() {
return true;
}
});
- dp = $( "#ui-datepicker-div" );
- inp.datepicker( "show" );
- equal( dp.css( "display" ), "block", "beforeShow returns true" );
- inp.datepicker( "hide" );
- inp.datepicker( "destroy" );
+ input.datepicker( "open" );
+ ok( input.datepicker( "widget" ).is( ":visible" ), "beforeOpen returns true" );
+ input.datepicker( "close" ).datepicker( "destroy" );
- inp = testHelper.init( "#inp", {
- beforeShow: function() {
+ input = testHelper.init( "#datepicker", {
+ beforeOpen: function() {
return false;
}
});
- dp = $( "#ui-datepicker-div" );
- inp.datepicker( "show" );
- equal( dp.css( "display" ), "none","beforeShow returns false" );
- inp.datepicker( "destroy" );
+ input.datepicker( "open" );
+ ok( !input.datepicker( "widget" ).is( ":visible" ), "beforeOpen returns false" );
+ input.datepicker( "destroy" );
});
} );
diff --git a/tests/unit/index.html b/tests/unit/index.html
index 418cfd34c..d6c214fa5 100644
--- a/tests/unit/index.html
+++ b/tests/unit/index.html
@@ -39,6 +39,7 @@
<ul>
<li><a href="accordion/accordion.html">Accordion</a></li>
<li><a href="autocomplete/autocomplete.html">Autocomplete</a></li>
+ <li><a href="calendar/calendar.html">Calendar</a></li>
<li><a href="button/button.html">Button</a></li>
<li><a href="datepicker/datepicker.html">Datepicker</a></li>
<li><a href="dialog/dialog.html">Dialog</a></li>
diff --git a/tests/unit/spinner/options.js b/tests/unit/spinner/options.js
index fa57e6096..424932da4 100644
--- a/tests/unit/spinner/options.js
+++ b/tests/unit/spinner/options.js
@@ -1,8 +1,8 @@
define( [
"jquery",
"ui/spinner",
- "globalize",
- "globalize/ja-JP"
+ "globalize-old",
+ "globalize-old/ja-JP"
], function( $ ) {
module( "spinner: options" );
diff --git a/tests/visual/compound/datepicker_dialog.html b/tests/visual/compound/datepicker_dialog.html
index 52c91a083..374b2aeb5 100644
--- a/tests/visual/compound/datepicker_dialog.html
+++ b/tests/visual/compound/datepicker_dialog.html
@@ -6,6 +6,9 @@
<link rel="stylesheet" href="../visual.css">
<link rel="stylesheet" href="../../../themes/base/all.css">
<script src="../../../external/jquery/jquery.js"></script>
+ <script src="../../../external/globalize/globalize.js"></script>
+ <script src="../../../external/date.js"></script>
+ <script src="../../../external/localization.js"></script>
<script src="../../../ui/core.js"></script>
<script src="../../../ui/widget.js"></script>
<script src="../../../ui/mouse.js"></script>
@@ -13,6 +16,7 @@
<script src="../../../ui/resizable.js"></script>
<script src="../../../ui/draggable.js"></script>
<script src="../../../ui/button.js"></script>
+ <script src="../../../ui/calendar.js"></script>
<script src="../../../ui/datepicker.js"></script>
<script src="../../../ui/dialog.js"></script>
<script>
diff --git a/tests/visual/compound/dialog_widgets.html b/tests/visual/compound/dialog_widgets.html
index 2258231e9..0f6396d9d 100644
--- a/tests/visual/compound/dialog_widgets.html
+++ b/tests/visual/compound/dialog_widgets.html
@@ -6,6 +6,9 @@
<link rel="stylesheet" href="../visual.css">
<link rel="stylesheet" href="../../../themes/base/all.css">
<script src="../../../external/jquery/jquery.js"></script>
+ <script src="../../../external/globalize/globalize.js"></script>
+ <script src="../../../external/date.js"></script>
+ <script src="../../../external/localization.js"></script>
<script src="../../../ui/core.js"></script>
<script src="../../../ui/widget.js"></script>
<script src="../../../ui/mouse.js"></script>
@@ -16,6 +19,7 @@
<script src="../../../ui/accordion.js"></script>
<script src="../../../ui/autocomplete.js"></script>
<script src="../../../ui/button.js"></script>
+ <script src="../../../ui/calendar.js"></script>
<script src="../../../ui/datepicker.js"></script>
<script src="../../../ui/dialog.js"></script>
<script src="../../../ui/progressbar.js"></script>
diff --git a/tests/visual/dialog/complex-dialogs.html b/tests/visual/dialog/complex-dialogs.html
index 9a6209be9..59844c6a9 100644
--- a/tests/visual/dialog/complex-dialogs.html
+++ b/tests/visual/dialog/complex-dialogs.html
@@ -15,6 +15,10 @@
<script src="../../../ui/dialog.js"></script>
<!-- stuff needed to make things complex -->
+ <script src="../../../external/globalize/globalize.js"></script>
+ <script src="../../../external/date.js"></script>
+ <script src="../../../external/localization.js"></script>
+ <script src="../../../ui/calendar.js"></script>
<script src="../../../ui/datepicker.js"></script>
<script src="../../../ui/menu.js"></script>
<script src="../../../ui/autocomplete.js"></script>
diff --git a/themes/base/base.css b/themes/base/base.css
index 3ed02661f..aa8e6d157 100644
--- a/themes/base/base.css
+++ b/themes/base/base.css
@@ -13,6 +13,7 @@
@import url("accordion.css");
@import url("autocomplete.css");
@import url("button.css");
+@import url("calendar.css");
@import url("datepicker.css");
@import url("dialog.css");
@import url("draggable.css");
diff --git a/themes/base/calendar.css b/themes/base/calendar.css
new file mode 100644
index 000000000..def9fe4ff
--- /dev/null
+++ b/themes/base/calendar.css
@@ -0,0 +1,158 @@
+/*!
+ * jQuery UI Calendar @VERSION
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/calendar/#theming
+ */
+.ui-calendar {
+ width: 17em;
+ padding: .2em .2em 0;
+}
+
+/* calendar header */
+.ui-calendar .ui-calendar-header {
+ position: relative;
+ padding: .2em 0;
+}
+.ui-calendar .ui-calendar-prev,
+.ui-calendar .ui-calendar-next {
+ cursor: pointer;
+ position: absolute;
+ top: 2px;
+ width: 36px;
+ height: 31px;
+}
+.ui-calendar .ui-calendar-prev:not(.ui-state-hover):not(.ui-state-focus),
+.ui-calendar .ui-calendar-next:not(.ui-state-hover):not(.ui-state-focus) {
+ background: none;
+ border: none;
+}
+.ui-calendar .ui-calendar-prev {
+ left: 2px;
+}
+.ui-calendar .ui-calendar-next {
+ right: 2px;
+}
+.ui-calendar .ui-calendar-prev .ui-icon,
+.ui-calendar .ui-calendar-next .ui-icon {
+ display: block;
+ position: absolute;
+ left: 50%;
+ margin-left: -8px;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-calendar .ui-calendar-title {
+ line-height: 1.8em;
+ text-align: center;
+}
+
+/* calendar grid */
+.ui-calendar table {
+ width: 100%;
+ font-size: .9em;
+ border-collapse: collapse;
+ margin: 0 0 .4em;
+}
+.ui-calendar th {
+ padding: .7em .3em;
+ text-align: center;
+ font-weight: bold;
+ border: 0;
+}
+.ui-calendar td {
+ border: 0;
+ padding: 1px;
+}
+.ui-calendar td button {
+ display: block;
+ padding: .2em;
+ text-align: right;
+ cursor: pointer;
+ width: 100%;
+}
+.ui-calendar td button::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+.ui-calendar .ui-state-disabled button {
+ cursor: default;
+}
+
+/* button pane */
+.ui-calendar .ui-calendar-buttonpane {
+ background-image: none;
+ margin: .7em 0 0 0;
+ padding: 0 .2em;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 0;
+}
+.ui-calendar .ui-calendar-buttonpane button {
+ float: right;
+ margin: .5em .2em .4em;
+ cursor: pointer;
+ padding: .2em .6em .3em .6em;
+ width: auto;
+ overflow: visible;
+}
+.ui-calendar .ui-calendar-buttonpane button.ui-calendar-current {
+ float: left;
+}
+
+/* with multiple calendars */
+.ui-calendar-multi {
+ width: auto;
+ display: inline-block;
+}
+.ui-calendar-multi .ui-calendar-group {
+ width: 17em;
+ float: left;
+}
+.ui-calendar-multi .ui-calendar-group table {
+ width: 95%;
+ margin: 0 2.5% .4em;
+}
+.ui-calendar-multi .ui-calendar-buttonpane {
+ clear: left;
+}
+.ui-calendar-row-break {
+ clear: both;
+ width: 100%;
+ font-size: 0;
+}
+
+/* RTL support */
+.ui-calendar-rtl {
+ direction: rtl;
+}
+.ui-calendar-rtl .ui-calendar-prev {
+ right: 2px;
+ left: auto;
+}
+.ui-calendar-rtl .ui-calendar-next {
+ left: 2px;
+ right: auto;
+}
+.ui-calendar-rtl .ui-calendar-prev:hover {
+ right: 1px;
+ left: auto;
+}
+.ui-calendar-rtl .ui-calendar-next:hover {
+ left: 1px;
+ right: auto;
+}
+.ui-calendar-rtl .ui-calendar-buttonpane {
+ clear: right;
+}
+.ui-calendar-rtl .ui-calendar-buttonpane button {
+ float: left;
+}
+.ui-calendar-rtl .ui-calendar-buttonpane button.ui-calendar-current,
+.ui-calendar-rtl .ui-calendar-group {
+ float: right;
+}
diff --git a/themes/base/datepicker.css b/themes/base/datepicker.css
index a77eab7b2..b19f5bda8 100644
--- a/themes/base/datepicker.css
+++ b/themes/base/datepicker.css
@@ -9,167 +9,7 @@
* http://api.jqueryui.com/datepicker/#theming
*/
.ui-datepicker {
- width: 17em;
- padding: .2em .2em 0;
display: none;
-}
-.ui-datepicker .ui-datepicker-header {
- position: relative;
- padding: .2em 0;
-}
-.ui-datepicker .ui-datepicker-prev,
-.ui-datepicker .ui-datepicker-next {
- position: absolute;
- top: 2px;
- width: 1.8em;
- height: 1.8em;
-}
-.ui-datepicker .ui-datepicker-prev-hover,
-.ui-datepicker .ui-datepicker-next-hover {
- top: 1px;
-}
-.ui-datepicker .ui-datepicker-prev {
- left: 2px;
-}
-.ui-datepicker .ui-datepicker-next {
- right: 2px;
-}
-.ui-datepicker .ui-datepicker-prev-hover {
- left: 1px;
-}
-.ui-datepicker .ui-datepicker-next-hover {
- right: 1px;
-}
-.ui-datepicker .ui-datepicker-prev span,
-.ui-datepicker .ui-datepicker-next span {
- display: block;
position: absolute;
- left: 50%;
- margin-left: -8px;
- top: 50%;
- margin-top: -8px;
-}
-.ui-datepicker .ui-datepicker-title {
- margin: 0 2.3em;
- line-height: 1.8em;
- text-align: center;
-}
-.ui-datepicker .ui-datepicker-title select {
- font-size: 1em;
- margin: 1px 0;
-}
-.ui-datepicker select.ui-datepicker-month,
-.ui-datepicker select.ui-datepicker-year {
- width: 45%;
-}
-.ui-datepicker table {
- width: 100%;
- font-size: .9em;
- border-collapse: collapse;
- margin: 0 0 .4em;
-}
-.ui-datepicker th {
- padding: .7em .3em;
- text-align: center;
- font-weight: bold;
- border: 0;
-}
-.ui-datepicker td {
- border: 0;
- padding: 1px;
-}
-.ui-datepicker td span,
-.ui-datepicker td a {
- display: block;
- padding: .2em;
- text-align: right;
- text-decoration: none;
-}
-.ui-datepicker .ui-datepicker-buttonpane {
- background-image: none;
- margin: .7em 0 0 0;
- padding: 0 .2em;
- border-left: 0;
- border-right: 0;
- border-bottom: 0;
-}
-.ui-datepicker .ui-datepicker-buttonpane button {
- float: right;
- margin: .5em .2em .4em;
- cursor: pointer;
- padding: .2em .6em .3em .6em;
- width: auto;
- overflow: visible;
-}
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
- float: left;
}
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi {
- width: auto;
-}
-.ui-datepicker-multi .ui-datepicker-group {
- float: left;
-}
-.ui-datepicker-multi .ui-datepicker-group table {
- width: 95%;
- margin: 0 auto .4em;
-}
-.ui-datepicker-multi-2 .ui-datepicker-group {
- width: 50%;
-}
-.ui-datepicker-multi-3 .ui-datepicker-group {
- width: 33.3%;
-}
-.ui-datepicker-multi-4 .ui-datepicker-group {
- width: 25%;
-}
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
- border-left-width: 0;
-}
-.ui-datepicker-multi .ui-datepicker-buttonpane {
- clear: left;
-}
-.ui-datepicker-row-break {
- clear: both;
- width: 100%;
- font-size: 0;
-}
-
-/* RTL support */
-.ui-datepicker-rtl {
- direction: rtl;
-}
-.ui-datepicker-rtl .ui-datepicker-prev {
- right: 2px;
- left: auto;
-}
-.ui-datepicker-rtl .ui-datepicker-next {
- left: 2px;
- right: auto;
-}
-.ui-datepicker-rtl .ui-datepicker-prev:hover {
- right: 1px;
- left: auto;
-}
-.ui-datepicker-rtl .ui-datepicker-next:hover {
- left: 1px;
- right: auto;
-}
-.ui-datepicker-rtl .ui-datepicker-buttonpane {
- clear: right;
-}
-.ui-datepicker-rtl .ui-datepicker-buttonpane button {
- float: left;
-}
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
-.ui-datepicker-rtl .ui-datepicker-group {
- float: right;
-}
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
- border-right-width: 0;
- border-left-width: 1px;
-}
diff --git a/ui/calendar.js b/ui/calendar.js
new file mode 100644
index 000000000..a358f69a0
--- /dev/null
+++ b/ui/calendar.js
@@ -0,0 +1,614 @@
+/*!
+ * jQuery UI Calendar @VERSION
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Datepicker
+//>>group: Widgets
+//>>description: Displays a calendar for inline date selection.
+//>>docs: http://api.jqueryui.com/calendar/
+//>>demos: http://jqueryui.com/calendar/
+
+( function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ // TODO: Keep button even if its optional?
+ define( [
+ "jquery",
+ "globalize",
+ "./core",
+ "./widget",
+ "./button",
+ "date"
+ ], factory );
+ } else {
+
+ // Browser globals
+ factory( jQuery, Globalize );
+ }
+}( function( $, Globalize ) {
+
+return $.widget( "ui.calendar", {
+ version: "@VERSION",
+ options: {
+ buttons: [],
+ dateFormat: { date: "short" },
+ eachDay: $.noop,
+ max: null,
+ min: null,
+ numberOfMonths: 1,
+ showWeek: false,
+ value: null,
+
+ // callbacks
+ select: null
+ },
+
+ refreshRelatedOptions: {
+ eachDay: true,
+ max: true,
+ min: true,
+ showWeek: true,
+ value: true
+ },
+
+ _create: function() {
+ this.id = this.element.uniqueId().attr( "id" );
+ this.labels = Globalize.translate( "datepicker" );
+ this.buttonClickContext = this.element[ 0 ];
+
+ this.date = $.date( this.options.value, this.options.dateFormat );
+ this.viewDate = this.date.clone();
+ this.viewDate.eachDay = this.options.eachDay;
+
+ this._on( this.element, {
+ "click .ui-calendar-prev": function( event ) {
+ event.preventDefault();
+ this.date.adjust( "M", -this.options.numberOfMonths );
+ this._refresh();
+ },
+ "click .ui-calendar-next": function( event ) {
+ event.preventDefault();
+ this.date.adjust( "M", this.options.numberOfMonths );
+ this._refresh();
+ },
+ "mousedown .ui-calendar-calendar button": function( event ) {
+ event.preventDefault();
+
+ this._setOption( "value", new Date( $( event.currentTarget ).data( "timestamp" ) ) );
+ this.refresh();
+ this._trigger( "select", event );
+ this.grid.focus();
+ },
+ "mouseenter .ui-calendar-header button": "_hover",
+ "mouseleave .ui-calendar-header button": "_hover",
+ "mouseenter .ui-calendar-calendar button": "_hover",
+ "mouseleave .ui-calendar-calendar button": "_hover",
+ "keydown .ui-calendar-calendar": "_handleKeydown"
+ } );
+
+ this._createCalendar();
+ },
+
+ _hover: function( event ) {
+ $( event.currentTarget ).toggleClass( "ui-state-hover" );
+ },
+
+ _handleKeydown: function( event ) {
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.ENTER:
+ this.activeDescendant.mousedown();
+ return;
+ case $.ui.keyCode.PAGE_UP:
+ this.date.adjust( event.altKey ? "Y" : "M", -1 );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ this.date.adjust( event.altKey ? "Y" : "M", 1 );
+ break;
+ case $.ui.keyCode.END:
+ this.date.setDay( this.date.daysInMonth() );
+ break;
+ case $.ui.keyCode.HOME:
+ this.date.setDay( 1 );
+ break;
+ case $.ui.keyCode.LEFT:
+ this.date.adjust( "D", -1 );
+ break;
+ case $.ui.keyCode.UP:
+ this.date.adjust( "D", -7 );
+ break;
+ case $.ui.keyCode.RIGHT:
+ this.date.adjust( "D", 1 );
+ break;
+ case $.ui.keyCode.DOWN:
+ this.date.adjust( "D", 7 );
+ break;
+ default:
+ event.preventDefault();
+ return;
+ }
+
+ if ( this._needsRefresh() ) {
+ this._refresh();
+ this.grid.focus();
+ }
+
+ this._setActiveDescendant();
+ },
+
+ _needsRefresh: function() {
+ if ( this.date.month() !== this.viewDate.month() || this.date.year() !== this.viewDate.year() ) {
+
+ // Check if the needed day is already present in our grid due
+ // to eachDay option changes (eg. other-months demo)
+ return !this.grid.find(
+ this._sanitizeSelector( "#" + this._getDayId( this.date ) )
+ ).length;
+ }
+
+ return false;
+ },
+
+ _setActiveDescendant: function() {
+ var id = this._getDayId( this.date );
+
+ this.grid
+ .attr( "aria-activedescendant", id )
+ .find( ".ui-state-focus" )
+ .removeClass( "ui-state-focus" );
+
+ this.activeDescendant = this.grid.find(
+ this._sanitizeSelector( "#" + id ) + " > button"
+ ).addClass( "ui-state-focus" );
+ },
+
+ _createCalendar: function() {
+ var classes = "ui-calendar ui-widget ui-widget-content ui-helper-clearfix ui-corner-all",
+ pickerHtml = "";
+
+ if ( this.options.numberOfMonths === 1 ) {
+ pickerHtml = this._buildHeader() + this._buildGrid();
+ } else {
+ pickerHtml = this._buildMultiplePicker();
+ classes += " ui-calendar-multi";
+ }
+
+ this.element
+ .addClass( classes )
+ .attr( {
+ role: "region",
+ "aria-labelledby": this.id + "-title"
+ } )
+ .html( pickerHtml );
+
+ this._createButtonPane();
+
+ this.grid = this.element.find( ".ui-calendar-calendar" );
+ },
+
+ _buildMultiplePicker: function() {
+ var headerClass,
+ html = "",
+ currentDate = this.viewDate,
+ months = this.viewDate.months( this.options.numberOfMonths - 1 ),
+ i = 0;
+
+ for ( ; i < months.length; i++ ) {
+
+ // TODO: Shouldn't we pass date as a parameter to build* fns instead of setting this.date?
+ this.viewDate = months[ i ];
+ headerClass = "ui-calendar-header ui-widget-header ui-helper-clearfix";
+ if ( months[ i ].first ) {
+ headerClass += " ui-corner-left";
+ } else if ( months[ i ].last ) {
+ headerClass += " ui-corner-right";
+ }
+
+ html += "<div class='ui-calendar-group'>" +
+ "<div class='" + headerClass + "'>";
+ if ( months[ i ].first ) {
+ html += this._buildPreviousLink();
+ } else if ( months[ i ].last ) {
+ html += this._buildNextLink();
+ }
+
+ html += this._buildTitlebar() + "</div>" + this._buildGrid() + "</div>";
+ }
+
+ html += "<div class='ui-calendar-row-break'></div>";
+
+ this.viewDate = currentDate;
+
+ return html;
+ },
+
+ _buildHeader: function() {
+ return "<div class='ui-calendar-header ui-widget-header ui-helper-clearfix ui-corner-all'>" +
+ this._buildPreviousLink() +
+ this._buildNextLink() +
+ this._buildTitlebar() +
+ "</div>";
+ },
+
+ _buildPreviousLink: function() {
+ var prevText = this._getTranslation( "prevText" );
+
+ return "<button class='ui-calendar-prev ui-corner-all' title='" +
+ prevText + "'>" +
+ "<span class='ui-icon ui-icon-circle-triangle-w'>" +
+ prevText +
+ "</span>" +
+ "</button>";
+ },
+
+ _buildNextLink: function() {
+ var nextText = this._getTranslation( "nextText" );
+
+ return "<button class='ui-calendar-next ui-corner-all' title='" +
+ nextText + "'>" +
+ "<span class='ui-icon ui-icon-circle-triangle-e'>" +
+ nextText +
+ "</span>" +
+ "</button>";
+ },
+
+ _buildTitlebar: function() {
+ return "<div role='header' id='" + this.id + "-title'>" +
+ "<div id='" + this.id + "-month-label' class='ui-calendar-title'>" +
+ this._buildTitle() +
+ "</div>" +
+ "<span class='ui-helper-hidden-accessible'>, " +
+ this._getTranslation( "datePickerRole" ) +
+ "</span>" +
+ "</div>";
+ },
+
+ _buildTitle: function() {
+ return "<span class='ui-calendar-month'>" +
+ this.viewDate.monthName() +
+ "</span> " +
+ "<span class='ui-calendar-year'>" +
+ this.viewDate.year() +
+ "</span>";
+ },
+
+ _buildGrid: function() {
+ return "<table class='ui-calendar-calendar' role='grid' aria-readonly='true' " +
+ "aria-labelledby='" + this.id + "-month-label' tabindex='0' " +
+ "aria-activedescendant='" + this._getDayId( this.date ) + "'>" +
+ this._buildGridHeading() +
+ this._buildGridBody() +
+ "</table>";
+ },
+
+ _buildGridHeading: function() {
+ var cells = "",
+ i = 0,
+ weekDayLength = this.viewDate.weekdays().length;
+
+ if ( this.options.showWeek ) {
+ cells += "<th class='ui-calendar-week-col'>" + this._getTranslation( "weekHeader" ) + "</th>";
+ }
+ for ( ; i < weekDayLength; i++ ) {
+ cells += this._buildGridHeaderCell( this.date.weekdays()[ i ] );
+ }
+
+ return "<thead role='presentation'>" +
+ "<tr role='row'>" + cells + "</tr>" +
+ "</thead>";
+ },
+
+ _buildGridHeaderCell: function( day ) {
+ return "<th role='columnheader' abbr='" + day.fullname + "' aria-label='" + day.fullname + "'>" +
+ "<span title='" + day.fullname + "'>" +
+ day.shortname +
+ "</span>" +
+ "</th>";
+ },
+
+ _buildGridBody: function() {
+
+ // this.date.days() needs caching as it has O(n^2) complexity.
+ var days = this.viewDate.days(),
+ i = 0,
+ rows = "";
+
+ for ( ; i < days.length; i++ ) {
+ rows += this._buildWeekRow( days[ i ] );
+ }
+
+ return "<tbody role='presentation'>" + rows + "</tbody>";
+ },
+
+ _buildWeekRow: function( week ) {
+ var cells = "",
+ i = 0;
+
+ if ( this.options.showWeek ) {
+ cells += "<td class='ui-calendar-week-col'>" + week.number + "</td>";
+ }
+ for ( ; i < week.days.length; i++ ) {
+ cells += this._buildDayCell( week.days[ i ] );
+ }
+
+ return "<tr role='row'>" + cells + "</tr>";
+ },
+
+ _buildDayCell: function( day ) {
+ var content = "",
+ attributes = [
+ "role='gridcell'",
+ "aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'"
+ ],
+ selectable = ( day.selectable && this._isValid( new Date( day.timestamp ) ) );
+
+ if ( day.render ) {
+ attributes.push( "id='" + this.id + "-" + day.year + "-" + day.month + "-" + day.date + "'" );
+
+ if ( !selectable ) {
+ attributes.push( "aria-disabled='true'" );
+ attributes.push( "class='ui-state-disabled'" );
+ }
+
+ content = this._buildDayElement( day, selectable );
+ }
+
+ return "<td " + attributes.join( " " ) + ">" + content + "</td>";
+ },
+
+ _getDayId: function( date ) {
+ return this.id + "-" + date.year() + "-" + date.month() + "-" + date.day();
+ },
+
+ _buildDayElement: function( day, selectable ) {
+ var attributes, content,
+ classes = [ "ui-state-default" ];
+
+ if ( day === this.date && selectable ) {
+ classes.push( "ui-state-focus" );
+ }
+ if ( this._isCurrent( day ) ) {
+ classes.push( "ui-state-active" );
+ }
+ if ( day.today ) {
+ classes.push( "ui-state-highlight" );
+ }
+ if ( day.extraClasses ) {
+ classes.push( day.extraClasses.split( " " ) );
+ }
+
+ attributes = " class='" + classes.join( " " ) + "'";
+ if ( selectable ) {
+ attributes += " tabindex='-1' data-timestamp='" + day.timestamp + "'";
+ } else {
+ attributes += " disabled='disabled'";
+ }
+ content = "<button" + attributes + ">" + day.date + "</button>";
+
+ if ( day.today ) {
+ content += "<span class='ui-helper-hidden-accessible'>, " + this._getTranslation( "currentText" ) + "</span>";
+ }
+
+ return content;
+ },
+
+ _isCurrent: function( day ) {
+ return this.options.value && day.timestamp === this.options.value.getTime();
+ },
+
+ _createButtonPane: function() {
+ this.buttonPane = $( "<div>" )
+ .addClass( "ui-calendar-buttonpane ui-widget-content ui-helper-clearfix" );
+
+ this.buttonSet = $( "<div>" )
+ .addClass( "ui-calendar-buttonset" )
+ .appendTo( this.buttonPane );
+
+ this._createButtons();
+ },
+
+ _createButtons: function() {
+ var that = this,
+ buttons = this.options.buttons;
+
+ this.buttonPane.remove();
+ this.buttonSet.empty();
+
+ if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
+ this.element.removeClass( "ui-calendar-buttons" );
+ return;
+ }
+
+ $.each( buttons, function( name, props ) {
+ var click, buttonOptions;
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+
+ // Default to a non-submitting button
+ props = $.extend( { type: "button" }, props );
+
+ // Change the context for the click callback to be the main element
+ click = props.click;
+ props.click = function() {
+ click.apply( that.buttonClickContext, arguments );
+ };
+ buttonOptions = {
+ icons: props.icons,
+ text: props.showText
+ };
+ delete props.icons;
+ delete props.showText;
+ $( "<button></button>", props )
+ .button( buttonOptions )
+ .appendTo( that.buttonSet );
+ } );
+ this.element.addClass( "ui-calendar-buttons" );
+ this.buttonPane.appendTo( this.element );
+ },
+
+ _refresh: function() {
+ this.viewDate.setTime( this.date.date().getTime() );
+ this.refresh();
+ },
+
+ // Refreshing the entire calendar during interaction confuses screen readers, specifically
+ // because the grid heading is marked up as a live region and will often not update if it's
+ // destroyed and recreated instead of just having its text change. Additionally, interacting
+ // with the prev and next links would cause loss of focus issues because the links being
+ // interacted with will disappear while focused.
+ refresh: function() {
+ this.labels = Globalize.translate( "datepicker" );
+
+ // Determine which day gridcell to focus after refresh
+ // TODO: Prevent disabled cells from being focused
+ if ( this.options.numberOfMonths === 1 ) {
+ this.grid = $( this._buildGrid() );
+ this.element.find( ".ui-calendar-title" ).html( this._buildTitle() );
+ this.element.find( ".ui-calendar-calendar" ).replaceWith( this.grid );
+ $( ".ui-calendar-prev", this.element ).attr( "title", this.labels.prevText )
+ .children().html( this.labels.prevText );
+ $( ".ui-calendar-next", this.element ).attr( "title", this.labels.nextText )
+ .children().html( this.labels.nextText );
+ this._createButtons();
+ } else {
+ this._refreshMultiplePicker();
+ }
+ },
+
+ _refreshMultiplePicker: function() {
+ var i = 0;
+
+ for ( ; i < this.options.numberOfMonths; i++ ) {
+ this.element.find( ".ui-calendar-title" ).eq( i ).html( this._buildTitle() );
+ this.element.find( ".ui-calendar-calendar" ).eq( i ).html( this._buildGrid() );
+ this.viewDate.adjust( "M", 1 );
+ }
+ this.viewDate.adjust( "M", -this.options.numberOfMonths );
+
+ // TODO: This assumes focus is on the first grid. For multi pickers, the widget needs
+ // to maintain the currently focused grid and base queries like this off of it.
+ this.element.find( ".ui-state-focus" ).not( ":first" ).removeClass( "ui-state-focus" );
+ },
+
+ _getTranslation: function( key ) {
+ return $( "<a>" ).text( this.labels[ key ] ).html();
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ _setHiddenPicker: function() {
+ this.element.attr( {
+ "aria-hidden": "true",
+ "aria-expanded": "false"
+ } );
+ },
+
+ value: function( value ) {
+ if ( arguments.length ) {
+ this.valueAsDate( Globalize.parseDate( value, this.options.dateFormat ) );
+ } else {
+ return Globalize.format( this.option( "value" ), this.options.dateFormat );
+ }
+ },
+
+ valueAsDate: function( value ) {
+ if ( arguments.length ) {
+ this.option( "value", value );
+ } else {
+ return this.options.value;
+ }
+ },
+
+ _isValid: function( value ) {
+ if ( $.type( value ) !== "date" ) {
+ return false;
+ }
+
+ if ( $.type( this.options.max ) === "date" ) {
+ if ( value > this.options.max ) {
+ return false;
+ }
+ }
+
+ if ( $.type( this.options.min ) === "date" ) {
+ if ( value < this.options.min ) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ _destroy: function() {
+ this.element
+ .off( ".calendar" )
+ .removeClass( "ui-calendar ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-calendar-multi" )
+ .removeAttr( "role aria-labelledby" )
+ .removeUniqueId()
+ .empty();
+ },
+
+ _setOptions: function( options ) {
+ var that = this,
+ refresh = false;
+
+ $.each( options, function( key, value ) {
+ that._setOption( key, value );
+
+ if ( key in that.refreshRelatedOptions ) {
+ refresh = true;
+ }
+ } );
+
+ if ( refresh ) {
+ this._refresh();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "value" ) {
+ if ( this._isValid( value ) ) {
+ this.date.setTime( value.getTime() );
+ this._super( key, value );
+ }
+ return;
+ }
+
+ if ( key === "max" || key === "min" ) {
+ if ( $.type( value ) === "date" || value === null ) {
+ this._super( key, value );
+ }
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "buttons" ) {
+ this._createButtons();
+ }
+
+ if ( key === "disabled" ) {
+ this.element
+ .toggleClass( "ui-state-disabled", value )
+ .attr( "aria-disabled", value );
+ }
+
+ if ( key === "eachDay" ) {
+ this.viewDate.eachDay = value;
+ }
+
+ if ( key === "dateFormat" ) {
+ this.date.setFormat( value );
+ }
+ }
+} );
+
+} ) );
diff --git a/ui/datepicker.js b/ui/datepicker.js
index cf63cbb20..dc8154e32 100644
--- a/ui/datepicker.js
+++ b/ui/datepicker.js
@@ -9,12 +9,9 @@
//>>label: Datepicker
//>>group: Widgets
-//>>description: Displays a calendar from an input or inline for selecting dates.
+//>>description: Displays a calendar for input-based date selection.
//>>docs: http://api.jqueryui.com/datepicker/
//>>demos: http://jqueryui.com/datepicker/
-//>>css.structure: ../themes/base/core.css
-//>>css.structure: ../themes/base/datepicker.css
-//>>css.theme: ../themes/base/theme.css
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
@@ -22,2071 +19,333 @@
// AMD. Register as an anonymous module.
define([
"jquery",
- "./core"
+ "globalize",
+ "./core",
+ "./widget",
+ "./calendar",
+ "./position"
], factory );
} else {
// Browser globals
- factory( jQuery );
+ factory( jQuery, Globalize );
}
-}(function( $ ) {
+}(function( $, Globalize ) {
-$.extend($.ui, { datepicker: { version: "@VERSION" } });
+var widget = $.widget( "ui.datepicker", {
+ version: "@VERSION",
+ options: {
+ appendTo: null,
+ position: {
+ my: "left top",
+ at: "left bottom"
+ },
+ show: true,
+ hide: true,
-var datepicker_instActive;
-
-function datepicker_getZindex( elem ) {
- var position, value;
- while ( elem.length && elem[ 0 ] !== document ) {
- // Ignore z-index if position is set to a value where z-index is ignored by the browser
- // This makes behavior of this function consistent across browsers
- // WebKit always returns auto if the element is positioned
- position = elem.css( "position" );
- if ( position === "absolute" || position === "relative" || position === "fixed" ) {
- // IE returns 0 when zIndex is not specified
- // other browsers return a string
- // we ignore the case of nested elements with an explicit value of 0
- // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
- value = parseInt( elem.css( "zIndex" ), 10 );
- if ( !isNaN( value ) && value !== 0 ) {
- return value;
- }
- }
- elem = elem.parent();
- }
-
- return 0;
-}
-/* Date picker manager.
- Use the singleton instance of this class, $.datepicker, to interact with the date picker.
- Settings for (groups of) date pickers are maintained in an instance object,
- allowing multiple different settings on the same page. */
-
-function Datepicker() {
- this._curInst = null; // The current instance in use
- this._keyEvent = false; // If the last event was a key event
- this._disabledInputs = []; // List of date picker inputs that have been disabled
- this._datepickerShowing = false; // True if the popup picker is showing , false if not
- this._inDialog = false; // True if showing within a "dialog", false if not
- this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
- this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
- this._appendClass = "ui-datepicker-append"; // The name of the append marker class
- this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
- this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
- this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
- this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
- this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
- this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
- this.regional = []; // Available regional settings, indexed by language code
- this.regional[""] = { // Default regional settings
- closeText: "Done", // Display text for close link
- prevText: "Prev", // Display text for previous month link
- nextText: "Next", // Display text for next month link
- currentText: "Today", // Display text for current month link
- monthNames: ["January","February","March","April","May","June",
- "July","August","September","October","November","December"], // Names of months for drop-down and formatting
- monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
- dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
- dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
- dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
- weekHeader: "Wk", // Column header for week of the year
- dateFormat: "mm/dd/yy", // See format options on parseDate
- firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
- isRTL: false, // True if right-to-left language, false if left-to-right
- showMonthAfterYear: false, // True if the year select precedes month, false for month then year
- yearSuffix: "" // Additional text to append to the year in the month headers
- };
- this._defaults = { // Global defaults for all the date picker instances
- showOn: "focus", // "focus" for popup on focus,
- // "button" for trigger button, or "both" for either
- showAnim: "fadeIn", // Name of jQuery animation for popup
- showOptions: {}, // Options for enhanced animations
- defaultDate: null, // Used when field is blank: actual date,
- // +/-number for offset from today, null for today
- appendText: "", // Display text following the input box, e.g. showing the format
- buttonText: "...", // Text for trigger button
- buttonImage: "", // URL for trigger button image
- buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
- hideIfNoPrevNext: false, // True to hide next/previous month links
- // if not applicable, false to just disable them
- navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
- gotoCurrent: false, // True if today link goes back to current selection instead
- changeMonth: false, // True if month can be selected directly, false if only prev/next
- changeYear: false, // True if year can be selected directly, false if only prev/next
- yearRange: "c-10:c+10", // Range of years to display in drop-down,
- // either relative to today's year (-nn:+nn), relative to currently displayed year
- // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
- showOtherMonths: false, // True to show dates in other months, false to leave blank
- selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
- showWeek: false, // True to show week of the year, false to not show it
- calculateWeek: this.iso8601Week, // How to calculate the week of the year,
- // takes a Date and returns the number of the week for it
- shortYearCutoff: "+10", // Short year values < this are in the current century,
- // > this are in the previous century,
- // string value starting with "+" for current year + value
- minDate: null, // The earliest selectable date, or null for no limit
- maxDate: null, // The latest selectable date, or null for no limit
- duration: "fast", // Duration of display/closure
- beforeShowDay: null, // Function that takes a date and returns an array with
- // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
- // [2] = cell title (optional), e.g. $.datepicker.noWeekends
- beforeShow: null, // Function that takes an input field and
- // returns a set of custom settings for the date picker
- onSelect: null, // Define a callback function when a date is selected
- onChangeMonthYear: null, // Define a callback function when the month or year is changed
- onClose: null, // Define a callback function when the datepicker is closed
- numberOfMonths: 1, // Number of months to show at a time
- showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
- stepMonths: 1, // Number of months to step back/forward
- stepBigMonths: 12, // Number of months to step back/forward for the big links
- altField: "", // Selector for an alternate field to store selected dates into
- altFormat: "", // The date format to use for the alternate field
- constrainInput: true, // The input is constrained by the current date format
- showButtonPanel: false, // True to show button panel, false to not show it
- autoSize: false, // True to size the input for the date format, false to leave as is
- disabled: false // The initial disabled state
- };
- $.extend(this._defaults, this.regional[""]);
- this.regional.en = $.extend( true, {}, this.regional[ "" ]);
- this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
- this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
-}
-
-$.extend(Datepicker.prototype, {
- /* Class name added to elements to indicate already configured with a date picker. */
- markerClassName: "hasDatepicker",
-
- //Keep track of the maximum number of rows displayed (see #7043)
- maxRows: 4,
-
- // TODO rename to "widget" when switching to widget factory
- _widgetDatepicker: function() {
- return this.dpDiv;
- },
-
- /* Override the default settings for all instances of the date picker.
- * @param settings object - the new settings to use as defaults (anonymous object)
- * @return the manager object
- */
- setDefaults: function(settings) {
- datepicker_extendRemove(this._defaults, settings || {});
- return this;
+ // callbacks
+ beforeOpen: null,
+ close: null,
+ open: null,
+ select: null
},
- /* Attach the date picker to a jQuery selection.
- * @param target element - the target input field or division or span
- * @param settings object - the new settings to use for this date picker instance (anonymous)
- */
- _attachDatepicker: function(target, settings) {
- var nodeName, inline, inst;
- nodeName = target.nodeName.toLowerCase();
- inline = (nodeName === "div" || nodeName === "span");
- if (!target.id) {
- this.uuid += 1;
- target.id = "dp" + this.uuid;
- }
- inst = this._newInst($(target), inline);
- inst.settings = $.extend({}, settings || {});
- if (nodeName === "input") {
- this._connectDatepicker(target, inst);
- } else if (inline) {
- this._inlineDatepicker(target, inst);
- }
- },
+ calendarOptions: [ "buttons", "dateFormat", "disabled", "eachDay", "max",
+ "min", "numberOfMonths", "showWeek" ],
- /* Create a new instance object. */
- _newInst: function(target, inline) {
- var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
- return {id: id, input: target, // associated target
- selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
- drawMonth: 0, drawYear: 0, // month being drawn
- inline: inline, // is datepicker inline or not
- dpDiv: (!inline ? this.dpDiv : // presentation div
- datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
- },
+ _create: function() {
+ this.suppressExpandOnFocus = false;
+ this._createCalendar();
- /* Attach the date picker to an input field. */
- _connectDatepicker: function(target, inst) {
- var input = $(target);
- inst.append = $([]);
- inst.trigger = $([]);
- if (input.hasClass(this.markerClassName)) {
- return;
- }
- this._attachments(input, inst);
- input.addClass(this.markerClassName).on( "keydown", this._doKeyDown).
- on( "keypress", this._doKeyPress).on( "keyup", this._doKeyUp);
- this._autoSize(inst);
- $.data(target, "datepicker", inst);
- //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
- if( inst.settings.disabled ) {
- this._disableDatepicker( target );
- }
+ this._on( this._inputEvents );
+ this._on( this.calendar, this._calendarEvents );
+ this._on( this.document, this._documentEvents );
},
- /* Make attachments based on settings. */
- _attachments: function(input, inst) {
- var showOn, buttonText, buttonImage,
- appendText = this._get(inst, "appendText"),
- isRTL = this._get(inst, "isRTL");
+ _getCreateOptions: function() {
+ var max = this.element.attr( "max" ),
+ min = this.element.attr( "min" ),
+ options = {};
- if (inst.append) {
- inst.append.remove();
- }
- if (appendText) {
- inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
- input[isRTL ? "before" : "after"](inst.append);
+ if ( max !== undefined ) {
+ options.max = Globalize.parseDate( max, { pattern: "yyyy-MM-dd" } );
}
- input.off("focus", this._showDatepicker);
-
- if (inst.trigger) {
- inst.trigger.remove();
+ if ( min !== undefined ) {
+ options.min = Globalize.parseDate( min, { pattern: "yyyy-MM-dd" } );
}
- showOn = this._get(inst, "showOn");
- if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
- input.on( "focus", this._showDatepicker );
- }
- if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
- buttonText = this._get(inst, "buttonText");
- buttonImage = this._get(inst, "buttonImage");
- inst.trigger = $(this._get(inst, "buttonImageOnly") ?
- $("<img/>").addClass(this._triggerClass).
- attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
- $("<button type='button'></button>").addClass(this._triggerClass).
- html(!buttonImage ? buttonText : $("<img/>").attr(
- { src:buttonImage, alt:buttonText, title:buttonText })));
- input[isRTL ? "before" : "after"](inst.trigger);
- inst.trigger.on( "click", function() {
- if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
- $.datepicker._hideDatepicker();
- } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
- $.datepicker._hideDatepicker();
- $.datepicker._showDatepicker(input[0]);
- } else {
- $.datepicker._showDatepicker(input[0]);
- }
- return false;
- });
- }
- },
-
- /* Apply the maximum length for the date format. */
- _autoSize: function(inst) {
- if (this._get(inst, "autoSize") && !inst.inline) {
- var findMax, max, maxI, i,
- date = new Date(2009, 12 - 1, 20), // Ensure double digits
- dateFormat = this._get(inst, "dateFormat");
-
- if (dateFormat.match(/[DM]/)) {
- findMax = function(names) {
- max = 0;
- maxI = 0;
- for (i = 0; i < names.length; i++) {
- if (names[i].length > max) {
- max = names[i].length;
- maxI = i;
- }
- }
- return maxI;
- };
- date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
- "monthNames" : "monthNamesShort"))));
- date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
- "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
- }
- inst.input.attr("size", this._formatDate(inst, date).length);
- }
- },
-
- /* Attach an inline date picker to a div. */
- _inlineDatepicker: function(target, inst) {
- var divSpan = $(target);
- if (divSpan.hasClass(this.markerClassName)) {
- return;
- }
- divSpan.addClass(this.markerClassName).append(inst.dpDiv);
- $.data(target, "datepicker", inst);
- this._setDate(inst, this._getDefaultDate(inst), true);
- this._updateDatepicker(inst);
- this._updateAlternate(inst);
- //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
- if( inst.settings.disabled ) {
- this._disableDatepicker( target );
- }
- // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
- // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
- inst.dpDiv.css( "display", "block" );
+ return options;
},
- /* Pop-up the date picker in a "dialog" box.
- * @param input element - ignored
- * @param date string or Date - the initial date to display
- * @param onSelect function - the function to call when a date is selected
- * @param settings object - update the dialog date picker instance's settings (anonymous object)
- * @param pos int[2] - coordinates for the dialog's position within the screen or
- * event - with x/y coordinates or
- * leave empty for default (screen centre)
- * @return the manager object
- */
- _dialogDatepicker: function(input, date, onSelect, settings, pos) {
- var id, browserWidth, browserHeight, scrollX, scrollY,
- inst = this._dialogInst; // internal instance
+ _createCalendar: function() {
+ var that = this;
- if (!inst) {
- this.uuid += 1;
- id = "dp" + this.uuid;
- this._dialogInput = $("<input type='text' id='" + id +
- "' style='position: absolute; top: -100px; width: 0px;'/>");
- this._dialogInput.on( "keydown", this._doKeyDown );
- $("body").append(this._dialogInput);
- inst = this._dialogInst = this._newInst(this._dialogInput, false);
- inst.settings = {};
- $.data(this._dialogInput[0], "datepicker", inst);
- }
- datepicker_extendRemove(inst.settings, settings || {});
- date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
- this._dialogInput.val(date);
-
- this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
- if (!this._pos) {
- browserWidth = document.documentElement.clientWidth;
- browserHeight = document.documentElement.clientHeight;
- scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
- scrollY = document.documentElement.scrollTop || document.body.scrollTop;
- this._pos = // should use actual width/height below
- [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
- }
-
- // move input on screen for focus, but hidden behind dialog
- this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
- inst.settings.onSelect = onSelect;
- this._inDialog = true;
- this.dpDiv.addClass(this._dialogClass);
- this._showDatepicker(this._dialogInput[0]);
- if ($.blockUI) {
- $.blockUI(this.dpDiv);
- }
- $.data(this._dialogInput[0], "datepicker", inst);
- return this;
- },
-
- /* Detach a datepicker from its control.
- * @param target element - the target input field or division or span
- */
- _destroyDatepicker: function(target) {
- var nodeName,
- $target = $(target),
- inst = $.data(target, "datepicker");
-
- if (!$target.hasClass(this.markerClassName)) {
- return;
- }
+ this.calendar = $( "<div>" )
+ .addClass( "ui-front ui-datepicker" )
+ .appendTo( this._appendTo() );
- nodeName = target.nodeName.toLowerCase();
- $.removeData(target, "datepicker");
- if (nodeName === "input") {
- inst.append.remove();
- inst.trigger.remove();
- $target.removeClass(this.markerClassName).
- off("focus", this._showDatepicker).
- off("keydown", this._doKeyDown).
- off("keypress", this._doKeyPress).
- off("keyup", this._doKeyUp);
- } else if (nodeName === "div" || nodeName === "span") {
- $target.removeClass(this.markerClassName).empty();
- }
-
- if ( datepicker_instActive === inst ) {
- datepicker_instActive = null;
- }
- },
-
- /* Enable the date picker to a jQuery selection.
- * @param target element - the target input field or division or span
- */
- _enableDatepicker: function(target) {
- var nodeName, inline,
- $target = $(target),
- inst = $.data(target, "datepicker");
-
- if (!$target.hasClass(this.markerClassName)) {
- return;
- }
-
- nodeName = target.nodeName.toLowerCase();
- if (nodeName === "input") {
- target.disabled = false;
- inst.trigger.filter("button").
- each(function() { this.disabled = false; }).end().
- filter("img").css({opacity: "1.0", cursor: ""});
- } else if (nodeName === "div" || nodeName === "span") {
- inline = $target.children("." + this._inlineClass);
- inline.children().removeClass("ui-state-disabled");
- inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
- prop("disabled", false);
- }
- this._disabledInputs = $.map(this._disabledInputs,
- function(value) { return (value === target ? null : value); }); // delete entry
- },
-
- /* Disable the date picker to a jQuery selection.
- * @param target element - the target input field or division or span
- */
- _disableDatepicker: function(target) {
- var nodeName, inline,
- $target = $(target),
- inst = $.data(target, "datepicker");
-
- if (!$target.hasClass(this.markerClassName)) {
- return;
- }
+ // Initialize calendar widget
+ this.calendarInstance = this.calendar
+ .calendar( $.extend( {}, this.options, {
+ value: this._getParsedValue(),
+ select: function( event ) {
+ that.element.val( that.calendarInstance.value() );
+ that.close();
+ that._focusTrigger();
+ that._trigger( "select", event );
+ }
+ }) )
+ .calendar( "instance" );
- nodeName = target.nodeName.toLowerCase();
- if (nodeName === "input") {
- target.disabled = true;
- inst.trigger.filter("button").
- each(function() { this.disabled = true; }).end().
- filter("img").css({opacity: "0.5", cursor: "default"});
- } else if (nodeName === "div" || nodeName === "span") {
- inline = $target.children("." + this._inlineClass);
- inline.children().addClass("ui-state-disabled");
- inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
- prop("disabled", true);
- }
- this._disabledInputs = $.map(this._disabledInputs,
- function(value) { return (value === target ? null : value); }); // delete entry
- this._disabledInputs[this._disabledInputs.length] = target;
- },
+ this.calendarInstance.buttonClickContext = that.element[ 0 ];
- /* Is the first field in a jQuery collection disabled as a datepicker?
- * @param target element - the target input field or division or span
- * @return boolean - true if disabled, false if enabled
- */
- _isDisabledDatepicker: function(target) {
- if (!target) {
- return false;
- }
- for (var i = 0; i < this._disabledInputs.length; i++) {
- if (this._disabledInputs[i] === target) {
- return true;
- }
- }
- return false;
- },
+ this._setHiddenPicker();
- /* Retrieve the instance data for the target control.
- * @param target element - the target input field or division or span
- * @return object - the associated instance data
- * @throws error if a jQuery problem getting data
- */
- _getInst: function(target) {
- try {
- return $.data(target, "datepicker");
- }
- catch (err) {
- throw "Missing instance data for this datepicker";
- }
+ this.element.attr({
+ "aria-haspopup": true,
+ "aria-owns": this.calendar.attr( "id" )
+ });
},
- /* Update or retrieve the settings for a date picker attached to an input field or division.
- * @param target element - the target input field or division or span
- * @param name object - the new settings to update or
- * string - the name of the setting to change or retrieve,
- * when retrieving also "all" for all instance settings or
- * "defaults" for all global defaults
- * @param value any - the new value for the setting
- * (omit if above is an object or to retrieve a value)
- */
- _optionDatepicker: function(target, name, value) {
- var settings, date, minDate, maxDate,
- inst = this._getInst(target);
-
- if (arguments.length === 2 && typeof name === "string") {
- return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
- (inst ? (name === "all" ? $.extend({}, inst.settings) :
- this._get(inst, name)) : null));
- }
-
- settings = name || {};
- if (typeof name === "string") {
- settings = {};
- settings[name] = value;
- }
-
- if (inst) {
- if (this._curInst === inst) {
- this._hideDatepicker();
+ _inputEvents: {
+ keydown: function( event ) {
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.TAB:
+ // Waiting for close() will make popup hide too late, which breaks tab key behavior
+ this.calendar.hide();
+ this.close( event );
+ break;
+ case $.ui.keyCode.ESCAPE:
+ if ( this.isOpen ) {
+ this.close( event );
+ }
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.UP:
+ clearTimeout( this.closeTimer );
+ this._delay( function() {
+ this.open( event );
+ this.calendarInstance.grid.focus();
+ }, 1 );
+ break;
}
-
- date = this._getDateDatepicker(target, true);
- minDate = this._getMinMaxDate(inst, "min");
- maxDate = this._getMinMaxDate(inst, "max");
- datepicker_extendRemove(inst.settings, settings);
- // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
- if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
- inst.settings.minDate = this._formatDate(inst, minDate);
+ },
+ keyup: function() {
+ if ( this.isValid() ) {
+ this.refresh();
}
- if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
- inst.settings.maxDate = this._formatDate(inst, maxDate);
+ },
+ mousedown: function( event ) {
+ if ( this.isOpen ) {
+ this.suppressExpandOnFocus = true;
+ this.close();
+ return;
}
- if ( "disabled" in settings ) {
- if ( settings.disabled ) {
- this._disableDatepicker(target);
- } else {
- this._enableDatepicker(target);
- }
- }
- this._attachments($(target), inst);
- this._autoSize(inst);
- this._setDate(inst, date);
- this._updateAlternate(inst);
- this._updateDatepicker(inst);
- }
- },
-
- // change method deprecated
- _changeDatepicker: function(target, name, value) {
- this._optionDatepicker(target, name, value);
- },
-
- /* Redraw the date picker attached to an input field or division.
- * @param target element - the target input field or division or span
- */
- _refreshDatepicker: function(target) {
- var inst = this._getInst(target);
- if (inst) {
- this._updateDatepicker(inst);
- }
- },
-
- /* Set the dates for a jQuery selection.
- * @param target element - the target input field or division or span
- * @param date Date - the new date
- */
- _setDateDatepicker: function(target, date) {
- var inst = this._getInst(target);
- if (inst) {
- this._setDate(inst, date);
- this._updateDatepicker(inst);
- this._updateAlternate(inst);
- }
- },
-
- /* Get the date(s) for the first entry in a jQuery selection.
- * @param target element - the target input field or division or span
- * @param noDefault boolean - true if no default date is to be used
- * @return Date - the current date
- */
- _getDateDatepicker: function(target, noDefault) {
- var inst = this._getInst(target);
- if (inst && !inst.inline) {
- this._setDateFromField(inst, noDefault);
- }
- return (inst ? this._getDate(inst) : null);
- },
-
- /* Handle keystrokes. */
- _doKeyDown: function(event) {
- var onSelect, dateStr, sel,
- inst = $.datepicker._getInst(event.target),
- handled = true,
- isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
-
- inst._keyEvent = true;
- if ($.datepicker._datepickerShowing) {
- switch (event.keyCode) {
- case 9: $.datepicker._hideDatepicker();
- handled = false;
- break; // hide on tab out
- case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
- $.datepicker._currentClass + ")", inst.dpDiv);
- if (sel[0]) {
- $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
- }
-
- onSelect = $.datepicker._get(inst, "onSelect");
- if (onSelect) {
- dateStr = $.datepicker._formatDate(inst);
-
- // trigger custom callback
- onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
- } else {
- $.datepicker._hideDatepicker();
- }
-
- return false; // don't submit the form
- case 27: $.datepicker._hideDatepicker();
- break; // hide on escape
- case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
- -$.datepicker._get(inst, "stepBigMonths") :
- -$.datepicker._get(inst, "stepMonths")), "M");
- break; // previous month/year on page up/+ ctrl
- case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
- +$.datepicker._get(inst, "stepBigMonths") :
- +$.datepicker._get(inst, "stepMonths")), "M");
- break; // next month/year on page down/+ ctrl
- case 35: if (event.ctrlKey || event.metaKey) {
- $.datepicker._clearDate(event.target);
- }
- handled = event.ctrlKey || event.metaKey;
- break; // clear on ctrl or command +end
- case 36: if (event.ctrlKey || event.metaKey) {
- $.datepicker._gotoToday(event.target);
- }
- handled = event.ctrlKey || event.metaKey;
- break; // current on ctrl or command +home
- case 37: if (event.ctrlKey || event.metaKey) {
- $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
- }
- handled = event.ctrlKey || event.metaKey;
- // -1 day on ctrl or command +left
- if (event.originalEvent.altKey) {
- $.datepicker._adjustDate(event.target, (event.ctrlKey ?
- -$.datepicker._get(inst, "stepBigMonths") :
- -$.datepicker._get(inst, "stepMonths")), "M");
- }
- // next month/year on alt +left on Mac
- break;
- case 38: if (event.ctrlKey || event.metaKey) {
- $.datepicker._adjustDate(event.target, -7, "D");
- }
- handled = event.ctrlKey || event.metaKey;
- break; // -1 week on ctrl or command +up
- case 39: if (event.ctrlKey || event.metaKey) {
- $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
- }
- handled = event.ctrlKey || event.metaKey;
- // +1 day on ctrl or command +right
- if (event.originalEvent.altKey) {
- $.datepicker._adjustDate(event.target, (event.ctrlKey ?
- +$.datepicker._get(inst, "stepBigMonths") :
- +$.datepicker._get(inst, "stepMonths")), "M");
- }
- // next month/year on alt +right
- break;
- case 40: if (event.ctrlKey || event.metaKey) {
- $.datepicker._adjustDate(event.target, +7, "D");
- }
- handled = event.ctrlKey || event.metaKey;
- break; // +1 week on ctrl or command +down
- default: handled = false;
- }
- } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
- $.datepicker._showDatepicker(this);
- } else {
- handled = false;
- }
-
- if (handled) {
- event.preventDefault();
- event.stopPropagation();
- }
- },
-
- /* Filter entered characters - based on date format. */
- _doKeyPress: function(event) {
- var chars, chr,
- inst = $.datepicker._getInst(event.target);
-
- if ($.datepicker._get(inst, "constrainInput")) {
- chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
- chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
- return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
- }
- },
-
- /* Synchronise manual entry and field/alternate field. */
- _doKeyUp: function(event) {
- var date,
- inst = $.datepicker._getInst(event.target);
-
- if (inst.input.val() !== inst.lastVal) {
- try {
- date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
- (inst.input ? inst.input.val() : null),
- $.datepicker._getFormatConfig(inst));
-
- if (date) { // only if valid
- $.datepicker._setDateFromField(inst);
- $.datepicker._updateAlternate(inst);
- $.datepicker._updateDatepicker(inst);
- }
+ this.open( event );
+ clearTimeout( this.closeTimer );
+ },
+ focus: function( event ) {
+ if ( !this.suppressExpandOnFocus && !this.isOpen ) {
+ this._delay( function() {
+ this.open( event );
+ });
}
- catch (err) {
+ this._delay( function() {
+ this.suppressExpandOnFocus = false;
+ }, 100 );
+ },
+ blur: function() {
+ this.suppressExpandOnFocus = false;
+ }
+ },
+
+ _calendarEvents: {
+ focusout: function( event ) {
+ // use a timer to allow click to clear it and letting that
+ // handle the closing instead of opening again
+ // also allows tabbing inside the calendar without it closing
+ this.closeTimer = this._delay( function() {
+ this.close( event );
+ }, 150 );
+ },
+ focusin: function() {
+ clearTimeout( this.closeTimer );
+ },
+ mouseup: function() {
+ clearTimeout( this.closeTimer );
+ },
+ // TODO on TAB (or shift TAB), make sure it ends up on something useful in DOM order
+ keyup: function( event ) {
+ if ( event.keyCode === $.ui.keyCode.ESCAPE && this.calendar.is( ":visible" ) ) {
+ this.close( event );
+ this._focusTrigger();
}
}
- return true;
},
- /* Pop-up the date picker for a given input field.
- * If false returned from beforeShow event handler do not show.
- * @param input element - the input field attached to the date picker or
- * event - if triggered by focus
- */
- _showDatepicker: function(input) {
- input = input.target || input;
- if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
- input = $("input", input.parentNode)[0];
- }
-
- if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
- return;
- }
-
- var inst, beforeShow, beforeShowSettings, isFixed,
- offset, showAnim, duration;
-
- inst = $.datepicker._getInst(input);
- if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
- $.datepicker._curInst.dpDiv.stop(true, true);
- if ( inst && $.datepicker._datepickerShowing ) {
- $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
- }
- }
-
- beforeShow = $.datepicker._get(inst, "beforeShow");
- beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
- if(beforeShowSettings === false){
- return;
- }
- datepicker_extendRemove(inst.settings, beforeShowSettings);
-
- inst.lastVal = null;
- $.datepicker._lastInput = input;
- $.datepicker._setDateFromField(inst);
-
- if ($.datepicker._inDialog) { // hide cursor
- input.value = "";
- }
- if (!$.datepicker._pos) { // position below input
- $.datepicker._pos = $.datepicker._findPos(input);
- $.datepicker._pos[1] += input.offsetHeight; // add the height
- }
-
- isFixed = false;
- $(input).parents().each(function() {
- isFixed |= $(this).css("position") === "fixed";
- return !isFixed;
- });
-
- offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
- $.datepicker._pos = null;
- //to avoid flashes on Firefox
- inst.dpDiv.empty();
- // determine sizing offscreen
- inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
- $.datepicker._updateDatepicker(inst);
- // fix width for dynamic number of date pickers
- // and adjust position before showing
- offset = $.datepicker._checkOffset(inst, offset, isFixed);
- inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
- "static" : (isFixed ? "fixed" : "absolute")), display: "none",
- left: offset.left + "px", top: offset.top + "px"});
-
- if (!inst.inline) {
- showAnim = $.datepicker._get(inst, "showAnim");
- duration = $.datepicker._get(inst, "duration");
- inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
- $.datepicker._datepickerShowing = true;
-
- if ( $.effects && $.effects.effect[ showAnim ] ) {
- inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
- } else {
- inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+ _documentEvents: {
+ mousedown: function( event ) {
+ if ( !this.isOpen ) {
+ return;
}
- if ( $.datepicker._shouldFocusInput( inst ) ) {
- inst.input.trigger( "focus" );
+ if ( !$( event.target ).closest( this.element.add( this.calendar ) ).length ) {
+ this.close( event );
}
-
- $.datepicker._curInst = inst;
}
},
- /* Generate the date picker content. */
- _updateDatepicker: function(inst) {
- this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
- datepicker_instActive = inst; // for delegate hover events
- inst.dpDiv.empty().append(this._generateHTML(inst));
- this._attachHandlers(inst);
+ _appendTo: function() {
+ var element = this.options.appendTo;
- var origyearshtml,
- numMonths = this._getNumberOfMonths(inst),
- cols = numMonths[1],
- width = 17,
- activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
-
- if ( activeCell.length > 0 ) {
- datepicker_handleMouseover.apply( activeCell.get( 0 ) );
+ if ( element ) {
+ element = element.jquery || element.nodeType ?
+ $( element ) :
+ this.document.find( element ).eq( 0 );
}
- inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
- if (cols > 1) {
- inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+ if ( !element || !element[ 0 ] ) {
+ element = this.element.closest( ".ui-front, dialog" );
}
- inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
- "Class"]("ui-datepicker-multi");
- inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
- "Class"]("ui-datepicker-rtl");
- if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
- inst.input.trigger( "focus" );
+ if ( !element.length ) {
+ element = this.document[ 0 ].body;
}
- // deffered render of the years select (to avoid flashes on Firefox)
- if( inst.yearshtml ){
- origyearshtml = inst.yearshtml;
- setTimeout(function(){
- //assure that inst.yearshtml didn't change.
- if( origyearshtml === inst.yearshtml && inst.yearshtml ){
- inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
- }
- origyearshtml = inst.yearshtml = null;
- }, 0);
- }
+ return element;
},
- // #6694 - don't focus the input if it's already focused
- // this breaks the change event in IE
- // Support: IE and jQuery <1.9
- _shouldFocusInput: function( inst ) {
- return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+ _focusTrigger: function() {
+ this.suppressExpandOnFocus = true;
+ this.element.focus();
},
- /* Check positioning to remain on screen. */
- _checkOffset: function(inst, offset, isFixed) {
- var dpWidth = inst.dpDiv.outerWidth(),
- dpHeight = inst.dpDiv.outerHeight(),
- inputWidth = inst.input ? inst.input.outerWidth() : 0,
- inputHeight = inst.input ? inst.input.outerHeight() : 0,
- viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
- viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
-
- offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
- offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
- offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
-
- // now check if datepicker is showing outside window viewport - move to a better place if so.
- offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
- Math.abs(offset.left + dpWidth - viewWidth) : 0);
- offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
- Math.abs(dpHeight + inputHeight) : 0);
-
- return offset;
+ refresh: function() {
+ this.calendarInstance.option( "value", this._getParsedValue() );
},
- /* Find an object's position on the screen. */
- _findPos: function(obj) {
- var position,
- inst = this._getInst(obj),
- isRTL = this._get(inst, "isRTL");
-
- while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
- obj = obj[isRTL ? "previousSibling" : "nextSibling"];
- }
-
- position = $(obj).offset();
- return [position.left, position.top];
- },
-
- /* Hide the date picker from view.
- * @param input element - the input field attached to the date picker
- */
- _hideDatepicker: function(input) {
- var showAnim, duration, postProcess, onClose,
- inst = this._curInst;
-
- if (!inst || (input && inst !== $.data(input, "datepicker"))) {
+ open: function( event ) {
+ if ( this.isOpen ) {
return;
}
-
- if (this._datepickerShowing) {
- showAnim = this._get(inst, "showAnim");
- duration = this._get(inst, "duration");
- postProcess = function() {
- $.datepicker._tidyDialog(inst);
- };
-
- // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
- if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
- inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
- } else {
- inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
- (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
- }
-
- if (!showAnim) {
- postProcess();
- }
- this._datepickerShowing = false;
-
- onClose = this._get(inst, "onClose");
- if (onClose) {
- onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
- }
-
- this._lastInput = null;
- if (this._inDialog) {
- this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
- if ($.blockUI) {
- $.unblockUI();
- $("body").append(this.dpDiv);
- }
- }
- this._inDialog = false;
- }
- },
-
- /* Tidy up after a dialog display. */
- _tidyDialog: function(inst) {
- inst.dpDiv.removeClass(this._dialogClass).off(".ui-datepicker-calendar");
- },
-
- /* Close date picker if clicked elsewhere. */
- _checkExternalClick: function(event) {
- if (!$.datepicker._curInst) {
+ if ( this._trigger( "beforeOpen", event ) === false ) {
return;
}
- var $target = $(event.target),
- inst = $.datepicker._getInst($target[0]);
+ this.calendarInstance.refresh();
+ this.calendar
+ .attr({
+ "aria-hidden": false,
+ "aria-expanded": true
+ })
+ .show()
+ .position( this._buildPosition() )
+ .hide();
+ this._show( this.calendar, this.options.show );
- if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
- $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
- !$target.hasClass($.datepicker.markerClassName) &&
- !$target.closest("." + $.datepicker._triggerClass).length &&
- $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
- ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
- $.datepicker._hideDatepicker();
- }
- },
+ // Take trigger out of tab order to allow shift-tab to skip trigger
+ // TODO Does this really make sense? related bug: tab-shift moves focus to last element on page
+ this.element.attr( "tabindex", -1 );
+ this.isOpen = true;
- /* Adjust one of the date sub-fields. */
- _adjustDate: function(id, offset, period) {
- var target = $(id),
- inst = this._getInst(target[0]);
-
- if (this._isDisabledDatepicker(target[0])) {
- return;
- }
- this._adjustInstDate(inst, offset +
- (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
- period);
- this._updateDatepicker(inst);
- },
-
- /* Action for current link. */
- _gotoToday: function(id) {
- var date,
- target = $(id),
- inst = this._getInst(target[0]);
-
- if (this._get(inst, "gotoCurrent") && inst.currentDay) {
- inst.selectedDay = inst.currentDay;
- inst.drawMonth = inst.selectedMonth = inst.currentMonth;
- inst.drawYear = inst.selectedYear = inst.currentYear;
- } else {
- date = new Date();
- inst.selectedDay = date.getDate();
- inst.drawMonth = inst.selectedMonth = date.getMonth();
- inst.drawYear = inst.selectedYear = date.getFullYear();
- }
- this._notifyChange(inst);
- this._adjustDate(target);
+ this._trigger( "open", event );
},
- /* Action for selecting a new month/year. */
- _selectMonthYear: function(id, select, period) {
- var target = $(id),
- inst = this._getInst(target[0]);
+ close: function( event ) {
+ this._setHiddenPicker();
+ this._hide( this.calendar, this.options.hide );
- inst["selected" + (period === "M" ? "Month" : "Year")] =
- inst["draw" + (period === "M" ? "Month" : "Year")] =
- parseInt(select.options[select.selectedIndex].value,10);
+ this.element.attr( "tabindex", 0 );
- this._notifyChange(inst);
- this._adjustDate(target);
+ this.isOpen = false;
+ this._trigger( "close", event );
},
- /* Action for selecting a day. */
- _selectDay: function(id, month, year, td) {
- var inst,
- target = $(id);
-
- if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
- return;
- }
-
- inst = this._getInst(target[0]);
- inst.selectedDay = inst.currentDay = $("a", td).html();
- inst.selectedMonth = inst.currentMonth = month;
- inst.selectedYear = inst.currentYear = year;
- this._selectDate(id, this._formatDate(inst,
- inst.currentDay, inst.currentMonth, inst.currentYear));
+ _setHiddenPicker: function() {
+ this.calendar.attr({
+ "aria-hidden": true,
+ "aria-expanded": false
+ });
},
- /* Erase the input field and hide the date picker. */
- _clearDate: function(id) {
- var target = $(id);
- this._selectDate(target, "");
+ _buildPosition: function() {
+ return $.extend( { of: this.element }, this.options.position );
},
- /* Update the input field with the selected date. */
- _selectDate: function(id, dateStr) {
- var onSelect,
- target = $(id),
- inst = this._getInst(target[0]);
-
- dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
- if (inst.input) {
- inst.input.val(dateStr);
- }
- this._updateAlternate(inst);
-
- onSelect = this._get(inst, "onSelect");
- if (onSelect) {
- onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
- } else if (inst.input) {
- inst.input.trigger("change"); // fire the change event
- }
-
- if (inst.inline){
- this._updateDatepicker(inst);
+ value: function( value ) {
+ if ( arguments.length ) {
+ this.valueAsDate( Globalize.parseDate( value, this.options.dateFormat ) );
} else {
- this._hideDatepicker();
- this._lastInput = inst.input[0];
- if (typeof(inst.input[0]) !== "object") {
- inst.input.trigger( "focus" ); // restore focus
- }
- this._lastInput = null;
- }
- },
-
- /* Update any alternate field to synchronise with the main field. */
- _updateAlternate: function(inst) {
- var altFormat, date, dateStr,
- altField = this._get(inst, "altField");
-
- if (altField) { // update alternate field too
- altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
- date = this._getDate(inst);
- dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
- $(altField).each(function() { $(this).val(dateStr); });
+ return this._getParsedValue() ? this.element.val() : null;
}
},
- /* Set as beforeShowDay function to prevent selection of weekends.
- * @param date Date - the date to customise
- * @return [boolean, string] - is this date selectable?, what is its CSS class?
- */
- noWeekends: function(date) {
- var day = date.getDay();
- return [(day > 0 && day < 6), ""];
- },
-
- /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
- * @param date Date - the date to get the week for
- * @return number - the number of the week within the year that contains this date
- */
- iso8601Week: function(date) {
- var time,
- checkDate = new Date(date.getTime());
-
- // Find Thursday of this week starting on Monday
- checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
-
- time = checkDate.getTime();
- checkDate.setMonth(0); // Compare with Jan 1
- checkDate.setDate(1);
- return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
- },
-
- /* Parse a string value into a date object.
- * See formatDate below for the possible formats.
- *
- * @param format string - the expected format of the date
- * @param value string - the date in the above format
- * @param settings Object - attributes include:
- * shortYearCutoff number - the cutoff year for determining the century (optional)
- * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
- * dayNames string[7] - names of the days from Sunday (optional)
- * monthNamesShort string[12] - abbreviated names of the months (optional)
- * monthNames string[12] - names of the months (optional)
- * @return Date - the extracted date value or null if value is blank
- */
- parseDate: function (format, value, settings) {
- if (format == null || value == null) {
- throw "Invalid arguments";
- }
-
- value = (typeof value === "object" ? value.toString() : value + "");
- if (value === "") {
- return null;
- }
-
- var iFormat, dim, extra,
- iValue = 0,
- shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
- shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
- new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
- dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
- dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
- monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
- monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
- year = -1,
- month = -1,
- day = -1,
- doy = -1,
- literal = false,
- date,
- // Check whether a format character is doubled
- lookAhead = function(match) {
- var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
- if (matches) {
- iFormat++;
- }
- return matches;
- },
- // Extract a number from the string value
- getNumber = function(match) {
- var isDoubled = lookAhead(match),
- size = (match === "@" ? 14 : (match === "!" ? 20 :
- (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
- minSize = (match === "y" ? size : 1),
- digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
- num = value.substring(iValue).match(digits);
- if (!num) {
- throw "Missing number at position " + iValue;
- }
- iValue += num[0].length;
- return parseInt(num[0], 10);
- },
- // Extract a name from the string value and convert to an index
- getName = function(match, shortNames, longNames) {
- var index = -1,
- names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
- return [ [k, v] ];
- }).sort(function (a, b) {
- return -(a[1].length - b[1].length);
- });
-
- $.each(names, function (i, pair) {
- var name = pair[1];
- if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
- index = pair[0];
- iValue += name.length;
- return false;
- }
- });
- if (index !== -1) {
- return index + 1;
- } else {
- throw "Unknown name at position " + iValue;
- }
- },
- // Confirm that a literal character matches the string value
- checkLiteral = function() {
- if (value.charAt(iValue) !== format.charAt(iFormat)) {
- throw "Unexpected literal at position " + iValue;
- }
- iValue++;
- };
-
- for (iFormat = 0; iFormat < format.length; iFormat++) {
- if (literal) {
- if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
- literal = false;
- } else {
- checkLiteral();
- }
- } else {
- switch (format.charAt(iFormat)) {
- case "d":
- day = getNumber("d");
- break;
- case "D":
- getName("D", dayNamesShort, dayNames);
- break;
- case "o":
- doy = getNumber("o");
- break;
- case "m":
- month = getNumber("m");
- break;
- case "M":
- month = getName("M", monthNamesShort, monthNames);
- break;
- case "y":
- year = getNumber("y");
- break;
- case "@":
- date = new Date(getNumber("@"));
- year = date.getFullYear();
- month = date.getMonth() + 1;
- day = date.getDate();
- break;
- case "!":
- date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
- year = date.getFullYear();
- month = date.getMonth() + 1;
- day = date.getDate();
- break;
- case "'":
- if (lookAhead("'")){
- checkLiteral();
- } else {
- literal = true;
- }
- break;
- default:
- checkLiteral();
- }
- }
- }
-
- if (iValue < value.length){
- extra = value.substr(iValue);
- if (!/^\s+/.test(extra)) {
- throw "Extra/unparsed characters found in date: " + extra;
- }
- }
-
- if (year === -1) {
- year = new Date().getFullYear();
- } else if (year < 100) {
- year += new Date().getFullYear() - new Date().getFullYear() % 100 +
- (year <= shortYearCutoff ? 0 : -100);
- }
-
- if (doy > -1) {
- month = 1;
- day = doy;
- do {
- dim = this._getDaysInMonth(year, month - 1);
- if (day <= dim) {
- break;
- }
- month++;
- day -= dim;
- } while (true);
- }
-
- date = this._daylightSavingAdjust(new Date(year, month - 1, day));
- if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
- throw "Invalid date"; // E.g. 31/02/00
- }
- return date;
- },
-
- /* Standard date formats. */
- ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
- COOKIE: "D, dd M yy",
- ISO_8601: "yy-mm-dd",
- RFC_822: "D, d M y",
- RFC_850: "DD, dd-M-y",
- RFC_1036: "D, d M y",
- RFC_1123: "D, d M yy",
- RFC_2822: "D, d M yy",
- RSS: "D, d M y", // RFC 822
- TICKS: "!",
- TIMESTAMP: "@",
- W3C: "yy-mm-dd", // ISO 8601
-
- _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
- Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
-
- /* Format a date object into a string value.
- * The format can be combinations of the following:
- * d - day of month (no leading zero)
- * dd - day of month (two digit)
- * o - day of year (no leading zeros)
- * oo - day of year (three digit)
- * D - day name short
- * DD - day name long
- * m - month of year (no leading zero)
- * mm - month of year (two digit)
- * M - month name short
- * MM - month name long
- * y - year (two digit)
- * yy - year (four digit)
- * @ - Unix timestamp (ms since 01/01/1970)
- * ! - Windows ticks (100ns since 01/01/0001)
- * "..." - literal text
- * '' - single quote
- *
- * @param format string - the desired format of the date
- * @param date Date - the date value to format
- * @param settings Object - attributes include:
- * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
- * dayNames string[7] - names of the days from Sunday (optional)
- * monthNamesShort string[12] - abbreviated names of the months (optional)
- * monthNames string[12] - names of the months (optional)
- * @return string - the date in the above format
- */
- formatDate: function (format, date, settings) {
- if (!date) {
- return "";
- }
-
- var iFormat,
- dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
- dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
- monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
- monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
- // Check whether a format character is doubled
- lookAhead = function(match) {
- var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
- if (matches) {
- iFormat++;
- }
- return matches;
- },
- // Format a number, with leading zero if necessary
- formatNumber = function(match, value, len) {
- var num = "" + value;
- if (lookAhead(match)) {
- while (num.length < len) {
- num = "0" + num;
- }
- }
- return num;
- },
- // Format a name, short or long as requested
- formatName = function(match, value, shortNames, longNames) {
- return (lookAhead(match) ? longNames[value] : shortNames[value]);
- },
- output = "",
- literal = false;
-
- if (date) {
- for (iFormat = 0; iFormat < format.length; iFormat++) {
- if (literal) {
- if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
- literal = false;
- } else {
- output += format.charAt(iFormat);
- }
- } else {
- switch (format.charAt(iFormat)) {
- case "d":
- output += formatNumber("d", date.getDate(), 2);
- break;
- case "D":
- output += formatName("D", date.getDay(), dayNamesShort, dayNames);
- break;
- case "o":
- output += formatNumber("o",
- Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
- break;
- case "m":
- output += formatNumber("m", date.getMonth() + 1, 2);
- break;
- case "M":
- output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
- break;
- case "y":
- output += (lookAhead("y") ? date.getFullYear() :
- (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
- break;
- case "@":
- output += date.getTime();
- break;
- case "!":
- output += date.getTime() * 10000 + this._ticksTo1970;
- break;
- case "'":
- if (lookAhead("'")) {
- output += "'";
- } else {
- literal = true;
- }
- break;
- default:
- output += format.charAt(iFormat);
- }
- }
+ valueAsDate: function( value ) {
+ if ( arguments.length ) {
+ if ( this.calendarInstance._isValid( value ) ) {
+ this.calendarInstance.valueAsDate( value );
+ this.element.val( Globalize.format( value, this.options.dateFormat ) );
}
+ } else {
+ return this._getParsedValue();
}
- return output;
},
- /* Extract all possible characters from the date format. */
- _possibleChars: function (format) {
- var iFormat,
- chars = "",
- literal = false,
- // Check whether a format character is doubled
- lookAhead = function(match) {
- var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
- if (matches) {
- iFormat++;
- }
- return matches;
- };
-
- for (iFormat = 0; iFormat < format.length; iFormat++) {
- if (literal) {
- if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
- literal = false;
- } else {
- chars += format.charAt(iFormat);
- }
- } else {
- switch (format.charAt(iFormat)) {
- case "d": case "m": case "y": case "@":
- chars += "0123456789";
- break;
- case "D": case "M":
- return null; // Accept anything
- case "'":
- if (lookAhead("'")) {
- chars += "'";
- } else {
- literal = true;
- }
- break;
- default:
- chars += format.charAt(iFormat);
- }
- }
- }
- return chars;
+ isValid: function() {
+ return this.calendarInstance._isValid( this._getParsedValue() );
},
- /* Get a setting value, defaulting if necessary. */
- _get: function(inst, name) {
- return inst.settings[name] !== undefined ?
- inst.settings[name] : this._defaults[name];
+ _destroy: function() {
+ this.calendarInstance.destroy();
+ this.calendar.remove();
+ this.element.removeAttr( "aria-haspopup aria-owns" );
},
- /* Parse existing date and initialise date picker. */
- _setDateFromField: function(inst, noDefault) {
- if (inst.input.val() === inst.lastVal) {
- return;
- }
-
- var dateFormat = this._get(inst, "dateFormat"),
- dates = inst.lastVal = inst.input ? inst.input.val() : null,
- defaultDate = this._getDefaultDate(inst),
- date = defaultDate,
- settings = this._getFormatConfig(inst);
-
- try {
- date = this.parseDate(dateFormat, dates, settings) || defaultDate;
- } catch (event) {
- dates = (noDefault ? "" : dates);
- }
- inst.selectedDay = date.getDate();
- inst.drawMonth = inst.selectedMonth = date.getMonth();
- inst.drawYear = inst.selectedYear = date.getFullYear();
- inst.currentDay = (dates ? date.getDate() : 0);
- inst.currentMonth = (dates ? date.getMonth() : 0);
- inst.currentYear = (dates ? date.getFullYear() : 0);
- this._adjustInstDate(inst);
+ widget: function() {
+ return this.calendar;
},
- /* Retrieve the default date shown on opening. */
- _getDefaultDate: function(inst) {
- return this._restrictMinMax(inst,
- this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+ _getParsedValue: function() {
+ return Globalize.parseDate( this.element.val(), this.options.dateFormat );
},
- /* A date may be specified as an exact value or a relative one. */
- _determineDate: function(inst, date, defaultDate) {
- var offsetNumeric = function(offset) {
- var date = new Date();
- date.setDate(date.getDate() + offset);
- return date;
- },
- offsetString = function(offset) {
- try {
- return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
- offset, $.datepicker._getFormatConfig(inst));
- }
- catch (e) {
- // Ignore
- }
-
- var date = (offset.toLowerCase().match(/^c/) ?
- $.datepicker._getDate(inst) : null) || new Date(),
- year = date.getFullYear(),
- month = date.getMonth(),
- day = date.getDate(),
- pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
- matches = pattern.exec(offset);
+ _setOption: function( key, value ) {
+ this._super( key, value );
- while (matches) {
- switch (matches[2] || "d") {
- case "d" : case "D" :
- day += parseInt(matches[1],10); break;
- case "w" : case "W" :
- day += parseInt(matches[1],10) * 7; break;
- case "m" : case "M" :
- month += parseInt(matches[1],10);
- day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
- break;
- case "y": case "Y" :
- year += parseInt(matches[1],10);
- day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
- break;
- }
- matches = pattern.exec(offset);
- }
- return new Date(year, month, day);
- },
- newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
- (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
-
- newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
- if (newDate) {
- newDate.setHours(0);
- newDate.setMinutes(0);
- newDate.setSeconds(0);
- newDate.setMilliseconds(0);
+ if ( $.inArray( key, this.calendarOptions ) !== -1 ) {
+ this.calendarInstance.option( key, value );
}
- return this._daylightSavingAdjust(newDate);
- },
- /* Handle switch to/from daylight saving.
- * Hours may be non-zero on daylight saving cut-over:
- * > 12 when midnight changeover, but then cannot generate
- * midnight datetime, so jump to 1AM, otherwise reset.
- * @param date (Date) the date to check
- * @return (Date) the corrected date
- */
- _daylightSavingAdjust: function(date) {
- if (!date) {
- return null;
+ if ( key === "appendTo" ) {
+ this.calendar.appendTo( this._appendTo() );
}
- date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
- return date;
- },
- /* Set the date(s) directly. */
- _setDate: function(inst, date, noChange) {
- var clear = !date,
- origMonth = inst.selectedMonth,
- origYear = inst.selectedYear,
- newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
-
- inst.selectedDay = inst.currentDay = newDate.getDate();
- inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
- inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
- if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
- this._notifyChange(inst);
- }
- this._adjustInstDate(inst);
- if (inst.input) {
- inst.input.val(clear ? "" : this._formatDate(inst));
+ if ( key === "dateFormat" ) {
+ this.element.val( this.calendarInstance.value() );
}
- },
-
- /* Retrieve the date(s) directly. */
- _getDate: function(inst) {
- var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
- this._daylightSavingAdjust(new Date(
- inst.currentYear, inst.currentMonth, inst.currentDay)));
- return startDate;
- },
-
- /* Attach the onxxx handlers. These are declared statically so
- * they work with static code transformers like Caja.
- */
- _attachHandlers: function(inst) {
- var stepMonths = this._get(inst, "stepMonths"),
- id = "#" + inst.id.replace( /\\\\/g, "\\" );
- inst.dpDiv.find("[data-handler]").map(function () {
- var handler = {
- prev: function () {
- $.datepicker._adjustDate(id, -stepMonths, "M");
- },
- next: function () {
- $.datepicker._adjustDate(id, +stepMonths, "M");
- },
- hide: function () {
- $.datepicker._hideDatepicker();
- },
- today: function () {
- $.datepicker._gotoToday(id);
- },
- selectDay: function () {
- $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
- return false;
- },
- selectMonth: function () {
- $.datepicker._selectMonthYear(id, this, "M");
- return false;
- },
- selectYear: function () {
- $.datepicker._selectMonthYear(id, this, "Y");
- return false;
- }
- };
- $(this).on(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
- });
- },
- /* Generate the HTML for the current state of the date picker. */
- _generateHTML: function(inst) {
- var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
- controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
- monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
- selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
- cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
- printDate, dRow, tbody, daySettings, otherMonth, unselectable,
- tempDate = new Date(),
- today = this._daylightSavingAdjust(
- new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
- isRTL = this._get(inst, "isRTL"),
- showButtonPanel = this._get(inst, "showButtonPanel"),
- hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
- navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
- numMonths = this._getNumberOfMonths(inst),
- showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
- stepMonths = this._get(inst, "stepMonths"),
- isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
- currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
- new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
- minDate = this._getMinMaxDate(inst, "min"),
- maxDate = this._getMinMaxDate(inst, "max"),
- drawMonth = inst.drawMonth - showCurrentAtPos,
- drawYear = inst.drawYear;
+ if ( key === "disabled" ) {
+ this.element
+ .prop( "disabled", value )
+ .toggleClass( "ui-state-disabled", value )
+ .attr( "aria-disabled", value );
- if (drawMonth < 0) {
- drawMonth += 12;
- drawYear--;
- }
- if (maxDate) {
- maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
- maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
- maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
- while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
- drawMonth--;
- if (drawMonth < 0) {
- drawMonth = 11;
- drawYear--;
- }
+ if ( value ) {
+ this.close();
}
}
- inst.drawMonth = drawMonth;
- inst.drawYear = drawYear;
-
- prevText = this._get(inst, "prevText");
- prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
- this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
- this._getFormatConfig(inst)));
- prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
- "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
- " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
- (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
-
- nextText = this._get(inst, "nextText");
- nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
- this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
- this._getFormatConfig(inst)));
-
- next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
- "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
- " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
- (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
-
- currentText = this._get(inst, "currentText");
- gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
- currentText = (!navigationAsDateFormat ? currentText :
- this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
-
- controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
- this._get(inst, "closeText") + "</button>" : "");
-
- buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
- (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
- ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
-
- firstDay = parseInt(this._get(inst, "firstDay"),10);
- firstDay = (isNaN(firstDay) ? 0 : firstDay);
-
- showWeek = this._get(inst, "showWeek");
- dayNames = this._get(inst, "dayNames");
- dayNamesMin = this._get(inst, "dayNamesMin");
- monthNames = this._get(inst, "monthNames");
- monthNamesShort = this._get(inst, "monthNamesShort");
- beforeShowDay = this._get(inst, "beforeShowDay");
- showOtherMonths = this._get(inst, "showOtherMonths");
- selectOtherMonths = this._get(inst, "selectOtherMonths");
- defaultDate = this._getDefaultDate(inst);
- html = "";
- dow;
- for (row = 0; row < numMonths[0]; row++) {
- group = "";
- this.maxRows = 4;
- for (col = 0; col < numMonths[1]; col++) {
- selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
- cornerClass = " ui-corner-all";
- calender = "";
- if (isMultiMonth) {
- calender += "<div class='ui-datepicker-group";
- if (numMonths[1] > 1) {
- switch (col) {
- case 0: calender += " ui-datepicker-group-first";
- cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
- case numMonths[1]-1: calender += " ui-datepicker-group-last";
- cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
- default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
- }
- }
- calender += "'>";
- }
- calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
- (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
- (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
- this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
- row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
- "</div><table class='ui-datepicker-calendar'><thead>" +
- "<tr>";
- thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
- for (dow = 0; dow < 7; dow++) { // days of the week
- day = (dow + firstDay) % 7;
- thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
- "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
- }
- calender += thead + "</tr></thead><tbody>";
- daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
- if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
- inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
- }
- leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
- curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
- numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
- this.maxRows = numRows;
- printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
- for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
- calender += "<tr>";
- tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
- this._get(inst, "calculateWeek")(printDate) + "</td>");
- for (dow = 0; dow < 7; dow++) { // create date picker days
- daySettings = (beforeShowDay ?
- beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
- otherMonth = (printDate.getMonth() !== drawMonth);
- unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
- (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
- tbody += "<td class='" +
- ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
- (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
- ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
- (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
- // or defaultDate is current printedDate and defaultDate is selectedDate
- " " + this._dayOverClass : "") + // highlight selected day
- (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
- (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
- (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
- (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
- ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
- (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
- (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
- (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
- (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
- (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
- (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
- "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
- printDate.setDate(printDate.getDate() + 1);
- printDate = this._daylightSavingAdjust(printDate);
- }
- calender += tbody + "</tr>";
- }
- drawMonth++;
- if (drawMonth > 11) {
- drawMonth = 0;
- drawYear++;
- }
- calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
- ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
- group += calender;
- }
- html += group;
- }
- html += buttonPanel;
- inst._keyEvent = false;
- return html;
- },
-
- /* Generate the month and year header. */
- _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
- secondary, monthNames, monthNamesShort) {
-
- var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
- changeMonth = this._get(inst, "changeMonth"),
- changeYear = this._get(inst, "changeYear"),
- showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
- html = "<div class='ui-datepicker-title'>",
- monthHtml = "";
-
- // month selection
- if (secondary || !changeMonth) {
- monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
- } else {
- inMinYear = (minDate && minDate.getFullYear() === drawYear);
- inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
- monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
- for ( month = 0; month < 12; month++) {
- if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
- monthHtml += "<option value='" + month + "'" +
- (month === drawMonth ? " selected='selected'" : "") +
- ">" + monthNamesShort[month] + "</option>";
- }
- }
- monthHtml += "</select>";
- }
-
- if (!showMonthAfterYear) {
- html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
- }
-
- // year selection
- if ( !inst.yearshtml ) {
- inst.yearshtml = "";
- if (secondary || !changeYear) {
- html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
- } else {
- // determine range of years to display
- years = this._get(inst, "yearRange").split(":");
- thisYear = new Date().getFullYear();
- determineYear = function(value) {
- var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
- (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
- parseInt(value, 10)));
- return (isNaN(year) ? thisYear : year);
- };
- year = determineYear(years[0]);
- endYear = Math.max(year, determineYear(years[1] || ""));
- year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
- endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
- inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
- for (; year <= endYear; year++) {
- inst.yearshtml += "<option value='" + year + "'" +
- (year === drawYear ? " selected='selected'" : "") +
- ">" + year + "</option>";
- }
- inst.yearshtml += "</select>";
-
- html += inst.yearshtml;
- inst.yearshtml = null;
- }
- }
-
- html += this._get(inst, "yearSuffix");
- if (showMonthAfterYear) {
- html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
- }
- html += "</div>"; // Close datepicker_header
- return html;
- },
-
- /* Adjust one of the date sub-fields. */
- _adjustInstDate: function(inst, offset, period) {
- var year = inst.drawYear + (period === "Y" ? offset : 0),
- month = inst.drawMonth + (period === "M" ? offset : 0),
- day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
- date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
-
- inst.selectedDay = date.getDate();
- inst.drawMonth = inst.selectedMonth = date.getMonth();
- inst.drawYear = inst.selectedYear = date.getFullYear();
- if (period === "M" || period === "Y") {
- this._notifyChange(inst);
- }
- },
-
- /* Ensure a date is within any min/max bounds. */
- _restrictMinMax: function(inst, date) {
- var minDate = this._getMinMaxDate(inst, "min"),
- maxDate = this._getMinMaxDate(inst, "max"),
- newDate = (minDate && date < minDate ? minDate : date);
- return (maxDate && newDate > maxDate ? maxDate : newDate);
- },
-
- /* Notify change of month/year. */
- _notifyChange: function(inst) {
- var onChange = this._get(inst, "onChangeMonthYear");
- if (onChange) {
- onChange.apply((inst.input ? inst.input[0] : null),
- [inst.selectedYear, inst.selectedMonth + 1, inst]);
- }
- },
-
- /* Determine the number of months to show. */
- _getNumberOfMonths: function(inst) {
- var numMonths = this._get(inst, "numberOfMonths");
- return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
- },
-
- /* Determine the current maximum date - ensure no time components are set. */
- _getMinMaxDate: function(inst, minMax) {
- return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
- },
-
- /* Find the number of days in a given month. */
- _getDaysInMonth: function(year, month) {
- return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
- },
-
- /* Find the day of the week of the first of a month. */
- _getFirstDayOfMonth: function(year, month) {
- return new Date(year, month, 1).getDay();
- },
-
- /* Determines if we should allow a "next/prev" month display change. */
- _canAdjustMonth: function(inst, offset, curYear, curMonth) {
- var numMonths = this._getNumberOfMonths(inst),
- date = this._daylightSavingAdjust(new Date(curYear,
- curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
-
- if (offset < 0) {
- date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+ if ( key === "position" ) {
+ this.calendar.position( this._buildPosition() );
}
- return this._isInRange(inst, date);
- },
-
- /* Is the given date in the accepted range? */
- _isInRange: function(inst, date) {
- var yearSplit, currentYear,
- minDate = this._getMinMaxDate(inst, "min"),
- maxDate = this._getMinMaxDate(inst, "max"),
- minYear = null,
- maxYear = null,
- years = this._get(inst, "yearRange");
- if (years){
- yearSplit = years.split(":");
- currentYear = new Date().getFullYear();
- minYear = parseInt(yearSplit[0], 10);
- maxYear = parseInt(yearSplit[1], 10);
- if ( yearSplit[0].match(/[+\-].*/) ) {
- minYear += currentYear;
- }
- if ( yearSplit[1].match(/[+\-].*/) ) {
- maxYear += currentYear;
- }
- }
-
- return ((!minDate || date.getTime() >= minDate.getTime()) &&
- (!maxDate || date.getTime() <= maxDate.getTime()) &&
- (!minYear || date.getFullYear() >= minYear) &&
- (!maxYear || date.getFullYear() <= maxYear));
- },
-
- /* Provide the configuration settings for formatting/parsing. */
- _getFormatConfig: function(inst) {
- var shortYearCutoff = this._get(inst, "shortYearCutoff");
- shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
- new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
- return {shortYearCutoff: shortYearCutoff,
- dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
- monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
- },
-
- /* Format the given date for display. */
- _formatDate: function(inst, day, month, year) {
- if (!day) {
- inst.currentDay = inst.selectedDay;
- inst.currentMonth = inst.selectedMonth;
- inst.currentYear = inst.selectedYear;
- }
- var date = (day ? (typeof day === "object" ? day :
- this._daylightSavingAdjust(new Date(year, month, day))) :
- this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
- return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
}
});
-/*
- * Bind hover events for datepicker elements.
- * Done via delegate so the binding only occurs once in the lifetime of the parent div.
- * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
- */
-function datepicker_bindHover(dpDiv) {
- var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
- return dpDiv.on( "mouseout", selector, function() {
- $(this).removeClass("ui-state-hover");
- if (this.className.indexOf("ui-datepicker-prev") !== -1) {
- $(this).removeClass("ui-datepicker-prev-hover");
- }
- if (this.className.indexOf("ui-datepicker-next") !== -1) {
- $(this).removeClass("ui-datepicker-next-hover");
- }
- })
- .on( "mouseover", selector, datepicker_handleMouseover );
-}
-
-function datepicker_handleMouseover() {
- if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
- $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
- $(this).addClass("ui-state-hover");
- if (this.className.indexOf("ui-datepicker-prev") !== -1) {
- $(this).addClass("ui-datepicker-prev-hover");
- }
- if (this.className.indexOf("ui-datepicker-next") !== -1) {
- $(this).addClass("ui-datepicker-next-hover");
- }
- }
-}
-
-/* jQuery extend now ignores nulls! */
-function datepicker_extendRemove(target, props) {
- $.extend(target, props);
- for (var name in props) {
- if (props[name] == null) {
- target[name] = props[name];
- }
- }
- return target;
-}
-
-/* Invoke the datepicker functionality.
- @param options string - a command, optionally followed by additional parameters or
- Object - settings for attaching new datepicker functionality
- @return jQuery object */
-$.fn.datepicker = function(options){
-
- /* Verify an empty collection wasn't passed - Fixes #6976 */
- if ( !this.length ) {
- return this;
- }
-
- /* Initialise the date picker. */
- if (!$.datepicker.initialized) {
- $(document).on( "mousedown", $.datepicker._checkExternalClick );
- $.datepicker.initialized = true;
- }
-
- /* Append datepicker main container to body if not exist. */
- if ($("#"+$.datepicker._mainDivId).length === 0) {
- $("body").append($.datepicker.dpDiv);
- }
-
- var otherArgs = Array.prototype.slice.call(arguments, 1);
- if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
- return $.datepicker["_" + options + "Datepicker"].
- apply($.datepicker, [this[0]].concat(otherArgs));
- }
- if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
- return $.datepicker["_" + options + "Datepicker"].
- apply($.datepicker, [this[0]].concat(otherArgs));
- }
- return this.each(function() {
- typeof options === "string" ?
- $.datepicker["_" + options + "Datepicker"].
- apply($.datepicker, [this].concat(otherArgs)) :
- $.datepicker._attachDatepicker(this, options);
- });
-};
-
-$.datepicker = new Datepicker(); // singleton instance
-$.datepicker.initialized = false;
-$.datepicker.uuid = new Date().getTime();
-$.datepicker.version = "@VERSION";
+$.each( $.ui.datepicker.prototype.calendarOptions, function( index, option ) {
+ $.ui.datepicker.prototype.options[ option ] = $.ui.calendar.prototype.options[ option ];
+});
-return $.datepicker;
+return widget;
}));