iqvoc 4.2.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile +15 -12
  4. data/Gemfile.lock +124 -90
  5. data/README.md +17 -1
  6. data/app/assets/images/iqvoc_logo.svg +41 -0
  7. data/app/assets/javascripts/framework.js +1 -1
  8. data/app/assets/javascripts/iqvoc/concept_mapper.js +62 -0
  9. data/app/assets/javascripts/iqvoc/concept_mapping_manager.js +137 -0
  10. data/app/assets/javascripts/iqvoc/entityselect.js.erb +51 -19
  11. data/app/assets/javascripts/iqvoc/federated_concept_mapper.js +75 -0
  12. data/app/assets/javascripts/iqvoc/iqvoc.js +16 -4
  13. data/app/assets/javascripts/iqvoc/label_resolver.js +23 -0
  14. data/app/assets/javascripts/iqvoc/manifest.js +4 -0
  15. data/app/assets/javascripts/iqvoc/onebox.js.erb +4 -4
  16. data/app/assets/javascripts/iqvoc/quicksearch.js +1 -1
  17. data/app/assets/stylesheets/framework.css.scss +2 -1
  18. data/app/assets/stylesheets/iqvoc/_settings.css.scss +12 -0
  19. data/app/assets/stylesheets/iqvoc/components/_components.css.scss +237 -0
  20. data/app/assets/stylesheets/iqvoc/{entity_select.css.scss → components/_entity_select.css.scss} +0 -2
  21. data/app/assets/stylesheets/iqvoc/{forms.css.scss → components/_forms.css.scss} +0 -0
  22. data/app/assets/stylesheets/iqvoc/{note.css.scss → components/_notes.css.scss} +2 -10
  23. data/app/assets/stylesheets/iqvoc/{panel.css.scss → components/_panels.css.scss} +3 -5
  24. data/app/assets/stylesheets/iqvoc/{sidebar.css.scss → components/_sidebars.css.scss} +0 -0
  25. data/app/assets/stylesheets/iqvoc/{visualization.css.scss → components/_visualization.css.scss} +0 -0
  26. data/app/assets/stylesheets/iqvoc/{bootstrap_extensions.css.scss → hacks/_bootstrap_extensions.css.scss} +0 -0
  27. data/app/assets/stylesheets/iqvoc/{hacks.css.scss → hacks/_hacks.css.scss} +0 -0
  28. data/app/assets/stylesheets/iqvoc/{jquery-ui_extensions.css.scss → hacks/_jquery-ui_extensions.css.scss} +0 -0
  29. data/app/assets/stylesheets/iqvoc/manifest.css.scss +10 -10
  30. data/app/controllers/concepts/alphabetical_controller.rb +23 -9
  31. data/app/controllers/concepts/scheme_controller.rb +19 -0
  32. data/app/controllers/concepts_controller.rb +13 -1
  33. data/app/controllers/concerns/dataset_initialization.rb +18 -0
  34. data/app/controllers/dashboard_controller.rb +17 -0
  35. data/app/controllers/hierarchy_controller.rb +65 -6
  36. data/app/controllers/{import_controller.rb → imports_controller.rb} +14 -11
  37. data/app/controllers/rdf_controller.rb +6 -0
  38. data/app/controllers/remote_labels_controller.rb +31 -0
  39. data/app/controllers/search_results_controller.rb +95 -14
  40. data/app/helpers/application_helper.rb +6 -4
  41. data/app/helpers/dashboard_helper.rb +3 -3
  42. data/app/helpers/link_helper.rb +14 -0
  43. data/app/helpers/search_results_helper.rb +5 -1
  44. data/app/jobs/import_job.rb +19 -0
  45. data/app/models/concept/base.rb +2 -2
  46. data/app/models/dataset/adaptors/iqvoc/alphabetical_search_adaptor.rb +38 -0
  47. data/app/models/dataset/adaptors/iqvoc/http_adaptor.rb +39 -0
  48. data/app/models/dataset/adaptors/iqvoc/label_adaptor.rb +15 -0
  49. data/app/models/dataset/adaptors/iqvoc/search_adaptor.rb +60 -0
  50. data/app/models/dataset/iqvoc_dataset.rb +39 -0
  51. data/app/models/import.rb +16 -0
  52. data/app/models/labeling/skos/base.rb +2 -1
  53. data/app/models/note/base.rb +2 -2
  54. data/app/models/note/skos/change_note.rb +3 -2
  55. data/app/presenters/alphabetical_search_result.rb +33 -0
  56. data/app/presenters/alphabetical_search_result_remote.rb +37 -0
  57. data/app/presenters/search_result.rb +33 -0
  58. data/app/presenters/search_result_collection.rb +8 -0
  59. data/app/presenters/search_result_remote.rb +52 -0
  60. data/app/views/collections/_sidebar.html.erb +3 -3
  61. data/app/views/concepts/_form.html.erb +1 -1
  62. data/app/views/concepts/alphabetical/_search_result.html.erb +16 -0
  63. data/app/views/concepts/alphabetical/_search_result_remote.html.erb +14 -0
  64. data/app/views/concepts/alphabetical/index.html.erb +5 -3
  65. data/app/views/concepts/expired/index.html.erb +5 -2
  66. data/app/views/concepts/scheme/_sidebar.html.erb +3 -3
  67. data/app/views/concepts/sidebars/_singular.html.erb +4 -4
  68. data/app/views/dashboard/_sidebar.html.erb +7 -4
  69. data/app/views/dashboard/index.html.erb +1 -1
  70. data/app/views/dashboard/reset.html.erb +6 -0
  71. data/app/views/imports/index.html.erb +44 -0
  72. data/app/views/imports/show.html.erb +7 -0
  73. data/app/views/layouts/application.html.erb +7 -1
  74. data/app/views/partials/labeling/skos/_search_result.html.erb +12 -16
  75. data/app/views/partials/match/_edit_base.html.erb +1 -1
  76. data/app/views/partials/note/_search_result.html.erb +8 -5
  77. data/app/views/partials/note/skos/change_note/_search_result.html.erb +7 -10
  78. data/app/views/partials/note/skos/definition/_search_result.html.erb +5 -5
  79. data/app/views/rdf/dataset.iqrdf +9 -0
  80. data/app/views/search_results/_search_result_remote.html.erb +13 -0
  81. data/app/views/search_results/_sidebar.html.erb +3 -3
  82. data/app/views/search_results/index.html.erb +4 -4
  83. data/app/views/search_results/index.iqrdf +7 -7
  84. data/app/views/search_results/sections/_datasets.html.erb +17 -0
  85. data/app/views/search_results/sections/_klass.html.erb +2 -2
  86. data/app/views/search_results/sections/_languages.html.erb +3 -3
  87. data/app/views/users/_sidebar.html.erb +1 -1
  88. data/config/application.rb +0 -2
  89. data/config/engine.rb +5 -0
  90. data/config/environments/heroku.rb +62 -16
  91. data/config/initializers/apipie.rb +17 -0
  92. data/config/initializers/secret_token.rb +25 -9
  93. data/config/locales/activerecord.de.yml +5 -0
  94. data/config/locales/activerecord.en.yml +5 -0
  95. data/config/locales/de.yml +14 -0
  96. data/config/locales/en.yml +14 -0
  97. data/config/locales/pt.yml +1 -0
  98. data/config/routes.rb +7 -4
  99. data/db/migrate/20131220134356_create_delayed_jobs.rb +22 -0
  100. data/db/migrate/20131220144601_create_imports.rb +11 -0
  101. data/db/schema.rb +26 -1
  102. data/iqvoc.gemspec +12 -3
  103. data/lib/iqvoc/ability.rb +2 -0
  104. data/lib/iqvoc/configuration/core.rb +36 -9
  105. data/lib/iqvoc/controller_extensions.rb +4 -0
  106. data/lib/iqvoc/environments/production.rb +1 -1
  107. data/lib/iqvoc/skos_importer.rb +31 -19
  108. data/lib/iqvoc/version.rb +1 -1
  109. data/lib/tasks/importer.rake +10 -2
  110. data/lib/tasks/release.rake +1 -1
  111. data/public/404.html +43 -11
  112. data/public/422.html +43 -11
  113. data/public/500.html +43 -12
  114. data/test/functional/{rdf_test.rb → rdf_rendering_test.rb} +1 -1
  115. data/test/integration/alphabetical_test.rb +5 -5
  116. data/test/integration/search_test.rb +16 -16
  117. data/test/unit/skos_import_test.rb +9 -9
  118. data/vendor/assets/images/animated-overlay.gif +0 -0
  119. data/vendor/assets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  120. data/vendor/assets/images/ui-bg_flat_55_fbec88_40x100.png +0 -0
  121. data/vendor/assets/images/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  122. data/vendor/assets/images/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  123. data/vendor/assets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  124. data/vendor/assets/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  125. data/vendor/assets/images/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  126. data/vendor/assets/images/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  127. data/vendor/assets/images/ui-icons_217bc0_256x240.png +0 -0
  128. data/vendor/assets/images/ui-icons_2e83ff_256x240.png +0 -0
  129. data/vendor/assets/images/ui-icons_469bdd_256x240.png +0 -0
  130. data/vendor/assets/images/ui-icons_6da8d5_256x240.png +0 -0
  131. data/vendor/assets/images/ui-icons_cd0a0a_256x240.png +0 -0
  132. data/vendor/assets/images/ui-icons_d8e7f3_256x240.png +0 -0
  133. data/vendor/assets/images/ui-icons_f9bd01_256x240.png +0 -0
  134. data/vendor/assets/javascripts/jquery-ui.custom.js +4538 -0
  135. data/vendor/assets/stylesheets/jquery-ui-1.10.3.custom.css.scss +724 -0
  136. metadata +214 -64
  137. data/app/assets/images/arrow_down.gif +0 -0
  138. data/app/assets/images/arrow_up.gif +0 -0
  139. data/app/assets/images/iqvoc_logo.png +0 -0
  140. data/app/assets/images/spinner_16x16.gif +0 -0
  141. data/app/assets/images/spinner_24x24.gif +0 -0
  142. data/app/assets/stylesheets/iqvoc/components.css.scss +0 -155
  143. data/app/assets/stylesheets/iqvoc/layout.css.scss +0 -0
  144. data/app/views/concepts/alphabetical/_pref_labeling.html.erb +0 -19
  145. data/app/views/import/import.html.erb +0 -7
  146. data/app/views/import/index.html.erb +0 -17
  147. data/vendor/assets/javascripts/jquery-ui-1.8.23.custom.js +0 -3399
  148. data/vendor/assets/stylesheets/jquery-ui-1.8.23.custom.css.scss +0 -405
data/public/500.html CHANGED
@@ -2,17 +2,48 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>We're sorry, but something went wrong (500)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
16
47
  </style>
17
48
  </head>
18
49
 
@@ -20,7 +51,7 @@
20
51
  <!-- This file lives in public/500.html -->
21
52
  <div class="dialog">
22
53
  <h1>We're sorry, but something went wrong.</h1>
23
- <p>We've been notified about this issue and we'll take a look at it shortly.</p>
24
54
  </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
25
56
  </body>
26
57
  </html>
@@ -16,7 +16,7 @@
16
16
 
17
17
  require File.join(File.expand_path(File.dirname(__FILE__)), '../test_helper')
18
18
 
19
- class RDFTest < ActionController::TestCase
19
+ class RdfRenderingTest < ActionController::TestCase
20
20
 
21
21
  setup do
22
22
  @controller = ConceptsController.new
@@ -33,19 +33,19 @@ class AlphabeticalConceptsTest < ActionDispatch::IntegrationTest
33
33
 
34
34
  test "showing only concepts with a pref label in respective language" do
35
35
  visit alphabetical_concepts_path(:lang => :en, :prefix => "x", :format => :html)
36
- concepts = page.all("ol.concepts li")
36
+ concepts = page.all(".concept-items .concept-item")
37
37
 
38
38
  assert_equal :en, I18n.locale
39
39
  assert_equal 2, concepts.length
40
- assert_equal "Xen1", concepts[0].find("p.term").text.strip
41
- assert_equal "Xen2", concepts[1].find("p.term").text.strip
40
+ assert_equal "Xen1", concepts[0].find(".concept-item-link").text.strip
41
+ assert_equal "Xen2", concepts[1].find(".concept-item-link").text.strip
42
42
 
43
43
  visit alphabetical_concepts_path(:lang => :de, :prefix => "x", :format => :html)
44
- concepts = page.all("ol.concepts li")
44
+ concepts = page.all(".concept-items .concept-item")
45
45
 
46
46
  assert_equal :de, I18n.locale
47
47
  assert_equal 1, concepts.length
48
- assert_equal "Xde1", concepts[0].find("p.term").text.strip
48
+ assert_equal "Xde1", concepts[0].find(".concept-item-link").text.strip
49
49
  end
50
50
 
51
51
  end
@@ -60,11 +60,11 @@ class SearchTest < ActionDispatch::IntegrationTest
60
60
 
61
61
  click_button("Search")
62
62
 
63
- assert page.has_css?("#search_results dt", :count => q[:amount]),
64
- "Page has #{page.all(:css, "#search_results dt").count} '#search_results dt' nodes. Should be #{q[:amount]}."
63
+ assert page.has_css?(".search-result", :count => q[:amount]),
64
+ "Page has #{page.all(:css, ".search-result").count} '.search-result' nodes. Should be #{q[:amount]}."
65
65
 
66
- within("#search_results dt") do
67
- assert page.has_content?(q[:result]), "Could not find '#{q[:result]}' within '#search_results dt'."
66
+ within(".search-result") do
67
+ assert page.has_content?(q[:result]), "Could not find '#{q[:result]}' within '.search-result'."
68
68
  end
69
69
  }
70
70
  end
@@ -76,15 +76,15 @@ class SearchTest < ActionDispatch::IntegrationTest
76
76
  find("#qt").select "contains"
77
77
  fill_in "Search term(s)", :with => "Alpha"
78
78
  click_button("Search")
79
- assert page.has_css?("#search_results dt", :count => 1)
79
+ assert page.has_css?(".search-result", :count => 1)
80
80
 
81
81
  choose "Concepts"
82
82
  click_button "Search"
83
- assert page.has_no_css?("#search_results dt")
83
+ assert page.has_no_css?(".search-result")
84
84
 
85
85
  choose "Collections"
86
86
  click_button "Search"
87
- assert page.has_css?("#search_results dt")
87
+ assert page.has_css?(".search-result")
88
88
  end
89
89
 
90
90
  test "searching within collections" do
@@ -102,8 +102,8 @@ class SearchTest < ActionDispatch::IntegrationTest
102
102
 
103
103
  click_button("Search")
104
104
 
105
- assert page.has_css?("#search_results dt", :count => 1)
106
- assert page.find("#search_results").has_content?("Forest")
105
+ assert page.has_css?(".search-result", :count => 1)
106
+ assert page.find(".search-results").has_content?("Forest")
107
107
 
108
108
  # TTL & RDF/XML
109
109
 
@@ -140,8 +140,8 @@ class SearchTest < ActionDispatch::IntegrationTest
140
140
 
141
141
  click_button("Search")
142
142
 
143
- assert page.has_css?("#search_results dt", :count => 1)
144
- assert page.find("#search_results").has_content?(concept.origin)
143
+ assert page.has_css?(".search-result", :count => 1)
144
+ assert page.find(".search-results").has_content?(concept.pref_label.to_s)
145
145
  end
146
146
 
147
147
  test "empty query with selected collection should return all collection members" do
@@ -159,9 +159,9 @@ class SearchTest < ActionDispatch::IntegrationTest
159
159
 
160
160
  click_button("Search")
161
161
 
162
- assert page.has_css?("#search_results dt", :count => 2)
163
- assert page.find("#search_results").has_content?("Tree")
164
- assert page.find("#search_results").has_content?("Forest")
162
+ assert page.has_css?(".search-result", :count => 2)
163
+ assert page.find(".search-results").has_content?("Tree")
164
+ assert page.find(".search-results").has_content?("Forest")
165
165
  end
166
166
 
167
167
  test "pagination" do
@@ -181,12 +181,12 @@ class SearchTest < ActionDispatch::IntegrationTest
181
181
 
182
182
  click_button("Search")
183
183
 
184
- assert page.has_css?("#search_results dt", :count => 5)
184
+ assert page.has_css?(".search-result", :count => 5)
185
185
  assert page.has_css?(".pagination .page", :count => 3)
186
186
 
187
187
  find(".pagination").all(".page").last.find("a").click
188
188
 
189
- assert page.has_css?("#search_results dt", :count => 2)
189
+ assert page.has_css?(".search-result", :count => 2)
190
190
 
191
191
  # TTL & RDF/XML
192
192
 
@@ -61,7 +61,7 @@ class SkosImportTest < ActiveSupport::TestCase
61
61
 
62
62
  test "basic_importer_functionality" do
63
63
  assert_difference('Concept::SKOS::Base.count', 4) do
64
- Iqvoc::SkosImporter.new(TEST_DATA, "http://www.example.com/")
64
+ Iqvoc::SkosImporter.new(TEST_DATA, "http://www.example.com/").run
65
65
  end
66
66
 
67
67
  concepts = {}
@@ -92,7 +92,7 @@ class SkosImportTest < ActiveSupport::TestCase
92
92
 
93
93
  test "incorrect origin" do
94
94
  assert_difference('Concept::SKOS::Base.count', 1) do
95
- Iqvoc::SkosImporter.new(["<http://www.example.com/1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2008/05/skos#Concept>."], "http://www.example.com/")
95
+ Iqvoc::SkosImporter.new(["<http://www.example.com/1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2008/05/skos#Concept>."], "http://www.example.com/").run
96
96
  end
97
97
  assert_nil Iqvoc::Concept.base_class.by_origin("1").last
98
98
  assert_not_nil Iqvoc::Concept.base_class.by_origin("_1").last
@@ -109,11 +109,11 @@ class SkosImportTest < ActiveSupport::TestCase
109
109
  ).split("\n")
110
110
 
111
111
  assert_difference('Note::SKOS::ChangeNote.count', 1) do
112
- Iqvoc::SkosImporter.new(test_data, "http://www.example.com/")
112
+ Iqvoc::SkosImporter.new(test_data, "http://www.example.com/").run
113
113
  end
114
114
 
115
115
  assert_difference('Note::Annotated::Base.count', 2) do
116
- Iqvoc::SkosImporter.new(test_data, "http://www.example.com/")
116
+ Iqvoc::SkosImporter.new(test_data, "http://www.example.com/").run
117
117
  end
118
118
  end
119
119
 
@@ -126,7 +126,7 @@ class SkosImportTest < ActiveSupport::TestCase
126
126
  ).split("\n")
127
127
 
128
128
  assert_difference('Notation::Base.count', 2) do
129
- Iqvoc::SkosImporter.new(test_data, "http://www.example.com/")
129
+ Iqvoc::SkosImporter.new(test_data, "http://www.example.com/").run
130
130
  end
131
131
  end
132
132
 
@@ -140,7 +140,7 @@ class SkosImportTest < ActiveSupport::TestCase
140
140
  ).split("\n")
141
141
 
142
142
  assert_difference('Concept::SKOS::Base.tops.count', 1) do
143
- Iqvoc::SkosImporter.new(test_data, "http://www.example.com/")
143
+ Iqvoc::SkosImporter.new(test_data, "http://www.example.com/").run
144
144
  end
145
145
  end
146
146
  end
@@ -178,7 +178,7 @@ class SkosCollectionImportTest < ActiveSupport::TestCase
178
178
 
179
179
  test "basic importer functionality" do
180
180
  assert_difference('Collection::Base.count', 2) do
181
- Iqvoc::SkosImporter.new(TEST_DATA, "http://www.example.com/")
181
+ Iqvoc::SkosImporter.new(TEST_DATA, "http://www.example.com/").run
182
182
  end
183
183
  concepts = {}
184
184
  ["cow", "donkey", "snake"].each do |origin|
@@ -203,7 +203,7 @@ class SkosCollectionImportTest < ActiveSupport::TestCase
203
203
 
204
204
  test "subcollections importer functionality" do
205
205
  assert_difference('Collection::Base.count', 2) do
206
- Iqvoc::SkosImporter.new(TEST_DATA, "http://www.example.com/")
206
+ Iqvoc::SkosImporter.new(TEST_DATA, "http://www.example.com/").run
207
207
  end
208
208
 
209
209
  collection_with_subcollections = Iqvoc::Collection.base_class.by_origin("land-animal").last
@@ -220,7 +220,7 @@ class SkosCollectionImportTest < ActiveSupport::TestCase
220
220
 
221
221
  assert_nothing_raised do
222
222
  assert_difference('Collection::Base.count', 1) do
223
- Iqvoc::SkosImporter.new(test_data, "http://www.example.com/")
223
+ Iqvoc::SkosImporter.new(test_data, "http://www.example.com/").run
224
224
  end
225
225
  end
226
226
  end
@@ -0,0 +1,4538 @@
1
+ /*! jQuery UI - v1.10.3 - 2013-11-25
2
+ * http://jqueryui.com
3
+ * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.position.js, jquery.ui.autocomplete.js, jquery.ui.datepicker.js, jquery.ui.menu.js
4
+ * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
5
+
6
+ (function( $, undefined ) {
7
+
8
+ var uuid = 0,
9
+ runiqueId = /^ui-id-\d+$/;
10
+
11
+ // $.ui might exist from components with no dependencies, e.g., $.ui.position
12
+ $.ui = $.ui || {};
13
+
14
+ $.extend( $.ui, {
15
+ version: "1.10.3",
16
+
17
+ keyCode: {
18
+ BACKSPACE: 8,
19
+ COMMA: 188,
20
+ DELETE: 46,
21
+ DOWN: 40,
22
+ END: 35,
23
+ ENTER: 13,
24
+ ESCAPE: 27,
25
+ HOME: 36,
26
+ LEFT: 37,
27
+ NUMPAD_ADD: 107,
28
+ NUMPAD_DECIMAL: 110,
29
+ NUMPAD_DIVIDE: 111,
30
+ NUMPAD_ENTER: 108,
31
+ NUMPAD_MULTIPLY: 106,
32
+ NUMPAD_SUBTRACT: 109,
33
+ PAGE_DOWN: 34,
34
+ PAGE_UP: 33,
35
+ PERIOD: 190,
36
+ RIGHT: 39,
37
+ SPACE: 32,
38
+ TAB: 9,
39
+ UP: 38
40
+ }
41
+ });
42
+
43
+ // plugins
44
+ $.fn.extend({
45
+ focus: (function( orig ) {
46
+ return function( delay, fn ) {
47
+ return typeof delay === "number" ?
48
+ this.each(function() {
49
+ var elem = this;
50
+ setTimeout(function() {
51
+ $( elem ).focus();
52
+ if ( fn ) {
53
+ fn.call( elem );
54
+ }
55
+ }, delay );
56
+ }) :
57
+ orig.apply( this, arguments );
58
+ };
59
+ })( $.fn.focus ),
60
+
61
+ scrollParent: function() {
62
+ var scrollParent;
63
+ if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
64
+ scrollParent = this.parents().filter(function() {
65
+ return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
66
+ }).eq(0);
67
+ } else {
68
+ scrollParent = this.parents().filter(function() {
69
+ return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
70
+ }).eq(0);
71
+ }
72
+
73
+ return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
74
+ },
75
+
76
+ zIndex: function( zIndex ) {
77
+ if ( zIndex !== undefined ) {
78
+ return this.css( "zIndex", zIndex );
79
+ }
80
+
81
+ if ( this.length ) {
82
+ var elem = $( this[ 0 ] ), position, value;
83
+ while ( elem.length && elem[ 0 ] !== document ) {
84
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
85
+ // This makes behavior of this function consistent across browsers
86
+ // WebKit always returns auto if the element is positioned
87
+ position = elem.css( "position" );
88
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
89
+ // IE returns 0 when zIndex is not specified
90
+ // other browsers return a string
91
+ // we ignore the case of nested elements with an explicit value of 0
92
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
93
+ value = parseInt( elem.css( "zIndex" ), 10 );
94
+ if ( !isNaN( value ) && value !== 0 ) {
95
+ return value;
96
+ }
97
+ }
98
+ elem = elem.parent();
99
+ }
100
+ }
101
+
102
+ return 0;
103
+ },
104
+
105
+ uniqueId: function() {
106
+ return this.each(function() {
107
+ if ( !this.id ) {
108
+ this.id = "ui-id-" + (++uuid);
109
+ }
110
+ });
111
+ },
112
+
113
+ removeUniqueId: function() {
114
+ return this.each(function() {
115
+ if ( runiqueId.test( this.id ) ) {
116
+ $( this ).removeAttr( "id" );
117
+ }
118
+ });
119
+ }
120
+ });
121
+
122
+ // selectors
123
+ function focusable( element, isTabIndexNotNaN ) {
124
+ var map, mapName, img,
125
+ nodeName = element.nodeName.toLowerCase();
126
+ if ( "area" === nodeName ) {
127
+ map = element.parentNode;
128
+ mapName = map.name;
129
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
130
+ return false;
131
+ }
132
+ img = $( "img[usemap=#" + mapName + "]" )[0];
133
+ return !!img && visible( img );
134
+ }
135
+ return ( /input|select|textarea|button|object/.test( nodeName ) ?
136
+ !element.disabled :
137
+ "a" === nodeName ?
138
+ element.href || isTabIndexNotNaN :
139
+ isTabIndexNotNaN) &&
140
+ // the element and all of its ancestors must be visible
141
+ visible( element );
142
+ }
143
+
144
+ function visible( element ) {
145
+ return $.expr.filters.visible( element ) &&
146
+ !$( element ).parents().addBack().filter(function() {
147
+ return $.css( this, "visibility" ) === "hidden";
148
+ }).length;
149
+ }
150
+
151
+ $.extend( $.expr[ ":" ], {
152
+ data: $.expr.createPseudo ?
153
+ $.expr.createPseudo(function( dataName ) {
154
+ return function( elem ) {
155
+ return !!$.data( elem, dataName );
156
+ };
157
+ }) :
158
+ // support: jQuery <1.8
159
+ function( elem, i, match ) {
160
+ return !!$.data( elem, match[ 3 ] );
161
+ },
162
+
163
+ focusable: function( element ) {
164
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
165
+ },
166
+
167
+ tabbable: function( element ) {
168
+ var tabIndex = $.attr( element, "tabindex" ),
169
+ isTabIndexNaN = isNaN( tabIndex );
170
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
171
+ }
172
+ });
173
+
174
+ // support: jQuery <1.8
175
+ if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
176
+ $.each( [ "Width", "Height" ], function( i, name ) {
177
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
178
+ type = name.toLowerCase(),
179
+ orig = {
180
+ innerWidth: $.fn.innerWidth,
181
+ innerHeight: $.fn.innerHeight,
182
+ outerWidth: $.fn.outerWidth,
183
+ outerHeight: $.fn.outerHeight
184
+ };
185
+
186
+ function reduce( elem, size, border, margin ) {
187
+ $.each( side, function() {
188
+ size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
189
+ if ( border ) {
190
+ size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
191
+ }
192
+ if ( margin ) {
193
+ size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
194
+ }
195
+ });
196
+ return size;
197
+ }
198
+
199
+ $.fn[ "inner" + name ] = function( size ) {
200
+ if ( size === undefined ) {
201
+ return orig[ "inner" + name ].call( this );
202
+ }
203
+
204
+ return this.each(function() {
205
+ $( this ).css( type, reduce( this, size ) + "px" );
206
+ });
207
+ };
208
+
209
+ $.fn[ "outer" + name] = function( size, margin ) {
210
+ if ( typeof size !== "number" ) {
211
+ return orig[ "outer" + name ].call( this, size );
212
+ }
213
+
214
+ return this.each(function() {
215
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
216
+ });
217
+ };
218
+ });
219
+ }
220
+
221
+ // support: jQuery <1.8
222
+ if ( !$.fn.addBack ) {
223
+ $.fn.addBack = function( selector ) {
224
+ return this.add( selector == null ?
225
+ this.prevObject : this.prevObject.filter( selector )
226
+ );
227
+ };
228
+ }
229
+
230
+ // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
231
+ if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
232
+ $.fn.removeData = (function( removeData ) {
233
+ return function( key ) {
234
+ if ( arguments.length ) {
235
+ return removeData.call( this, $.camelCase( key ) );
236
+ } else {
237
+ return removeData.call( this );
238
+ }
239
+ };
240
+ })( $.fn.removeData );
241
+ }
242
+
243
+
244
+
245
+
246
+
247
+ // deprecated
248
+ $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
249
+
250
+ $.support.selectstart = "onselectstart" in document.createElement( "div" );
251
+ $.fn.extend({
252
+ disableSelection: function() {
253
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
254
+ ".ui-disableSelection", function( event ) {
255
+ event.preventDefault();
256
+ });
257
+ },
258
+
259
+ enableSelection: function() {
260
+ return this.unbind( ".ui-disableSelection" );
261
+ }
262
+ });
263
+
264
+ $.extend( $.ui, {
265
+ // $.ui.plugin is deprecated. Use $.widget() extensions instead.
266
+ plugin: {
267
+ add: function( module, option, set ) {
268
+ var i,
269
+ proto = $.ui[ module ].prototype;
270
+ for ( i in set ) {
271
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
272
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
273
+ }
274
+ },
275
+ call: function( instance, name, args ) {
276
+ var i,
277
+ set = instance.plugins[ name ];
278
+ if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
279
+ return;
280
+ }
281
+
282
+ for ( i = 0; i < set.length; i++ ) {
283
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
284
+ set[ i ][ 1 ].apply( instance.element, args );
285
+ }
286
+ }
287
+ }
288
+ },
289
+
290
+ // only used by resizable
291
+ hasScroll: function( el, a ) {
292
+
293
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
294
+ if ( $( el ).css( "overflow" ) === "hidden") {
295
+ return false;
296
+ }
297
+
298
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
299
+ has = false;
300
+
301
+ if ( el[ scroll ] > 0 ) {
302
+ return true;
303
+ }
304
+
305
+ // TODO: determine which cases actually cause this to happen
306
+ // if the element doesn't have the scroll set, see if it's possible to
307
+ // set the scroll
308
+ el[ scroll ] = 1;
309
+ has = ( el[ scroll ] > 0 );
310
+ el[ scroll ] = 0;
311
+ return has;
312
+ }
313
+ });
314
+
315
+ })( jQuery );
316
+ (function( $, undefined ) {
317
+
318
+ var uuid = 0,
319
+ slice = Array.prototype.slice,
320
+ _cleanData = $.cleanData;
321
+ $.cleanData = function( elems ) {
322
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
323
+ try {
324
+ $( elem ).triggerHandler( "remove" );
325
+ // http://bugs.jquery.com/ticket/8235
326
+ } catch( e ) {}
327
+ }
328
+ _cleanData( elems );
329
+ };
330
+
331
+ $.widget = function( name, base, prototype ) {
332
+ var fullName, existingConstructor, constructor, basePrototype,
333
+ // proxiedPrototype allows the provided prototype to remain unmodified
334
+ // so that it can be used as a mixin for multiple widgets (#8876)
335
+ proxiedPrototype = {},
336
+ namespace = name.split( "." )[ 0 ];
337
+
338
+ name = name.split( "." )[ 1 ];
339
+ fullName = namespace + "-" + name;
340
+
341
+ if ( !prototype ) {
342
+ prototype = base;
343
+ base = $.Widget;
344
+ }
345
+
346
+ // create selector for plugin
347
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
348
+ return !!$.data( elem, fullName );
349
+ };
350
+
351
+ $[ namespace ] = $[ namespace ] || {};
352
+ existingConstructor = $[ namespace ][ name ];
353
+ constructor = $[ namespace ][ name ] = function( options, element ) {
354
+ // allow instantiation without "new" keyword
355
+ if ( !this._createWidget ) {
356
+ return new constructor( options, element );
357
+ }
358
+
359
+ // allow instantiation without initializing for simple inheritance
360
+ // must use "new" keyword (the code above always passes args)
361
+ if ( arguments.length ) {
362
+ this._createWidget( options, element );
363
+ }
364
+ };
365
+ // extend with the existing constructor to carry over any static properties
366
+ $.extend( constructor, existingConstructor, {
367
+ version: prototype.version,
368
+ // copy the object used to create the prototype in case we need to
369
+ // redefine the widget later
370
+ _proto: $.extend( {}, prototype ),
371
+ // track widgets that inherit from this widget in case this widget is
372
+ // redefined after a widget inherits from it
373
+ _childConstructors: []
374
+ });
375
+
376
+ basePrototype = new base();
377
+ // we need to make the options hash a property directly on the new instance
378
+ // otherwise we'll modify the options hash on the prototype that we're
379
+ // inheriting from
380
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
381
+ $.each( prototype, function( prop, value ) {
382
+ if ( !$.isFunction( value ) ) {
383
+ proxiedPrototype[ prop ] = value;
384
+ return;
385
+ }
386
+ proxiedPrototype[ prop ] = (function() {
387
+ var _super = function() {
388
+ return base.prototype[ prop ].apply( this, arguments );
389
+ },
390
+ _superApply = function( args ) {
391
+ return base.prototype[ prop ].apply( this, args );
392
+ };
393
+ return function() {
394
+ var __super = this._super,
395
+ __superApply = this._superApply,
396
+ returnValue;
397
+
398
+ this._super = _super;
399
+ this._superApply = _superApply;
400
+
401
+ returnValue = value.apply( this, arguments );
402
+
403
+ this._super = __super;
404
+ this._superApply = __superApply;
405
+
406
+ return returnValue;
407
+ };
408
+ })();
409
+ });
410
+ constructor.prototype = $.widget.extend( basePrototype, {
411
+ // TODO: remove support for widgetEventPrefix
412
+ // always use the name + a colon as the prefix, e.g., draggable:start
413
+ // don't prefix for widgets that aren't DOM-based
414
+ widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
415
+ }, proxiedPrototype, {
416
+ constructor: constructor,
417
+ namespace: namespace,
418
+ widgetName: name,
419
+ widgetFullName: fullName
420
+ });
421
+
422
+ // If this widget is being redefined then we need to find all widgets that
423
+ // are inheriting from it and redefine all of them so that they inherit from
424
+ // the new version of this widget. We're essentially trying to replace one
425
+ // level in the prototype chain.
426
+ if ( existingConstructor ) {
427
+ $.each( existingConstructor._childConstructors, function( i, child ) {
428
+ var childPrototype = child.prototype;
429
+
430
+ // redefine the child widget using the same prototype that was
431
+ // originally used, but inherit from the new version of the base
432
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
433
+ });
434
+ // remove the list of existing child constructors from the old constructor
435
+ // so the old child constructors can be garbage collected
436
+ delete existingConstructor._childConstructors;
437
+ } else {
438
+ base._childConstructors.push( constructor );
439
+ }
440
+
441
+ $.widget.bridge( name, constructor );
442
+ };
443
+
444
+ $.widget.extend = function( target ) {
445
+ var input = slice.call( arguments, 1 ),
446
+ inputIndex = 0,
447
+ inputLength = input.length,
448
+ key,
449
+ value;
450
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
451
+ for ( key in input[ inputIndex ] ) {
452
+ value = input[ inputIndex ][ key ];
453
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
454
+ // Clone objects
455
+ if ( $.isPlainObject( value ) ) {
456
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
457
+ $.widget.extend( {}, target[ key ], value ) :
458
+ // Don't extend strings, arrays, etc. with objects
459
+ $.widget.extend( {}, value );
460
+ // Copy everything else by reference
461
+ } else {
462
+ target[ key ] = value;
463
+ }
464
+ }
465
+ }
466
+ }
467
+ return target;
468
+ };
469
+
470
+ $.widget.bridge = function( name, object ) {
471
+ var fullName = object.prototype.widgetFullName || name;
472
+ $.fn[ name ] = function( options ) {
473
+ var isMethodCall = typeof options === "string",
474
+ args = slice.call( arguments, 1 ),
475
+ returnValue = this;
476
+
477
+ // allow multiple hashes to be passed on init
478
+ options = !isMethodCall && args.length ?
479
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
480
+ options;
481
+
482
+ if ( isMethodCall ) {
483
+ this.each(function() {
484
+ var methodValue,
485
+ instance = $.data( this, fullName );
486
+ if ( !instance ) {
487
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
488
+ "attempted to call method '" + options + "'" );
489
+ }
490
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
491
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
492
+ }
493
+ methodValue = instance[ options ].apply( instance, args );
494
+ if ( methodValue !== instance && methodValue !== undefined ) {
495
+ returnValue = methodValue && methodValue.jquery ?
496
+ returnValue.pushStack( methodValue.get() ) :
497
+ methodValue;
498
+ return false;
499
+ }
500
+ });
501
+ } else {
502
+ this.each(function() {
503
+ var instance = $.data( this, fullName );
504
+ if ( instance ) {
505
+ instance.option( options || {} )._init();
506
+ } else {
507
+ $.data( this, fullName, new object( options, this ) );
508
+ }
509
+ });
510
+ }
511
+
512
+ return returnValue;
513
+ };
514
+ };
515
+
516
+ $.Widget = function( /* options, element */ ) {};
517
+ $.Widget._childConstructors = [];
518
+
519
+ $.Widget.prototype = {
520
+ widgetName: "widget",
521
+ widgetEventPrefix: "",
522
+ defaultElement: "<div>",
523
+ options: {
524
+ disabled: false,
525
+
526
+ // callbacks
527
+ create: null
528
+ },
529
+ _createWidget: function( options, element ) {
530
+ element = $( element || this.defaultElement || this )[ 0 ];
531
+ this.element = $( element );
532
+ this.uuid = uuid++;
533
+ this.eventNamespace = "." + this.widgetName + this.uuid;
534
+ this.options = $.widget.extend( {},
535
+ this.options,
536
+ this._getCreateOptions(),
537
+ options );
538
+
539
+ this.bindings = $();
540
+ this.hoverable = $();
541
+ this.focusable = $();
542
+
543
+ if ( element !== this ) {
544
+ $.data( element, this.widgetFullName, this );
545
+ this._on( true, this.element, {
546
+ remove: function( event ) {
547
+ if ( event.target === element ) {
548
+ this.destroy();
549
+ }
550
+ }
551
+ });
552
+ this.document = $( element.style ?
553
+ // element within the document
554
+ element.ownerDocument :
555
+ // element is window or document
556
+ element.document || element );
557
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
558
+ }
559
+
560
+ this._create();
561
+ this._trigger( "create", null, this._getCreateEventData() );
562
+ this._init();
563
+ },
564
+ _getCreateOptions: $.noop,
565
+ _getCreateEventData: $.noop,
566
+ _create: $.noop,
567
+ _init: $.noop,
568
+
569
+ destroy: function() {
570
+ this._destroy();
571
+ // we can probably remove the unbind calls in 2.0
572
+ // all event bindings should go through this._on()
573
+ this.element
574
+ .unbind( this.eventNamespace )
575
+ // 1.9 BC for #7810
576
+ // TODO remove dual storage
577
+ .removeData( this.widgetName )
578
+ .removeData( this.widgetFullName )
579
+ // support: jquery <1.6.3
580
+ // http://bugs.jquery.com/ticket/9413
581
+ .removeData( $.camelCase( this.widgetFullName ) );
582
+ this.widget()
583
+ .unbind( this.eventNamespace )
584
+ .removeAttr( "aria-disabled" )
585
+ .removeClass(
586
+ this.widgetFullName + "-disabled " +
587
+ "ui-state-disabled" );
588
+
589
+ // clean up events and states
590
+ this.bindings.unbind( this.eventNamespace );
591
+ this.hoverable.removeClass( "ui-state-hover" );
592
+ this.focusable.removeClass( "ui-state-focus" );
593
+ },
594
+ _destroy: $.noop,
595
+
596
+ widget: function() {
597
+ return this.element;
598
+ },
599
+
600
+ option: function( key, value ) {
601
+ var options = key,
602
+ parts,
603
+ curOption,
604
+ i;
605
+
606
+ if ( arguments.length === 0 ) {
607
+ // don't return a reference to the internal hash
608
+ return $.widget.extend( {}, this.options );
609
+ }
610
+
611
+ if ( typeof key === "string" ) {
612
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
613
+ options = {};
614
+ parts = key.split( "." );
615
+ key = parts.shift();
616
+ if ( parts.length ) {
617
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
618
+ for ( i = 0; i < parts.length - 1; i++ ) {
619
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
620
+ curOption = curOption[ parts[ i ] ];
621
+ }
622
+ key = parts.pop();
623
+ if ( value === undefined ) {
624
+ return curOption[ key ] === undefined ? null : curOption[ key ];
625
+ }
626
+ curOption[ key ] = value;
627
+ } else {
628
+ if ( value === undefined ) {
629
+ return this.options[ key ] === undefined ? null : this.options[ key ];
630
+ }
631
+ options[ key ] = value;
632
+ }
633
+ }
634
+
635
+ this._setOptions( options );
636
+
637
+ return this;
638
+ },
639
+ _setOptions: function( options ) {
640
+ var key;
641
+
642
+ for ( key in options ) {
643
+ this._setOption( key, options[ key ] );
644
+ }
645
+
646
+ return this;
647
+ },
648
+ _setOption: function( key, value ) {
649
+ this.options[ key ] = value;
650
+
651
+ if ( key === "disabled" ) {
652
+ this.widget()
653
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
654
+ .attr( "aria-disabled", value );
655
+ this.hoverable.removeClass( "ui-state-hover" );
656
+ this.focusable.removeClass( "ui-state-focus" );
657
+ }
658
+
659
+ return this;
660
+ },
661
+
662
+ enable: function() {
663
+ return this._setOption( "disabled", false );
664
+ },
665
+ disable: function() {
666
+ return this._setOption( "disabled", true );
667
+ },
668
+
669
+ _on: function( suppressDisabledCheck, element, handlers ) {
670
+ var delegateElement,
671
+ instance = this;
672
+
673
+ // no suppressDisabledCheck flag, shuffle arguments
674
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
675
+ handlers = element;
676
+ element = suppressDisabledCheck;
677
+ suppressDisabledCheck = false;
678
+ }
679
+
680
+ // no element argument, shuffle and use this.element
681
+ if ( !handlers ) {
682
+ handlers = element;
683
+ element = this.element;
684
+ delegateElement = this.widget();
685
+ } else {
686
+ // accept selectors, DOM elements
687
+ element = delegateElement = $( element );
688
+ this.bindings = this.bindings.add( element );
689
+ }
690
+
691
+ $.each( handlers, function( event, handler ) {
692
+ function handlerProxy() {
693
+ // allow widgets to customize the disabled handling
694
+ // - disabled as an array instead of boolean
695
+ // - disabled class as method for disabling individual parts
696
+ if ( !suppressDisabledCheck &&
697
+ ( instance.options.disabled === true ||
698
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
699
+ return;
700
+ }
701
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
702
+ .apply( instance, arguments );
703
+ }
704
+
705
+ // copy the guid so direct unbinding works
706
+ if ( typeof handler !== "string" ) {
707
+ handlerProxy.guid = handler.guid =
708
+ handler.guid || handlerProxy.guid || $.guid++;
709
+ }
710
+
711
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
712
+ eventName = match[1] + instance.eventNamespace,
713
+ selector = match[2];
714
+ if ( selector ) {
715
+ delegateElement.delegate( selector, eventName, handlerProxy );
716
+ } else {
717
+ element.bind( eventName, handlerProxy );
718
+ }
719
+ });
720
+ },
721
+
722
+ _off: function( element, eventName ) {
723
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
724
+ element.unbind( eventName ).undelegate( eventName );
725
+ },
726
+
727
+ _delay: function( handler, delay ) {
728
+ function handlerProxy() {
729
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
730
+ .apply( instance, arguments );
731
+ }
732
+ var instance = this;
733
+ return setTimeout( handlerProxy, delay || 0 );
734
+ },
735
+
736
+ _hoverable: function( element ) {
737
+ this.hoverable = this.hoverable.add( element );
738
+ this._on( element, {
739
+ mouseenter: function( event ) {
740
+ $( event.currentTarget ).addClass( "ui-state-hover" );
741
+ },
742
+ mouseleave: function( event ) {
743
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
744
+ }
745
+ });
746
+ },
747
+
748
+ _focusable: function( element ) {
749
+ this.focusable = this.focusable.add( element );
750
+ this._on( element, {
751
+ focusin: function( event ) {
752
+ $( event.currentTarget ).addClass( "ui-state-focus" );
753
+ },
754
+ focusout: function( event ) {
755
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
756
+ }
757
+ });
758
+ },
759
+
760
+ _trigger: function( type, event, data ) {
761
+ var prop, orig,
762
+ callback = this.options[ type ];
763
+
764
+ data = data || {};
765
+ event = $.Event( event );
766
+ event.type = ( type === this.widgetEventPrefix ?
767
+ type :
768
+ this.widgetEventPrefix + type ).toLowerCase();
769
+ // the original event may come from any element
770
+ // so we need to reset the target on the new event
771
+ event.target = this.element[ 0 ];
772
+
773
+ // copy original event properties over to the new event
774
+ orig = event.originalEvent;
775
+ if ( orig ) {
776
+ for ( prop in orig ) {
777
+ if ( !( prop in event ) ) {
778
+ event[ prop ] = orig[ prop ];
779
+ }
780
+ }
781
+ }
782
+
783
+ this.element.trigger( event, data );
784
+ return !( $.isFunction( callback ) &&
785
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
786
+ event.isDefaultPrevented() );
787
+ }
788
+ };
789
+
790
+ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
791
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
792
+ if ( typeof options === "string" ) {
793
+ options = { effect: options };
794
+ }
795
+ var hasOptions,
796
+ effectName = !options ?
797
+ method :
798
+ options === true || typeof options === "number" ?
799
+ defaultEffect :
800
+ options.effect || defaultEffect;
801
+ options = options || {};
802
+ if ( typeof options === "number" ) {
803
+ options = { duration: options };
804
+ }
805
+ hasOptions = !$.isEmptyObject( options );
806
+ options.complete = callback;
807
+ if ( options.delay ) {
808
+ element.delay( options.delay );
809
+ }
810
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
811
+ element[ method ]( options );
812
+ } else if ( effectName !== method && element[ effectName ] ) {
813
+ element[ effectName ]( options.duration, options.easing, callback );
814
+ } else {
815
+ element.queue(function( next ) {
816
+ $( this )[ method ]();
817
+ if ( callback ) {
818
+ callback.call( element[ 0 ] );
819
+ }
820
+ next();
821
+ });
822
+ }
823
+ };
824
+ });
825
+
826
+ })( jQuery );
827
+ (function( $, undefined ) {
828
+
829
+ $.ui = $.ui || {};
830
+
831
+ var cachedScrollbarWidth,
832
+ max = Math.max,
833
+ abs = Math.abs,
834
+ round = Math.round,
835
+ rhorizontal = /left|center|right/,
836
+ rvertical = /top|center|bottom/,
837
+ roffset = /[\+\-]\d+(\.[\d]+)?%?/,
838
+ rposition = /^\w+/,
839
+ rpercent = /%$/,
840
+ _position = $.fn.position;
841
+
842
+ function getOffsets( offsets, width, height ) {
843
+ return [
844
+ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
845
+ parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
846
+ ];
847
+ }
848
+
849
+ function parseCss( element, property ) {
850
+ return parseInt( $.css( element, property ), 10 ) || 0;
851
+ }
852
+
853
+ function getDimensions( elem ) {
854
+ var raw = elem[0];
855
+ if ( raw.nodeType === 9 ) {
856
+ return {
857
+ width: elem.width(),
858
+ height: elem.height(),
859
+ offset: { top: 0, left: 0 }
860
+ };
861
+ }
862
+ if ( $.isWindow( raw ) ) {
863
+ return {
864
+ width: elem.width(),
865
+ height: elem.height(),
866
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
867
+ };
868
+ }
869
+ if ( raw.preventDefault ) {
870
+ return {
871
+ width: 0,
872
+ height: 0,
873
+ offset: { top: raw.pageY, left: raw.pageX }
874
+ };
875
+ }
876
+ return {
877
+ width: elem.outerWidth(),
878
+ height: elem.outerHeight(),
879
+ offset: elem.offset()
880
+ };
881
+ }
882
+
883
+ $.position = {
884
+ scrollbarWidth: function() {
885
+ if ( cachedScrollbarWidth !== undefined ) {
886
+ return cachedScrollbarWidth;
887
+ }
888
+ var w1, w2,
889
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
890
+ innerDiv = div.children()[0];
891
+
892
+ $( "body" ).append( div );
893
+ w1 = innerDiv.offsetWidth;
894
+ div.css( "overflow", "scroll" );
895
+
896
+ w2 = innerDiv.offsetWidth;
897
+
898
+ if ( w1 === w2 ) {
899
+ w2 = div[0].clientWidth;
900
+ }
901
+
902
+ div.remove();
903
+
904
+ return (cachedScrollbarWidth = w1 - w2);
905
+ },
906
+ getScrollInfo: function( within ) {
907
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
908
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
909
+ hasOverflowX = overflowX === "scroll" ||
910
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
911
+ hasOverflowY = overflowY === "scroll" ||
912
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
913
+ return {
914
+ width: hasOverflowY ? $.position.scrollbarWidth() : 0,
915
+ height: hasOverflowX ? $.position.scrollbarWidth() : 0
916
+ };
917
+ },
918
+ getWithinInfo: function( element ) {
919
+ var withinElement = $( element || window ),
920
+ isWindow = $.isWindow( withinElement[0] );
921
+ return {
922
+ element: withinElement,
923
+ isWindow: isWindow,
924
+ offset: withinElement.offset() || { left: 0, top: 0 },
925
+ scrollLeft: withinElement.scrollLeft(),
926
+ scrollTop: withinElement.scrollTop(),
927
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
928
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
929
+ };
930
+ }
931
+ };
932
+
933
+ $.fn.position = function( options ) {
934
+ if ( !options || !options.of ) {
935
+ return _position.apply( this, arguments );
936
+ }
937
+
938
+ // make a copy, we don't want to modify arguments
939
+ options = $.extend( {}, options );
940
+
941
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
942
+ target = $( options.of ),
943
+ within = $.position.getWithinInfo( options.within ),
944
+ scrollInfo = $.position.getScrollInfo( within ),
945
+ collision = ( options.collision || "flip" ).split( " " ),
946
+ offsets = {};
947
+
948
+ dimensions = getDimensions( target );
949
+ if ( target[0].preventDefault ) {
950
+ // force left top to allow flipping
951
+ options.at = "left top";
952
+ }
953
+ targetWidth = dimensions.width;
954
+ targetHeight = dimensions.height;
955
+ targetOffset = dimensions.offset;
956
+ // clone to reuse original targetOffset later
957
+ basePosition = $.extend( {}, targetOffset );
958
+
959
+ // force my and at to have valid horizontal and vertical positions
960
+ // if a value is missing or invalid, it will be converted to center
961
+ $.each( [ "my", "at" ], function() {
962
+ var pos = ( options[ this ] || "" ).split( " " ),
963
+ horizontalOffset,
964
+ verticalOffset;
965
+
966
+ if ( pos.length === 1) {
967
+ pos = rhorizontal.test( pos[ 0 ] ) ?
968
+ pos.concat( [ "center" ] ) :
969
+ rvertical.test( pos[ 0 ] ) ?
970
+ [ "center" ].concat( pos ) :
971
+ [ "center", "center" ];
972
+ }
973
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
974
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
975
+
976
+ // calculate offsets
977
+ horizontalOffset = roffset.exec( pos[ 0 ] );
978
+ verticalOffset = roffset.exec( pos[ 1 ] );
979
+ offsets[ this ] = [
980
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
981
+ verticalOffset ? verticalOffset[ 0 ] : 0
982
+ ];
983
+
984
+ // reduce to just the positions without the offsets
985
+ options[ this ] = [
986
+ rposition.exec( pos[ 0 ] )[ 0 ],
987
+ rposition.exec( pos[ 1 ] )[ 0 ]
988
+ ];
989
+ });
990
+
991
+ // normalize collision option
992
+ if ( collision.length === 1 ) {
993
+ collision[ 1 ] = collision[ 0 ];
994
+ }
995
+
996
+ if ( options.at[ 0 ] === "right" ) {
997
+ basePosition.left += targetWidth;
998
+ } else if ( options.at[ 0 ] === "center" ) {
999
+ basePosition.left += targetWidth / 2;
1000
+ }
1001
+
1002
+ if ( options.at[ 1 ] === "bottom" ) {
1003
+ basePosition.top += targetHeight;
1004
+ } else if ( options.at[ 1 ] === "center" ) {
1005
+ basePosition.top += targetHeight / 2;
1006
+ }
1007
+
1008
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1009
+ basePosition.left += atOffset[ 0 ];
1010
+ basePosition.top += atOffset[ 1 ];
1011
+
1012
+ return this.each(function() {
1013
+ var collisionPosition, using,
1014
+ elem = $( this ),
1015
+ elemWidth = elem.outerWidth(),
1016
+ elemHeight = elem.outerHeight(),
1017
+ marginLeft = parseCss( this, "marginLeft" ),
1018
+ marginTop = parseCss( this, "marginTop" ),
1019
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1020
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1021
+ position = $.extend( {}, basePosition ),
1022
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1023
+
1024
+ if ( options.my[ 0 ] === "right" ) {
1025
+ position.left -= elemWidth;
1026
+ } else if ( options.my[ 0 ] === "center" ) {
1027
+ position.left -= elemWidth / 2;
1028
+ }
1029
+
1030
+ if ( options.my[ 1 ] === "bottom" ) {
1031
+ position.top -= elemHeight;
1032
+ } else if ( options.my[ 1 ] === "center" ) {
1033
+ position.top -= elemHeight / 2;
1034
+ }
1035
+
1036
+ position.left += myOffset[ 0 ];
1037
+ position.top += myOffset[ 1 ];
1038
+
1039
+ // if the browser doesn't support fractions, then round for consistent results
1040
+ if ( !$.support.offsetFractions ) {
1041
+ position.left = round( position.left );
1042
+ position.top = round( position.top );
1043
+ }
1044
+
1045
+ collisionPosition = {
1046
+ marginLeft: marginLeft,
1047
+ marginTop: marginTop
1048
+ };
1049
+
1050
+ $.each( [ "left", "top" ], function( i, dir ) {
1051
+ if ( $.ui.position[ collision[ i ] ] ) {
1052
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
1053
+ targetWidth: targetWidth,
1054
+ targetHeight: targetHeight,
1055
+ elemWidth: elemWidth,
1056
+ elemHeight: elemHeight,
1057
+ collisionPosition: collisionPosition,
1058
+ collisionWidth: collisionWidth,
1059
+ collisionHeight: collisionHeight,
1060
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1061
+ my: options.my,
1062
+ at: options.at,
1063
+ within: within,
1064
+ elem : elem
1065
+ });
1066
+ }
1067
+ });
1068
+
1069
+ if ( options.using ) {
1070
+ // adds feedback as second argument to using callback, if present
1071
+ using = function( props ) {
1072
+ var left = targetOffset.left - position.left,
1073
+ right = left + targetWidth - elemWidth,
1074
+ top = targetOffset.top - position.top,
1075
+ bottom = top + targetHeight - elemHeight,
1076
+ feedback = {
1077
+ target: {
1078
+ element: target,
1079
+ left: targetOffset.left,
1080
+ top: targetOffset.top,
1081
+ width: targetWidth,
1082
+ height: targetHeight
1083
+ },
1084
+ element: {
1085
+ element: elem,
1086
+ left: position.left,
1087
+ top: position.top,
1088
+ width: elemWidth,
1089
+ height: elemHeight
1090
+ },
1091
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1092
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1093
+ };
1094
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1095
+ feedback.horizontal = "center";
1096
+ }
1097
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1098
+ feedback.vertical = "middle";
1099
+ }
1100
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1101
+ feedback.important = "horizontal";
1102
+ } else {
1103
+ feedback.important = "vertical";
1104
+ }
1105
+ options.using.call( this, props, feedback );
1106
+ };
1107
+ }
1108
+
1109
+ elem.offset( $.extend( position, { using: using } ) );
1110
+ });
1111
+ };
1112
+
1113
+ $.ui.position = {
1114
+ fit: {
1115
+ left: function( position, data ) {
1116
+ var within = data.within,
1117
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1118
+ outerWidth = within.width,
1119
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1120
+ overLeft = withinOffset - collisionPosLeft,
1121
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1122
+ newOverRight;
1123
+
1124
+ // element is wider than within
1125
+ if ( data.collisionWidth > outerWidth ) {
1126
+ // element is initially over the left side of within
1127
+ if ( overLeft > 0 && overRight <= 0 ) {
1128
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1129
+ position.left += overLeft - newOverRight;
1130
+ // element is initially over right side of within
1131
+ } else if ( overRight > 0 && overLeft <= 0 ) {
1132
+ position.left = withinOffset;
1133
+ // element is initially over both left and right sides of within
1134
+ } else {
1135
+ if ( overLeft > overRight ) {
1136
+ position.left = withinOffset + outerWidth - data.collisionWidth;
1137
+ } else {
1138
+ position.left = withinOffset;
1139
+ }
1140
+ }
1141
+ // too far left -> align with left edge
1142
+ } else if ( overLeft > 0 ) {
1143
+ position.left += overLeft;
1144
+ // too far right -> align with right edge
1145
+ } else if ( overRight > 0 ) {
1146
+ position.left -= overRight;
1147
+ // adjust based on position and margin
1148
+ } else {
1149
+ position.left = max( position.left - collisionPosLeft, position.left );
1150
+ }
1151
+ },
1152
+ top: function( position, data ) {
1153
+ var within = data.within,
1154
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1155
+ outerHeight = data.within.height,
1156
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
1157
+ overTop = withinOffset - collisionPosTop,
1158
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1159
+ newOverBottom;
1160
+
1161
+ // element is taller than within
1162
+ if ( data.collisionHeight > outerHeight ) {
1163
+ // element is initially over the top of within
1164
+ if ( overTop > 0 && overBottom <= 0 ) {
1165
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1166
+ position.top += overTop - newOverBottom;
1167
+ // element is initially over bottom of within
1168
+ } else if ( overBottom > 0 && overTop <= 0 ) {
1169
+ position.top = withinOffset;
1170
+ // element is initially over both top and bottom of within
1171
+ } else {
1172
+ if ( overTop > overBottom ) {
1173
+ position.top = withinOffset + outerHeight - data.collisionHeight;
1174
+ } else {
1175
+ position.top = withinOffset;
1176
+ }
1177
+ }
1178
+ // too far up -> align with top
1179
+ } else if ( overTop > 0 ) {
1180
+ position.top += overTop;
1181
+ // too far down -> align with bottom edge
1182
+ } else if ( overBottom > 0 ) {
1183
+ position.top -= overBottom;
1184
+ // adjust based on position and margin
1185
+ } else {
1186
+ position.top = max( position.top - collisionPosTop, position.top );
1187
+ }
1188
+ }
1189
+ },
1190
+ flip: {
1191
+ left: function( position, data ) {
1192
+ var within = data.within,
1193
+ withinOffset = within.offset.left + within.scrollLeft,
1194
+ outerWidth = within.width,
1195
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1196
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1197
+ overLeft = collisionPosLeft - offsetLeft,
1198
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1199
+ myOffset = data.my[ 0 ] === "left" ?
1200
+ -data.elemWidth :
1201
+ data.my[ 0 ] === "right" ?
1202
+ data.elemWidth :
1203
+ 0,
1204
+ atOffset = data.at[ 0 ] === "left" ?
1205
+ data.targetWidth :
1206
+ data.at[ 0 ] === "right" ?
1207
+ -data.targetWidth :
1208
+ 0,
1209
+ offset = -2 * data.offset[ 0 ],
1210
+ newOverRight,
1211
+ newOverLeft;
1212
+
1213
+ if ( overLeft < 0 ) {
1214
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1215
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1216
+ position.left += myOffset + atOffset + offset;
1217
+ }
1218
+ }
1219
+ else if ( overRight > 0 ) {
1220
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1221
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1222
+ position.left += myOffset + atOffset + offset;
1223
+ }
1224
+ }
1225
+ },
1226
+ top: function( position, data ) {
1227
+ var within = data.within,
1228
+ withinOffset = within.offset.top + within.scrollTop,
1229
+ outerHeight = within.height,
1230
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1231
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
1232
+ overTop = collisionPosTop - offsetTop,
1233
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1234
+ top = data.my[ 1 ] === "top",
1235
+ myOffset = top ?
1236
+ -data.elemHeight :
1237
+ data.my[ 1 ] === "bottom" ?
1238
+ data.elemHeight :
1239
+ 0,
1240
+ atOffset = data.at[ 1 ] === "top" ?
1241
+ data.targetHeight :
1242
+ data.at[ 1 ] === "bottom" ?
1243
+ -data.targetHeight :
1244
+ 0,
1245
+ offset = -2 * data.offset[ 1 ],
1246
+ newOverTop,
1247
+ newOverBottom;
1248
+ if ( overTop < 0 ) {
1249
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1250
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1251
+ position.top += myOffset + atOffset + offset;
1252
+ }
1253
+ }
1254
+ else if ( overBottom > 0 ) {
1255
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1256
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1257
+ position.top += myOffset + atOffset + offset;
1258
+ }
1259
+ }
1260
+ }
1261
+ },
1262
+ flipfit: {
1263
+ left: function() {
1264
+ $.ui.position.flip.left.apply( this, arguments );
1265
+ $.ui.position.fit.left.apply( this, arguments );
1266
+ },
1267
+ top: function() {
1268
+ $.ui.position.flip.top.apply( this, arguments );
1269
+ $.ui.position.fit.top.apply( this, arguments );
1270
+ }
1271
+ }
1272
+ };
1273
+
1274
+ // fraction support test
1275
+ (function () {
1276
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
1277
+ body = document.getElementsByTagName( "body" )[ 0 ],
1278
+ div = document.createElement( "div" );
1279
+
1280
+ //Create a "fake body" for testing based on method used in jQuery.support
1281
+ testElement = document.createElement( body ? "div" : "body" );
1282
+ testElementStyle = {
1283
+ visibility: "hidden",
1284
+ width: 0,
1285
+ height: 0,
1286
+ border: 0,
1287
+ margin: 0,
1288
+ background: "none"
1289
+ };
1290
+ if ( body ) {
1291
+ $.extend( testElementStyle, {
1292
+ position: "absolute",
1293
+ left: "-1000px",
1294
+ top: "-1000px"
1295
+ });
1296
+ }
1297
+ for ( i in testElementStyle ) {
1298
+ testElement.style[ i ] = testElementStyle[ i ];
1299
+ }
1300
+ testElement.appendChild( div );
1301
+ testElementParent = body || document.documentElement;
1302
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
1303
+
1304
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
1305
+
1306
+ offsetLeft = $( div ).offset().left;
1307
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
1308
+
1309
+ testElement.innerHTML = "";
1310
+ testElementParent.removeChild( testElement );
1311
+ })();
1312
+
1313
+ }( jQuery ) );
1314
+ (function( $, undefined ) {
1315
+
1316
+ // used to prevent race conditions with remote data sources
1317
+ var requestIndex = 0;
1318
+
1319
+ $.widget( "ui.autocomplete", {
1320
+ version: "1.10.3",
1321
+ defaultElement: "<input>",
1322
+ options: {
1323
+ appendTo: null,
1324
+ autoFocus: false,
1325
+ delay: 300,
1326
+ minLength: 1,
1327
+ position: {
1328
+ my: "left top",
1329
+ at: "left bottom",
1330
+ collision: "none"
1331
+ },
1332
+ source: null,
1333
+
1334
+ // callbacks
1335
+ change: null,
1336
+ close: null,
1337
+ focus: null,
1338
+ open: null,
1339
+ response: null,
1340
+ search: null,
1341
+ select: null
1342
+ },
1343
+
1344
+ pending: 0,
1345
+
1346
+ _create: function() {
1347
+ // Some browsers only repeat keydown events, not keypress events,
1348
+ // so we use the suppressKeyPress flag to determine if we've already
1349
+ // handled the keydown event. #7269
1350
+ // Unfortunately the code for & in keypress is the same as the up arrow,
1351
+ // so we use the suppressKeyPressRepeat flag to avoid handling keypress
1352
+ // events when we know the keydown event was used to modify the
1353
+ // search term. #7799
1354
+ var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
1355
+ nodeName = this.element[0].nodeName.toLowerCase(),
1356
+ isTextarea = nodeName === "textarea",
1357
+ isInput = nodeName === "input";
1358
+
1359
+ this.isMultiLine =
1360
+ // Textareas are always multi-line
1361
+ isTextarea ? true :
1362
+ // Inputs are always single-line, even if inside a contentEditable element
1363
+ // IE also treats inputs as contentEditable
1364
+ isInput ? false :
1365
+ // All other element types are determined by whether or not they're contentEditable
1366
+ this.element.prop( "isContentEditable" );
1367
+
1368
+ this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
1369
+ this.isNewMenu = true;
1370
+
1371
+ this.element
1372
+ .addClass( "ui-autocomplete-input" )
1373
+ .attr( "autocomplete", "off" );
1374
+
1375
+ this._on( this.element, {
1376
+ keydown: function( event ) {
1377
+ /*jshint maxcomplexity:15*/
1378
+ if ( this.element.prop( "readOnly" ) ) {
1379
+ suppressKeyPress = true;
1380
+ suppressInput = true;
1381
+ suppressKeyPressRepeat = true;
1382
+ return;
1383
+ }
1384
+
1385
+ suppressKeyPress = false;
1386
+ suppressInput = false;
1387
+ suppressKeyPressRepeat = false;
1388
+ var keyCode = $.ui.keyCode;
1389
+ switch( event.keyCode ) {
1390
+ case keyCode.PAGE_UP:
1391
+ suppressKeyPress = true;
1392
+ this._move( "previousPage", event );
1393
+ break;
1394
+ case keyCode.PAGE_DOWN:
1395
+ suppressKeyPress = true;
1396
+ this._move( "nextPage", event );
1397
+ break;
1398
+ case keyCode.UP:
1399
+ suppressKeyPress = true;
1400
+ this._keyEvent( "previous", event );
1401
+ break;
1402
+ case keyCode.DOWN:
1403
+ suppressKeyPress = true;
1404
+ this._keyEvent( "next", event );
1405
+ break;
1406
+ case keyCode.ENTER:
1407
+ case keyCode.NUMPAD_ENTER:
1408
+ // when menu is open and has focus
1409
+ if ( this.menu.active ) {
1410
+ // #6055 - Opera still allows the keypress to occur
1411
+ // which causes forms to submit
1412
+ suppressKeyPress = true;
1413
+ event.preventDefault();
1414
+ this.menu.select( event );
1415
+ }
1416
+ break;
1417
+ case keyCode.TAB:
1418
+ if ( this.menu.active ) {
1419
+ this.menu.select( event );
1420
+ }
1421
+ break;
1422
+ case keyCode.ESCAPE:
1423
+ if ( this.menu.element.is( ":visible" ) ) {
1424
+ this._value( this.term );
1425
+ this.close( event );
1426
+ // Different browsers have different default behavior for escape
1427
+ // Single press can mean undo or clear
1428
+ // Double press in IE means clear the whole form
1429
+ event.preventDefault();
1430
+ }
1431
+ break;
1432
+ default:
1433
+ suppressKeyPressRepeat = true;
1434
+ // search timeout should be triggered before the input value is changed
1435
+ this._searchTimeout( event );
1436
+ break;
1437
+ }
1438
+ },
1439
+ keypress: function( event ) {
1440
+ if ( suppressKeyPress ) {
1441
+ suppressKeyPress = false;
1442
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
1443
+ event.preventDefault();
1444
+ }
1445
+ return;
1446
+ }
1447
+ if ( suppressKeyPressRepeat ) {
1448
+ return;
1449
+ }
1450
+
1451
+ // replicate some key handlers to allow them to repeat in Firefox and Opera
1452
+ var keyCode = $.ui.keyCode;
1453
+ switch( event.keyCode ) {
1454
+ case keyCode.PAGE_UP:
1455
+ this._move( "previousPage", event );
1456
+ break;
1457
+ case keyCode.PAGE_DOWN:
1458
+ this._move( "nextPage", event );
1459
+ break;
1460
+ case keyCode.UP:
1461
+ this._keyEvent( "previous", event );
1462
+ break;
1463
+ case keyCode.DOWN:
1464
+ this._keyEvent( "next", event );
1465
+ break;
1466
+ }
1467
+ },
1468
+ input: function( event ) {
1469
+ if ( suppressInput ) {
1470
+ suppressInput = false;
1471
+ event.preventDefault();
1472
+ return;
1473
+ }
1474
+ this._searchTimeout( event );
1475
+ },
1476
+ focus: function() {
1477
+ this.selectedItem = null;
1478
+ this.previous = this._value();
1479
+ },
1480
+ blur: function( event ) {
1481
+ if ( this.cancelBlur ) {
1482
+ delete this.cancelBlur;
1483
+ return;
1484
+ }
1485
+
1486
+ clearTimeout( this.searching );
1487
+ this.close( event );
1488
+ this._change( event );
1489
+ }
1490
+ });
1491
+
1492
+ this._initSource();
1493
+ this.menu = $( "<ul>" )
1494
+ .addClass( "ui-autocomplete ui-front" )
1495
+ .appendTo( this._appendTo() )
1496
+ .menu({
1497
+ // disable ARIA support, the live region takes care of that
1498
+ role: null
1499
+ })
1500
+ .hide()
1501
+ .data( "ui-menu" );
1502
+
1503
+ this._on( this.menu.element, {
1504
+ mousedown: function( event ) {
1505
+ // prevent moving focus out of the text field
1506
+ event.preventDefault();
1507
+
1508
+ // IE doesn't prevent moving focus even with event.preventDefault()
1509
+ // so we set a flag to know when we should ignore the blur event
1510
+ this.cancelBlur = true;
1511
+ this._delay(function() {
1512
+ delete this.cancelBlur;
1513
+ });
1514
+
1515
+ // clicking on the scrollbar causes focus to shift to the body
1516
+ // but we can't detect a mouseup or a click immediately afterward
1517
+ // so we have to track the next mousedown and close the menu if
1518
+ // the user clicks somewhere outside of the autocomplete
1519
+ var menuElement = this.menu.element[ 0 ];
1520
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
1521
+ this._delay(function() {
1522
+ var that = this;
1523
+ this.document.one( "mousedown", function( event ) {
1524
+ if ( event.target !== that.element[ 0 ] &&
1525
+ event.target !== menuElement &&
1526
+ !$.contains( menuElement, event.target ) ) {
1527
+ that.close();
1528
+ }
1529
+ });
1530
+ });
1531
+ }
1532
+ },
1533
+ menufocus: function( event, ui ) {
1534
+ // support: Firefox
1535
+ // Prevent accidental activation of menu items in Firefox (#7024 #9118)
1536
+ if ( this.isNewMenu ) {
1537
+ this.isNewMenu = false;
1538
+ if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
1539
+ this.menu.blur();
1540
+
1541
+ this.document.one( "mousemove", function() {
1542
+ $( event.target ).trigger( event.originalEvent );
1543
+ });
1544
+
1545
+ return;
1546
+ }
1547
+ }
1548
+
1549
+ var item = ui.item.data( "ui-autocomplete-item" );
1550
+ if ( false !== this._trigger( "focus", event, { item: item } ) ) {
1551
+ // use value to match what will end up in the input, if it was a key event
1552
+ if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
1553
+ this._value( item.value );
1554
+ }
1555
+ } else {
1556
+ // Normally the input is populated with the item's value as the
1557
+ // menu is navigated, causing screen readers to notice a change and
1558
+ // announce the item. Since the focus event was canceled, this doesn't
1559
+ // happen, so we update the live region so that screen readers can
1560
+ // still notice the change and announce it.
1561
+ this.liveRegion.text( item.value );
1562
+ }
1563
+ },
1564
+ menuselect: function( event, ui ) {
1565
+ var item = ui.item.data( "ui-autocomplete-item" ),
1566
+ previous = this.previous;
1567
+
1568
+ // only trigger when focus was lost (click on menu)
1569
+ if ( this.element[0] !== this.document[0].activeElement ) {
1570
+ this.element.focus();
1571
+ this.previous = previous;
1572
+ // #6109 - IE triggers two focus events and the second
1573
+ // is asynchronous, so we need to reset the previous
1574
+ // term synchronously and asynchronously :-(
1575
+ this._delay(function() {
1576
+ this.previous = previous;
1577
+ this.selectedItem = item;
1578
+ });
1579
+ }
1580
+
1581
+ if ( false !== this._trigger( "select", event, { item: item } ) ) {
1582
+ this._value( item.value );
1583
+ }
1584
+ // reset the term after the select event
1585
+ // this allows custom select handling to work properly
1586
+ this.term = this._value();
1587
+
1588
+ this.close( event );
1589
+ this.selectedItem = item;
1590
+ }
1591
+ });
1592
+
1593
+ this.liveRegion = $( "<span>", {
1594
+ role: "status",
1595
+ "aria-live": "polite"
1596
+ })
1597
+ .addClass( "ui-helper-hidden-accessible" )
1598
+ .insertBefore( this.element );
1599
+
1600
+ // turning off autocomplete prevents the browser from remembering the
1601
+ // value when navigating through history, so we re-enable autocomplete
1602
+ // if the page is unloaded before the widget is destroyed. #7790
1603
+ this._on( this.window, {
1604
+ beforeunload: function() {
1605
+ this.element.removeAttr( "autocomplete" );
1606
+ }
1607
+ });
1608
+ },
1609
+
1610
+ _destroy: function() {
1611
+ clearTimeout( this.searching );
1612
+ this.element
1613
+ .removeClass( "ui-autocomplete-input" )
1614
+ .removeAttr( "autocomplete" );
1615
+ this.menu.element.remove();
1616
+ this.liveRegion.remove();
1617
+ },
1618
+
1619
+ _setOption: function( key, value ) {
1620
+ this._super( key, value );
1621
+ if ( key === "source" ) {
1622
+ this._initSource();
1623
+ }
1624
+ if ( key === "appendTo" ) {
1625
+ this.menu.element.appendTo( this._appendTo() );
1626
+ }
1627
+ if ( key === "disabled" && value && this.xhr ) {
1628
+ this.xhr.abort();
1629
+ }
1630
+ },
1631
+
1632
+ _appendTo: function() {
1633
+ var element = this.options.appendTo;
1634
+
1635
+ if ( element ) {
1636
+ element = element.jquery || element.nodeType ?
1637
+ $( element ) :
1638
+ this.document.find( element ).eq( 0 );
1639
+ }
1640
+
1641
+ if ( !element ) {
1642
+ element = this.element.closest( ".ui-front" );
1643
+ }
1644
+
1645
+ if ( !element.length ) {
1646
+ element = this.document[0].body;
1647
+ }
1648
+
1649
+ return element;
1650
+ },
1651
+
1652
+ _initSource: function() {
1653
+ var array, url,
1654
+ that = this;
1655
+ if ( $.isArray(this.options.source) ) {
1656
+ array = this.options.source;
1657
+ this.source = function( request, response ) {
1658
+ response( $.ui.autocomplete.filter( array, request.term ) );
1659
+ };
1660
+ } else if ( typeof this.options.source === "string" ) {
1661
+ url = this.options.source;
1662
+ this.source = function( request, response ) {
1663
+ if ( that.xhr ) {
1664
+ that.xhr.abort();
1665
+ }
1666
+ that.xhr = $.ajax({
1667
+ url: url,
1668
+ data: request,
1669
+ dataType: "json",
1670
+ success: function( data ) {
1671
+ response( data );
1672
+ },
1673
+ error: function() {
1674
+ response( [] );
1675
+ }
1676
+ });
1677
+ };
1678
+ } else {
1679
+ this.source = this.options.source;
1680
+ }
1681
+ },
1682
+
1683
+ _searchTimeout: function( event ) {
1684
+ clearTimeout( this.searching );
1685
+ this.searching = this._delay(function() {
1686
+ // only search if the value has changed
1687
+ if ( this.term !== this._value() ) {
1688
+ this.selectedItem = null;
1689
+ this.search( null, event );
1690
+ }
1691
+ }, this.options.delay );
1692
+ },
1693
+
1694
+ search: function( value, event ) {
1695
+ value = value != null ? value : this._value();
1696
+
1697
+ // always save the actual value, not the one passed as an argument
1698
+ this.term = this._value();
1699
+
1700
+ if ( value.length < this.options.minLength ) {
1701
+ return this.close( event );
1702
+ }
1703
+
1704
+ if ( this._trigger( "search", event ) === false ) {
1705
+ return;
1706
+ }
1707
+
1708
+ return this._search( value );
1709
+ },
1710
+
1711
+ _search: function( value ) {
1712
+ this.pending++;
1713
+ this.element.addClass( "ui-autocomplete-loading" );
1714
+ this.cancelSearch = false;
1715
+
1716
+ this.source( { term: value }, this._response() );
1717
+ },
1718
+
1719
+ _response: function() {
1720
+ var that = this,
1721
+ index = ++requestIndex;
1722
+
1723
+ return function( content ) {
1724
+ if ( index === requestIndex ) {
1725
+ that.__response( content );
1726
+ }
1727
+
1728
+ that.pending--;
1729
+ if ( !that.pending ) {
1730
+ that.element.removeClass( "ui-autocomplete-loading" );
1731
+ }
1732
+ };
1733
+ },
1734
+
1735
+ __response: function( content ) {
1736
+ if ( content ) {
1737
+ content = this._normalize( content );
1738
+ }
1739
+ this._trigger( "response", null, { content: content } );
1740
+ if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
1741
+ this._suggest( content );
1742
+ this._trigger( "open" );
1743
+ } else {
1744
+ // use ._close() instead of .close() so we don't cancel future searches
1745
+ this._close();
1746
+ }
1747
+ },
1748
+
1749
+ close: function( event ) {
1750
+ this.cancelSearch = true;
1751
+ this._close( event );
1752
+ },
1753
+
1754
+ _close: function( event ) {
1755
+ if ( this.menu.element.is( ":visible" ) ) {
1756
+ this.menu.element.hide();
1757
+ this.menu.blur();
1758
+ this.isNewMenu = true;
1759
+ this._trigger( "close", event );
1760
+ }
1761
+ },
1762
+
1763
+ _change: function( event ) {
1764
+ if ( this.previous !== this._value() ) {
1765
+ this._trigger( "change", event, { item: this.selectedItem } );
1766
+ }
1767
+ },
1768
+
1769
+ _normalize: function( items ) {
1770
+ // assume all items have the right format when the first item is complete
1771
+ if ( items.length && items[0].label && items[0].value ) {
1772
+ return items;
1773
+ }
1774
+ return $.map( items, function( item ) {
1775
+ if ( typeof item === "string" ) {
1776
+ return {
1777
+ label: item,
1778
+ value: item
1779
+ };
1780
+ }
1781
+ return $.extend({
1782
+ label: item.label || item.value,
1783
+ value: item.value || item.label
1784
+ }, item );
1785
+ });
1786
+ },
1787
+
1788
+ _suggest: function( items ) {
1789
+ var ul = this.menu.element.empty();
1790
+ this._renderMenu( ul, items );
1791
+ this.isNewMenu = true;
1792
+ this.menu.refresh();
1793
+
1794
+ // size and position menu
1795
+ ul.show();
1796
+ this._resizeMenu();
1797
+ ul.position( $.extend({
1798
+ of: this.element
1799
+ }, this.options.position ));
1800
+
1801
+ if ( this.options.autoFocus ) {
1802
+ this.menu.next();
1803
+ }
1804
+ },
1805
+
1806
+ _resizeMenu: function() {
1807
+ var ul = this.menu.element;
1808
+ ul.outerWidth( Math.max(
1809
+ // Firefox wraps long text (possibly a rounding bug)
1810
+ // so we add 1px to avoid the wrapping (#7513)
1811
+ ul.width( "" ).outerWidth() + 1,
1812
+ this.element.outerWidth()
1813
+ ) );
1814
+ },
1815
+
1816
+ _renderMenu: function( ul, items ) {
1817
+ var that = this;
1818
+ $.each( items, function( index, item ) {
1819
+ that._renderItemData( ul, item );
1820
+ });
1821
+ },
1822
+
1823
+ _renderItemData: function( ul, item ) {
1824
+ return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
1825
+ },
1826
+
1827
+ _renderItem: function( ul, item ) {
1828
+ return $( "<li>" )
1829
+ .append( $( "<a>" ).text( item.label ) )
1830
+ .appendTo( ul );
1831
+ },
1832
+
1833
+ _move: function( direction, event ) {
1834
+ if ( !this.menu.element.is( ":visible" ) ) {
1835
+ this.search( null, event );
1836
+ return;
1837
+ }
1838
+ if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
1839
+ this.menu.isLastItem() && /^next/.test( direction ) ) {
1840
+ this._value( this.term );
1841
+ this.menu.blur();
1842
+ return;
1843
+ }
1844
+ this.menu[ direction ]( event );
1845
+ },
1846
+
1847
+ widget: function() {
1848
+ return this.menu.element;
1849
+ },
1850
+
1851
+ _value: function() {
1852
+ return this.valueMethod.apply( this.element, arguments );
1853
+ },
1854
+
1855
+ _keyEvent: function( keyEvent, event ) {
1856
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
1857
+ this._move( keyEvent, event );
1858
+
1859
+ // prevents moving cursor to beginning/end of the text field in some browsers
1860
+ event.preventDefault();
1861
+ }
1862
+ }
1863
+ });
1864
+
1865
+ $.extend( $.ui.autocomplete, {
1866
+ escapeRegex: function( value ) {
1867
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
1868
+ },
1869
+ filter: function(array, term) {
1870
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
1871
+ return $.grep( array, function(value) {
1872
+ return matcher.test( value.label || value.value || value );
1873
+ });
1874
+ }
1875
+ });
1876
+
1877
+
1878
+ // live region extension, adding a `messages` option
1879
+ // NOTE: This is an experimental API. We are still investigating
1880
+ // a full solution for string manipulation and internationalization.
1881
+ $.widget( "ui.autocomplete", $.ui.autocomplete, {
1882
+ options: {
1883
+ messages: {
1884
+ noResults: "No search results.",
1885
+ results: function( amount ) {
1886
+ return amount + ( amount > 1 ? " results are" : " result is" ) +
1887
+ " available, use up and down arrow keys to navigate.";
1888
+ }
1889
+ }
1890
+ },
1891
+
1892
+ __response: function( content ) {
1893
+ var message;
1894
+ this._superApply( arguments );
1895
+ if ( this.options.disabled || this.cancelSearch ) {
1896
+ return;
1897
+ }
1898
+ if ( content && content.length ) {
1899
+ message = this.options.messages.results( content.length );
1900
+ } else {
1901
+ message = this.options.messages.noResults;
1902
+ }
1903
+ this.liveRegion.text( message );
1904
+ }
1905
+ });
1906
+
1907
+ }( jQuery ));
1908
+ (function( $, undefined ) {
1909
+
1910
+ $.extend($.ui, { datepicker: { version: "1.10.3" } });
1911
+
1912
+ var PROP_NAME = "datepicker",
1913
+ instActive;
1914
+
1915
+ /* Date picker manager.
1916
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
1917
+ Settings for (groups of) date pickers are maintained in an instance object,
1918
+ allowing multiple different settings on the same page. */
1919
+
1920
+ function Datepicker() {
1921
+ this._curInst = null; // The current instance in use
1922
+ this._keyEvent = false; // If the last event was a key event
1923
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
1924
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
1925
+ this._inDialog = false; // True if showing within a "dialog", false if not
1926
+ this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
1927
+ this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
1928
+ this._appendClass = "ui-datepicker-append"; // The name of the append marker class
1929
+ this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
1930
+ this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
1931
+ this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
1932
+ this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
1933
+ this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
1934
+ this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
1935
+ this.regional = []; // Available regional settings, indexed by language code
1936
+ this.regional[""] = { // Default regional settings
1937
+ closeText: "Done", // Display text for close link
1938
+ prevText: "Prev", // Display text for previous month link
1939
+ nextText: "Next", // Display text for next month link
1940
+ currentText: "Today", // Display text for current month link
1941
+ monthNames: ["January","February","March","April","May","June",
1942
+ "July","August","September","October","November","December"], // Names of months for drop-down and formatting
1943
+ monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
1944
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
1945
+ dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
1946
+ dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
1947
+ weekHeader: "Wk", // Column header for week of the year
1948
+ dateFormat: "mm/dd/yy", // See format options on parseDate
1949
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
1950
+ isRTL: false, // True if right-to-left language, false if left-to-right
1951
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
1952
+ yearSuffix: "" // Additional text to append to the year in the month headers
1953
+ };
1954
+ this._defaults = { // Global defaults for all the date picker instances
1955
+ showOn: "focus", // "focus" for popup on focus,
1956
+ // "button" for trigger button, or "both" for either
1957
+ showAnim: "fadeIn", // Name of jQuery animation for popup
1958
+ showOptions: {}, // Options for enhanced animations
1959
+ defaultDate: null, // Used when field is blank: actual date,
1960
+ // +/-number for offset from today, null for today
1961
+ appendText: "", // Display text following the input box, e.g. showing the format
1962
+ buttonText: "...", // Text for trigger button
1963
+ buttonImage: "", // URL for trigger button image
1964
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
1965
+ hideIfNoPrevNext: false, // True to hide next/previous month links
1966
+ // if not applicable, false to just disable them
1967
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
1968
+ gotoCurrent: false, // True if today link goes back to current selection instead
1969
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
1970
+ changeYear: false, // True if year can be selected directly, false if only prev/next
1971
+ yearRange: "c-10:c+10", // Range of years to display in drop-down,
1972
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
1973
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
1974
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
1975
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
1976
+ showWeek: false, // True to show week of the year, false to not show it
1977
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
1978
+ // takes a Date and returns the number of the week for it
1979
+ shortYearCutoff: "+10", // Short year values < this are in the current century,
1980
+ // > this are in the previous century,
1981
+ // string value starting with "+" for current year + value
1982
+ minDate: null, // The earliest selectable date, or null for no limit
1983
+ maxDate: null, // The latest selectable date, or null for no limit
1984
+ duration: "fast", // Duration of display/closure
1985
+ beforeShowDay: null, // Function that takes a date and returns an array with
1986
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
1987
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
1988
+ beforeShow: null, // Function that takes an input field and
1989
+ // returns a set of custom settings for the date picker
1990
+ onSelect: null, // Define a callback function when a date is selected
1991
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
1992
+ onClose: null, // Define a callback function when the datepicker is closed
1993
+ numberOfMonths: 1, // Number of months to show at a time
1994
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
1995
+ stepMonths: 1, // Number of months to step back/forward
1996
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
1997
+ altField: "", // Selector for an alternate field to store selected dates into
1998
+ altFormat: "", // The date format to use for the alternate field
1999
+ constrainInput: true, // The input is constrained by the current date format
2000
+ showButtonPanel: false, // True to show button panel, false to not show it
2001
+ autoSize: false, // True to size the input for the date format, false to leave as is
2002
+ disabled: false // The initial disabled state
2003
+ };
2004
+ $.extend(this._defaults, this.regional[""]);
2005
+ this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
2006
+ }
2007
+
2008
+ $.extend(Datepicker.prototype, {
2009
+ /* Class name added to elements to indicate already configured with a date picker. */
2010
+ markerClassName: "hasDatepicker",
2011
+
2012
+ //Keep track of the maximum number of rows displayed (see #7043)
2013
+ maxRows: 4,
2014
+
2015
+ // TODO rename to "widget" when switching to widget factory
2016
+ _widgetDatepicker: function() {
2017
+ return this.dpDiv;
2018
+ },
2019
+
2020
+ /* Override the default settings for all instances of the date picker.
2021
+ * @param settings object - the new settings to use as defaults (anonymous object)
2022
+ * @return the manager object
2023
+ */
2024
+ setDefaults: function(settings) {
2025
+ extendRemove(this._defaults, settings || {});
2026
+ return this;
2027
+ },
2028
+
2029
+ /* Attach the date picker to a jQuery selection.
2030
+ * @param target element - the target input field or division or span
2031
+ * @param settings object - the new settings to use for this date picker instance (anonymous)
2032
+ */
2033
+ _attachDatepicker: function(target, settings) {
2034
+ var nodeName, inline, inst;
2035
+ nodeName = target.nodeName.toLowerCase();
2036
+ inline = (nodeName === "div" || nodeName === "span");
2037
+ if (!target.id) {
2038
+ this.uuid += 1;
2039
+ target.id = "dp" + this.uuid;
2040
+ }
2041
+ inst = this._newInst($(target), inline);
2042
+ inst.settings = $.extend({}, settings || {});
2043
+ if (nodeName === "input") {
2044
+ this._connectDatepicker(target, inst);
2045
+ } else if (inline) {
2046
+ this._inlineDatepicker(target, inst);
2047
+ }
2048
+ },
2049
+
2050
+ /* Create a new instance object. */
2051
+ _newInst: function(target, inline) {
2052
+ var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
2053
+ return {id: id, input: target, // associated target
2054
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
2055
+ drawMonth: 0, drawYear: 0, // month being drawn
2056
+ inline: inline, // is datepicker inline or not
2057
+ dpDiv: (!inline ? this.dpDiv : // presentation div
2058
+ bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
2059
+ },
2060
+
2061
+ /* Attach the date picker to an input field. */
2062
+ _connectDatepicker: function(target, inst) {
2063
+ var input = $(target);
2064
+ inst.append = $([]);
2065
+ inst.trigger = $([]);
2066
+ if (input.hasClass(this.markerClassName)) {
2067
+ return;
2068
+ }
2069
+ this._attachments(input, inst);
2070
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
2071
+ keypress(this._doKeyPress).keyup(this._doKeyUp);
2072
+ this._autoSize(inst);
2073
+ $.data(target, PROP_NAME, inst);
2074
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
2075
+ if( inst.settings.disabled ) {
2076
+ this._disableDatepicker( target );
2077
+ }
2078
+ },
2079
+
2080
+ /* Make attachments based on settings. */
2081
+ _attachments: function(input, inst) {
2082
+ var showOn, buttonText, buttonImage,
2083
+ appendText = this._get(inst, "appendText"),
2084
+ isRTL = this._get(inst, "isRTL");
2085
+
2086
+ if (inst.append) {
2087
+ inst.append.remove();
2088
+ }
2089
+ if (appendText) {
2090
+ inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
2091
+ input[isRTL ? "before" : "after"](inst.append);
2092
+ }
2093
+
2094
+ input.unbind("focus", this._showDatepicker);
2095
+
2096
+ if (inst.trigger) {
2097
+ inst.trigger.remove();
2098
+ }
2099
+
2100
+ showOn = this._get(inst, "showOn");
2101
+ if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
2102
+ input.focus(this._showDatepicker);
2103
+ }
2104
+ if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
2105
+ buttonText = this._get(inst, "buttonText");
2106
+ buttonImage = this._get(inst, "buttonImage");
2107
+ inst.trigger = $(this._get(inst, "buttonImageOnly") ?
2108
+ $("<img/>").addClass(this._triggerClass).
2109
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
2110
+ $("<button type='button'></button>").addClass(this._triggerClass).
2111
+ html(!buttonImage ? buttonText : $("<img/>").attr(
2112
+ { src:buttonImage, alt:buttonText, title:buttonText })));
2113
+ input[isRTL ? "before" : "after"](inst.trigger);
2114
+ inst.trigger.click(function() {
2115
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
2116
+ $.datepicker._hideDatepicker();
2117
+ } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
2118
+ $.datepicker._hideDatepicker();
2119
+ $.datepicker._showDatepicker(input[0]);
2120
+ } else {
2121
+ $.datepicker._showDatepicker(input[0]);
2122
+ }
2123
+ return false;
2124
+ });
2125
+ }
2126
+ },
2127
+
2128
+ /* Apply the maximum length for the date format. */
2129
+ _autoSize: function(inst) {
2130
+ if (this._get(inst, "autoSize") && !inst.inline) {
2131
+ var findMax, max, maxI, i,
2132
+ date = new Date(2009, 12 - 1, 20), // Ensure double digits
2133
+ dateFormat = this._get(inst, "dateFormat");
2134
+
2135
+ if (dateFormat.match(/[DM]/)) {
2136
+ findMax = function(names) {
2137
+ max = 0;
2138
+ maxI = 0;
2139
+ for (i = 0; i < names.length; i++) {
2140
+ if (names[i].length > max) {
2141
+ max = names[i].length;
2142
+ maxI = i;
2143
+ }
2144
+ }
2145
+ return maxI;
2146
+ };
2147
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
2148
+ "monthNames" : "monthNamesShort"))));
2149
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
2150
+ "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
2151
+ }
2152
+ inst.input.attr("size", this._formatDate(inst, date).length);
2153
+ }
2154
+ },
2155
+
2156
+ /* Attach an inline date picker to a div. */
2157
+ _inlineDatepicker: function(target, inst) {
2158
+ var divSpan = $(target);
2159
+ if (divSpan.hasClass(this.markerClassName)) {
2160
+ return;
2161
+ }
2162
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv);
2163
+ $.data(target, PROP_NAME, inst);
2164
+ this._setDate(inst, this._getDefaultDate(inst), true);
2165
+ this._updateDatepicker(inst);
2166
+ this._updateAlternate(inst);
2167
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
2168
+ if( inst.settings.disabled ) {
2169
+ this._disableDatepicker( target );
2170
+ }
2171
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
2172
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
2173
+ inst.dpDiv.css( "display", "block" );
2174
+ },
2175
+
2176
+ /* Pop-up the date picker in a "dialog" box.
2177
+ * @param input element - ignored
2178
+ * @param date string or Date - the initial date to display
2179
+ * @param onSelect function - the function to call when a date is selected
2180
+ * @param settings object - update the dialog date picker instance's settings (anonymous object)
2181
+ * @param pos int[2] - coordinates for the dialog's position within the screen or
2182
+ * event - with x/y coordinates or
2183
+ * leave empty for default (screen centre)
2184
+ * @return the manager object
2185
+ */
2186
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
2187
+ var id, browserWidth, browserHeight, scrollX, scrollY,
2188
+ inst = this._dialogInst; // internal instance
2189
+
2190
+ if (!inst) {
2191
+ this.uuid += 1;
2192
+ id = "dp" + this.uuid;
2193
+ this._dialogInput = $("<input type='text' id='" + id +
2194
+ "' style='position: absolute; top: -100px; width: 0px;'/>");
2195
+ this._dialogInput.keydown(this._doKeyDown);
2196
+ $("body").append(this._dialogInput);
2197
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
2198
+ inst.settings = {};
2199
+ $.data(this._dialogInput[0], PROP_NAME, inst);
2200
+ }
2201
+ extendRemove(inst.settings, settings || {});
2202
+ date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
2203
+ this._dialogInput.val(date);
2204
+
2205
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
2206
+ if (!this._pos) {
2207
+ browserWidth = document.documentElement.clientWidth;
2208
+ browserHeight = document.documentElement.clientHeight;
2209
+ scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
2210
+ scrollY = document.documentElement.scrollTop || document.body.scrollTop;
2211
+ this._pos = // should use actual width/height below
2212
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
2213
+ }
2214
+
2215
+ // move input on screen for focus, but hidden behind dialog
2216
+ this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
2217
+ inst.settings.onSelect = onSelect;
2218
+ this._inDialog = true;
2219
+ this.dpDiv.addClass(this._dialogClass);
2220
+ this._showDatepicker(this._dialogInput[0]);
2221
+ if ($.blockUI) {
2222
+ $.blockUI(this.dpDiv);
2223
+ }
2224
+ $.data(this._dialogInput[0], PROP_NAME, inst);
2225
+ return this;
2226
+ },
2227
+
2228
+ /* Detach a datepicker from its control.
2229
+ * @param target element - the target input field or division or span
2230
+ */
2231
+ _destroyDatepicker: function(target) {
2232
+ var nodeName,
2233
+ $target = $(target),
2234
+ inst = $.data(target, PROP_NAME);
2235
+
2236
+ if (!$target.hasClass(this.markerClassName)) {
2237
+ return;
2238
+ }
2239
+
2240
+ nodeName = target.nodeName.toLowerCase();
2241
+ $.removeData(target, PROP_NAME);
2242
+ if (nodeName === "input") {
2243
+ inst.append.remove();
2244
+ inst.trigger.remove();
2245
+ $target.removeClass(this.markerClassName).
2246
+ unbind("focus", this._showDatepicker).
2247
+ unbind("keydown", this._doKeyDown).
2248
+ unbind("keypress", this._doKeyPress).
2249
+ unbind("keyup", this._doKeyUp);
2250
+ } else if (nodeName === "div" || nodeName === "span") {
2251
+ $target.removeClass(this.markerClassName).empty();
2252
+ }
2253
+ },
2254
+
2255
+ /* Enable the date picker to a jQuery selection.
2256
+ * @param target element - the target input field or division or span
2257
+ */
2258
+ _enableDatepicker: function(target) {
2259
+ var nodeName, inline,
2260
+ $target = $(target),
2261
+ inst = $.data(target, PROP_NAME);
2262
+
2263
+ if (!$target.hasClass(this.markerClassName)) {
2264
+ return;
2265
+ }
2266
+
2267
+ nodeName = target.nodeName.toLowerCase();
2268
+ if (nodeName === "input") {
2269
+ target.disabled = false;
2270
+ inst.trigger.filter("button").
2271
+ each(function() { this.disabled = false; }).end().
2272
+ filter("img").css({opacity: "1.0", cursor: ""});
2273
+ } else if (nodeName === "div" || nodeName === "span") {
2274
+ inline = $target.children("." + this._inlineClass);
2275
+ inline.children().removeClass("ui-state-disabled");
2276
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
2277
+ prop("disabled", false);
2278
+ }
2279
+ this._disabledInputs = $.map(this._disabledInputs,
2280
+ function(value) { return (value === target ? null : value); }); // delete entry
2281
+ },
2282
+
2283
+ /* Disable the date picker to a jQuery selection.
2284
+ * @param target element - the target input field or division or span
2285
+ */
2286
+ _disableDatepicker: function(target) {
2287
+ var nodeName, inline,
2288
+ $target = $(target),
2289
+ inst = $.data(target, PROP_NAME);
2290
+
2291
+ if (!$target.hasClass(this.markerClassName)) {
2292
+ return;
2293
+ }
2294
+
2295
+ nodeName = target.nodeName.toLowerCase();
2296
+ if (nodeName === "input") {
2297
+ target.disabled = true;
2298
+ inst.trigger.filter("button").
2299
+ each(function() { this.disabled = true; }).end().
2300
+ filter("img").css({opacity: "0.5", cursor: "default"});
2301
+ } else if (nodeName === "div" || nodeName === "span") {
2302
+ inline = $target.children("." + this._inlineClass);
2303
+ inline.children().addClass("ui-state-disabled");
2304
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
2305
+ prop("disabled", true);
2306
+ }
2307
+ this._disabledInputs = $.map(this._disabledInputs,
2308
+ function(value) { return (value === target ? null : value); }); // delete entry
2309
+ this._disabledInputs[this._disabledInputs.length] = target;
2310
+ },
2311
+
2312
+ /* Is the first field in a jQuery collection disabled as a datepicker?
2313
+ * @param target element - the target input field or division or span
2314
+ * @return boolean - true if disabled, false if enabled
2315
+ */
2316
+ _isDisabledDatepicker: function(target) {
2317
+ if (!target) {
2318
+ return false;
2319
+ }
2320
+ for (var i = 0; i < this._disabledInputs.length; i++) {
2321
+ if (this._disabledInputs[i] === target) {
2322
+ return true;
2323
+ }
2324
+ }
2325
+ return false;
2326
+ },
2327
+
2328
+ /* Retrieve the instance data for the target control.
2329
+ * @param target element - the target input field or division or span
2330
+ * @return object - the associated instance data
2331
+ * @throws error if a jQuery problem getting data
2332
+ */
2333
+ _getInst: function(target) {
2334
+ try {
2335
+ return $.data(target, PROP_NAME);
2336
+ }
2337
+ catch (err) {
2338
+ throw "Missing instance data for this datepicker";
2339
+ }
2340
+ },
2341
+
2342
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
2343
+ * @param target element - the target input field or division or span
2344
+ * @param name object - the new settings to update or
2345
+ * string - the name of the setting to change or retrieve,
2346
+ * when retrieving also "all" for all instance settings or
2347
+ * "defaults" for all global defaults
2348
+ * @param value any - the new value for the setting
2349
+ * (omit if above is an object or to retrieve a value)
2350
+ */
2351
+ _optionDatepicker: function(target, name, value) {
2352
+ var settings, date, minDate, maxDate,
2353
+ inst = this._getInst(target);
2354
+
2355
+ if (arguments.length === 2 && typeof name === "string") {
2356
+ return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
2357
+ (inst ? (name === "all" ? $.extend({}, inst.settings) :
2358
+ this._get(inst, name)) : null));
2359
+ }
2360
+
2361
+ settings = name || {};
2362
+ if (typeof name === "string") {
2363
+ settings = {};
2364
+ settings[name] = value;
2365
+ }
2366
+
2367
+ if (inst) {
2368
+ if (this._curInst === inst) {
2369
+ this._hideDatepicker();
2370
+ }
2371
+
2372
+ date = this._getDateDatepicker(target, true);
2373
+ minDate = this._getMinMaxDate(inst, "min");
2374
+ maxDate = this._getMinMaxDate(inst, "max");
2375
+ extendRemove(inst.settings, settings);
2376
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
2377
+ if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
2378
+ inst.settings.minDate = this._formatDate(inst, minDate);
2379
+ }
2380
+ if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
2381
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
2382
+ }
2383
+ if ( "disabled" in settings ) {
2384
+ if ( settings.disabled ) {
2385
+ this._disableDatepicker(target);
2386
+ } else {
2387
+ this._enableDatepicker(target);
2388
+ }
2389
+ }
2390
+ this._attachments($(target), inst);
2391
+ this._autoSize(inst);
2392
+ this._setDate(inst, date);
2393
+ this._updateAlternate(inst);
2394
+ this._updateDatepicker(inst);
2395
+ }
2396
+ },
2397
+
2398
+ // change method deprecated
2399
+ _changeDatepicker: function(target, name, value) {
2400
+ this._optionDatepicker(target, name, value);
2401
+ },
2402
+
2403
+ /* Redraw the date picker attached to an input field or division.
2404
+ * @param target element - the target input field or division or span
2405
+ */
2406
+ _refreshDatepicker: function(target) {
2407
+ var inst = this._getInst(target);
2408
+ if (inst) {
2409
+ this._updateDatepicker(inst);
2410
+ }
2411
+ },
2412
+
2413
+ /* Set the dates for a jQuery selection.
2414
+ * @param target element - the target input field or division or span
2415
+ * @param date Date - the new date
2416
+ */
2417
+ _setDateDatepicker: function(target, date) {
2418
+ var inst = this._getInst(target);
2419
+ if (inst) {
2420
+ this._setDate(inst, date);
2421
+ this._updateDatepicker(inst);
2422
+ this._updateAlternate(inst);
2423
+ }
2424
+ },
2425
+
2426
+ /* Get the date(s) for the first entry in a jQuery selection.
2427
+ * @param target element - the target input field or division or span
2428
+ * @param noDefault boolean - true if no default date is to be used
2429
+ * @return Date - the current date
2430
+ */
2431
+ _getDateDatepicker: function(target, noDefault) {
2432
+ var inst = this._getInst(target);
2433
+ if (inst && !inst.inline) {
2434
+ this._setDateFromField(inst, noDefault);
2435
+ }
2436
+ return (inst ? this._getDate(inst) : null);
2437
+ },
2438
+
2439
+ /* Handle keystrokes. */
2440
+ _doKeyDown: function(event) {
2441
+ var onSelect, dateStr, sel,
2442
+ inst = $.datepicker._getInst(event.target),
2443
+ handled = true,
2444
+ isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
2445
+
2446
+ inst._keyEvent = true;
2447
+ if ($.datepicker._datepickerShowing) {
2448
+ switch (event.keyCode) {
2449
+ case 9: $.datepicker._hideDatepicker();
2450
+ handled = false;
2451
+ break; // hide on tab out
2452
+ case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
2453
+ $.datepicker._currentClass + ")", inst.dpDiv);
2454
+ if (sel[0]) {
2455
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
2456
+ }
2457
+
2458
+ onSelect = $.datepicker._get(inst, "onSelect");
2459
+ if (onSelect) {
2460
+ dateStr = $.datepicker._formatDate(inst);
2461
+
2462
+ // trigger custom callback
2463
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
2464
+ } else {
2465
+ $.datepicker._hideDatepicker();
2466
+ }
2467
+
2468
+ return false; // don't submit the form
2469
+ case 27: $.datepicker._hideDatepicker();
2470
+ break; // hide on escape
2471
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
2472
+ -$.datepicker._get(inst, "stepBigMonths") :
2473
+ -$.datepicker._get(inst, "stepMonths")), "M");
2474
+ break; // previous month/year on page up/+ ctrl
2475
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
2476
+ +$.datepicker._get(inst, "stepBigMonths") :
2477
+ +$.datepicker._get(inst, "stepMonths")), "M");
2478
+ break; // next month/year on page down/+ ctrl
2479
+ case 35: if (event.ctrlKey || event.metaKey) {
2480
+ $.datepicker._clearDate(event.target);
2481
+ }
2482
+ handled = event.ctrlKey || event.metaKey;
2483
+ break; // clear on ctrl or command +end
2484
+ case 36: if (event.ctrlKey || event.metaKey) {
2485
+ $.datepicker._gotoToday(event.target);
2486
+ }
2487
+ handled = event.ctrlKey || event.metaKey;
2488
+ break; // current on ctrl or command +home
2489
+ case 37: if (event.ctrlKey || event.metaKey) {
2490
+ $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
2491
+ }
2492
+ handled = event.ctrlKey || event.metaKey;
2493
+ // -1 day on ctrl or command +left
2494
+ if (event.originalEvent.altKey) {
2495
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
2496
+ -$.datepicker._get(inst, "stepBigMonths") :
2497
+ -$.datepicker._get(inst, "stepMonths")), "M");
2498
+ }
2499
+ // next month/year on alt +left on Mac
2500
+ break;
2501
+ case 38: if (event.ctrlKey || event.metaKey) {
2502
+ $.datepicker._adjustDate(event.target, -7, "D");
2503
+ }
2504
+ handled = event.ctrlKey || event.metaKey;
2505
+ break; // -1 week on ctrl or command +up
2506
+ case 39: if (event.ctrlKey || event.metaKey) {
2507
+ $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
2508
+ }
2509
+ handled = event.ctrlKey || event.metaKey;
2510
+ // +1 day on ctrl or command +right
2511
+ if (event.originalEvent.altKey) {
2512
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
2513
+ +$.datepicker._get(inst, "stepBigMonths") :
2514
+ +$.datepicker._get(inst, "stepMonths")), "M");
2515
+ }
2516
+ // next month/year on alt +right
2517
+ break;
2518
+ case 40: if (event.ctrlKey || event.metaKey) {
2519
+ $.datepicker._adjustDate(event.target, +7, "D");
2520
+ }
2521
+ handled = event.ctrlKey || event.metaKey;
2522
+ break; // +1 week on ctrl or command +down
2523
+ default: handled = false;
2524
+ }
2525
+ } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
2526
+ $.datepicker._showDatepicker(this);
2527
+ } else {
2528
+ handled = false;
2529
+ }
2530
+
2531
+ if (handled) {
2532
+ event.preventDefault();
2533
+ event.stopPropagation();
2534
+ }
2535
+ },
2536
+
2537
+ /* Filter entered characters - based on date format. */
2538
+ _doKeyPress: function(event) {
2539
+ var chars, chr,
2540
+ inst = $.datepicker._getInst(event.target);
2541
+
2542
+ if ($.datepicker._get(inst, "constrainInput")) {
2543
+ chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
2544
+ chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
2545
+ return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
2546
+ }
2547
+ },
2548
+
2549
+ /* Synchronise manual entry and field/alternate field. */
2550
+ _doKeyUp: function(event) {
2551
+ var date,
2552
+ inst = $.datepicker._getInst(event.target);
2553
+
2554
+ if (inst.input.val() !== inst.lastVal) {
2555
+ try {
2556
+ date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
2557
+ (inst.input ? inst.input.val() : null),
2558
+ $.datepicker._getFormatConfig(inst));
2559
+
2560
+ if (date) { // only if valid
2561
+ $.datepicker._setDateFromField(inst);
2562
+ $.datepicker._updateAlternate(inst);
2563
+ $.datepicker._updateDatepicker(inst);
2564
+ }
2565
+ }
2566
+ catch (err) {
2567
+ }
2568
+ }
2569
+ return true;
2570
+ },
2571
+
2572
+ /* Pop-up the date picker for a given input field.
2573
+ * If false returned from beforeShow event handler do not show.
2574
+ * @param input element - the input field attached to the date picker or
2575
+ * event - if triggered by focus
2576
+ */
2577
+ _showDatepicker: function(input) {
2578
+ input = input.target || input;
2579
+ if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
2580
+ input = $("input", input.parentNode)[0];
2581
+ }
2582
+
2583
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
2584
+ return;
2585
+ }
2586
+
2587
+ var inst, beforeShow, beforeShowSettings, isFixed,
2588
+ offset, showAnim, duration;
2589
+
2590
+ inst = $.datepicker._getInst(input);
2591
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
2592
+ $.datepicker._curInst.dpDiv.stop(true, true);
2593
+ if ( inst && $.datepicker._datepickerShowing ) {
2594
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
2595
+ }
2596
+ }
2597
+
2598
+ beforeShow = $.datepicker._get(inst, "beforeShow");
2599
+ beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
2600
+ if(beforeShowSettings === false){
2601
+ return;
2602
+ }
2603
+ extendRemove(inst.settings, beforeShowSettings);
2604
+
2605
+ inst.lastVal = null;
2606
+ $.datepicker._lastInput = input;
2607
+ $.datepicker._setDateFromField(inst);
2608
+
2609
+ if ($.datepicker._inDialog) { // hide cursor
2610
+ input.value = "";
2611
+ }
2612
+ if (!$.datepicker._pos) { // position below input
2613
+ $.datepicker._pos = $.datepicker._findPos(input);
2614
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
2615
+ }
2616
+
2617
+ isFixed = false;
2618
+ $(input).parents().each(function() {
2619
+ isFixed |= $(this).css("position") === "fixed";
2620
+ return !isFixed;
2621
+ });
2622
+
2623
+ offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
2624
+ $.datepicker._pos = null;
2625
+ //to avoid flashes on Firefox
2626
+ inst.dpDiv.empty();
2627
+ // determine sizing offscreen
2628
+ inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
2629
+ $.datepicker._updateDatepicker(inst);
2630
+ // fix width for dynamic number of date pickers
2631
+ // and adjust position before showing
2632
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
2633
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
2634
+ "static" : (isFixed ? "fixed" : "absolute")), display: "none",
2635
+ left: offset.left + "px", top: offset.top + "px"});
2636
+
2637
+ if (!inst.inline) {
2638
+ showAnim = $.datepicker._get(inst, "showAnim");
2639
+ duration = $.datepicker._get(inst, "duration");
2640
+ inst.dpDiv.zIndex($(input).zIndex()+1);
2641
+ $.datepicker._datepickerShowing = true;
2642
+
2643
+ if ( $.effects && $.effects.effect[ showAnim ] ) {
2644
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
2645
+ } else {
2646
+ inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
2647
+ }
2648
+
2649
+ if ( $.datepicker._shouldFocusInput( inst ) ) {
2650
+ inst.input.focus();
2651
+ }
2652
+
2653
+ $.datepicker._curInst = inst;
2654
+ }
2655
+ },
2656
+
2657
+ /* Generate the date picker content. */
2658
+ _updateDatepicker: function(inst) {
2659
+ this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
2660
+ instActive = inst; // for delegate hover events
2661
+ inst.dpDiv.empty().append(this._generateHTML(inst));
2662
+ this._attachHandlers(inst);
2663
+ inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
2664
+
2665
+ var origyearshtml,
2666
+ numMonths = this._getNumberOfMonths(inst),
2667
+ cols = numMonths[1],
2668
+ width = 17;
2669
+
2670
+ inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
2671
+ if (cols > 1) {
2672
+ inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
2673
+ }
2674
+ inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
2675
+ "Class"]("ui-datepicker-multi");
2676
+ inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
2677
+ "Class"]("ui-datepicker-rtl");
2678
+
2679
+ if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
2680
+ inst.input.focus();
2681
+ }
2682
+
2683
+ // deffered render of the years select (to avoid flashes on Firefox)
2684
+ if( inst.yearshtml ){
2685
+ origyearshtml = inst.yearshtml;
2686
+ setTimeout(function(){
2687
+ //assure that inst.yearshtml didn't change.
2688
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
2689
+ inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
2690
+ }
2691
+ origyearshtml = inst.yearshtml = null;
2692
+ }, 0);
2693
+ }
2694
+ },
2695
+
2696
+ // #6694 - don't focus the input if it's already focused
2697
+ // this breaks the change event in IE
2698
+ // Support: IE and jQuery <1.9
2699
+ _shouldFocusInput: function( inst ) {
2700
+ return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
2701
+ },
2702
+
2703
+ /* Check positioning to remain on screen. */
2704
+ _checkOffset: function(inst, offset, isFixed) {
2705
+ var dpWidth = inst.dpDiv.outerWidth(),
2706
+ dpHeight = inst.dpDiv.outerHeight(),
2707
+ inputWidth = inst.input ? inst.input.outerWidth() : 0,
2708
+ inputHeight = inst.input ? inst.input.outerHeight() : 0,
2709
+ viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
2710
+ viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
2711
+
2712
+ offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
2713
+ offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
2714
+ offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
2715
+
2716
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
2717
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
2718
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
2719
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
2720
+ Math.abs(dpHeight + inputHeight) : 0);
2721
+
2722
+ return offset;
2723
+ },
2724
+
2725
+ /* Find an object's position on the screen. */
2726
+ _findPos: function(obj) {
2727
+ var position,
2728
+ inst = this._getInst(obj),
2729
+ isRTL = this._get(inst, "isRTL");
2730
+
2731
+ while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
2732
+ obj = obj[isRTL ? "previousSibling" : "nextSibling"];
2733
+ }
2734
+
2735
+ position = $(obj).offset();
2736
+ return [position.left, position.top];
2737
+ },
2738
+
2739
+ /* Hide the date picker from view.
2740
+ * @param input element - the input field attached to the date picker
2741
+ */
2742
+ _hideDatepicker: function(input) {
2743
+ var showAnim, duration, postProcess, onClose,
2744
+ inst = this._curInst;
2745
+
2746
+ if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
2747
+ return;
2748
+ }
2749
+
2750
+ if (this._datepickerShowing) {
2751
+ showAnim = this._get(inst, "showAnim");
2752
+ duration = this._get(inst, "duration");
2753
+ postProcess = function() {
2754
+ $.datepicker._tidyDialog(inst);
2755
+ };
2756
+
2757
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
2758
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
2759
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
2760
+ } else {
2761
+ inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
2762
+ (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
2763
+ }
2764
+
2765
+ if (!showAnim) {
2766
+ postProcess();
2767
+ }
2768
+ this._datepickerShowing = false;
2769
+
2770
+ onClose = this._get(inst, "onClose");
2771
+ if (onClose) {
2772
+ onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
2773
+ }
2774
+
2775
+ this._lastInput = null;
2776
+ if (this._inDialog) {
2777
+ this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
2778
+ if ($.blockUI) {
2779
+ $.unblockUI();
2780
+ $("body").append(this.dpDiv);
2781
+ }
2782
+ }
2783
+ this._inDialog = false;
2784
+ }
2785
+ },
2786
+
2787
+ /* Tidy up after a dialog display. */
2788
+ _tidyDialog: function(inst) {
2789
+ inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
2790
+ },
2791
+
2792
+ /* Close date picker if clicked elsewhere. */
2793
+ _checkExternalClick: function(event) {
2794
+ if (!$.datepicker._curInst) {
2795
+ return;
2796
+ }
2797
+
2798
+ var $target = $(event.target),
2799
+ inst = $.datepicker._getInst($target[0]);
2800
+
2801
+ if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
2802
+ $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
2803
+ !$target.hasClass($.datepicker.markerClassName) &&
2804
+ !$target.closest("." + $.datepicker._triggerClass).length &&
2805
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
2806
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
2807
+ $.datepicker._hideDatepicker();
2808
+ }
2809
+ },
2810
+
2811
+ /* Adjust one of the date sub-fields. */
2812
+ _adjustDate: function(id, offset, period) {
2813
+ var target = $(id),
2814
+ inst = this._getInst(target[0]);
2815
+
2816
+ if (this._isDisabledDatepicker(target[0])) {
2817
+ return;
2818
+ }
2819
+ this._adjustInstDate(inst, offset +
2820
+ (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
2821
+ period);
2822
+ this._updateDatepicker(inst);
2823
+ },
2824
+
2825
+ /* Action for current link. */
2826
+ _gotoToday: function(id) {
2827
+ var date,
2828
+ target = $(id),
2829
+ inst = this._getInst(target[0]);
2830
+
2831
+ if (this._get(inst, "gotoCurrent") && inst.currentDay) {
2832
+ inst.selectedDay = inst.currentDay;
2833
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
2834
+ inst.drawYear = inst.selectedYear = inst.currentYear;
2835
+ } else {
2836
+ date = new Date();
2837
+ inst.selectedDay = date.getDate();
2838
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
2839
+ inst.drawYear = inst.selectedYear = date.getFullYear();
2840
+ }
2841
+ this._notifyChange(inst);
2842
+ this._adjustDate(target);
2843
+ },
2844
+
2845
+ /* Action for selecting a new month/year. */
2846
+ _selectMonthYear: function(id, select, period) {
2847
+ var target = $(id),
2848
+ inst = this._getInst(target[0]);
2849
+
2850
+ inst["selected" + (period === "M" ? "Month" : "Year")] =
2851
+ inst["draw" + (period === "M" ? "Month" : "Year")] =
2852
+ parseInt(select.options[select.selectedIndex].value,10);
2853
+
2854
+ this._notifyChange(inst);
2855
+ this._adjustDate(target);
2856
+ },
2857
+
2858
+ /* Action for selecting a day. */
2859
+ _selectDay: function(id, month, year, td) {
2860
+ var inst,
2861
+ target = $(id);
2862
+
2863
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
2864
+ return;
2865
+ }
2866
+
2867
+ inst = this._getInst(target[0]);
2868
+ inst.selectedDay = inst.currentDay = $("a", td).html();
2869
+ inst.selectedMonth = inst.currentMonth = month;
2870
+ inst.selectedYear = inst.currentYear = year;
2871
+ this._selectDate(id, this._formatDate(inst,
2872
+ inst.currentDay, inst.currentMonth, inst.currentYear));
2873
+ },
2874
+
2875
+ /* Erase the input field and hide the date picker. */
2876
+ _clearDate: function(id) {
2877
+ var target = $(id);
2878
+ this._selectDate(target, "");
2879
+ },
2880
+
2881
+ /* Update the input field with the selected date. */
2882
+ _selectDate: function(id, dateStr) {
2883
+ var onSelect,
2884
+ target = $(id),
2885
+ inst = this._getInst(target[0]);
2886
+
2887
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
2888
+ if (inst.input) {
2889
+ inst.input.val(dateStr);
2890
+ }
2891
+ this._updateAlternate(inst);
2892
+
2893
+ onSelect = this._get(inst, "onSelect");
2894
+ if (onSelect) {
2895
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
2896
+ } else if (inst.input) {
2897
+ inst.input.trigger("change"); // fire the change event
2898
+ }
2899
+
2900
+ if (inst.inline){
2901
+ this._updateDatepicker(inst);
2902
+ } else {
2903
+ this._hideDatepicker();
2904
+ this._lastInput = inst.input[0];
2905
+ if (typeof(inst.input[0]) !== "object") {
2906
+ inst.input.focus(); // restore focus
2907
+ }
2908
+ this._lastInput = null;
2909
+ }
2910
+ },
2911
+
2912
+ /* Update any alternate field to synchronise with the main field. */
2913
+ _updateAlternate: function(inst) {
2914
+ var altFormat, date, dateStr,
2915
+ altField = this._get(inst, "altField");
2916
+
2917
+ if (altField) { // update alternate field too
2918
+ altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
2919
+ date = this._getDate(inst);
2920
+ dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
2921
+ $(altField).each(function() { $(this).val(dateStr); });
2922
+ }
2923
+ },
2924
+
2925
+ /* Set as beforeShowDay function to prevent selection of weekends.
2926
+ * @param date Date - the date to customise
2927
+ * @return [boolean, string] - is this date selectable?, what is its CSS class?
2928
+ */
2929
+ noWeekends: function(date) {
2930
+ var day = date.getDay();
2931
+ return [(day > 0 && day < 6), ""];
2932
+ },
2933
+
2934
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
2935
+ * @param date Date - the date to get the week for
2936
+ * @return number - the number of the week within the year that contains this date
2937
+ */
2938
+ iso8601Week: function(date) {
2939
+ var time,
2940
+ checkDate = new Date(date.getTime());
2941
+
2942
+ // Find Thursday of this week starting on Monday
2943
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
2944
+
2945
+ time = checkDate.getTime();
2946
+ checkDate.setMonth(0); // Compare with Jan 1
2947
+ checkDate.setDate(1);
2948
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
2949
+ },
2950
+
2951
+ /* Parse a string value into a date object.
2952
+ * See formatDate below for the possible formats.
2953
+ *
2954
+ * @param format string - the expected format of the date
2955
+ * @param value string - the date in the above format
2956
+ * @param settings Object - attributes include:
2957
+ * shortYearCutoff number - the cutoff year for determining the century (optional)
2958
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
2959
+ * dayNames string[7] - names of the days from Sunday (optional)
2960
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
2961
+ * monthNames string[12] - names of the months (optional)
2962
+ * @return Date - the extracted date value or null if value is blank
2963
+ */
2964
+ parseDate: function (format, value, settings) {
2965
+ if (format == null || value == null) {
2966
+ throw "Invalid arguments";
2967
+ }
2968
+
2969
+ value = (typeof value === "object" ? value.toString() : value + "");
2970
+ if (value === "") {
2971
+ return null;
2972
+ }
2973
+
2974
+ var iFormat, dim, extra,
2975
+ iValue = 0,
2976
+ shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
2977
+ shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
2978
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
2979
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
2980
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
2981
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
2982
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
2983
+ year = -1,
2984
+ month = -1,
2985
+ day = -1,
2986
+ doy = -1,
2987
+ literal = false,
2988
+ date,
2989
+ // Check whether a format character is doubled
2990
+ lookAhead = function(match) {
2991
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
2992
+ if (matches) {
2993
+ iFormat++;
2994
+ }
2995
+ return matches;
2996
+ },
2997
+ // Extract a number from the string value
2998
+ getNumber = function(match) {
2999
+ var isDoubled = lookAhead(match),
3000
+ size = (match === "@" ? 14 : (match === "!" ? 20 :
3001
+ (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
3002
+ digits = new RegExp("^\\d{1," + size + "}"),
3003
+ num = value.substring(iValue).match(digits);
3004
+ if (!num) {
3005
+ throw "Missing number at position " + iValue;
3006
+ }
3007
+ iValue += num[0].length;
3008
+ return parseInt(num[0], 10);
3009
+ },
3010
+ // Extract a name from the string value and convert to an index
3011
+ getName = function(match, shortNames, longNames) {
3012
+ var index = -1,
3013
+ names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
3014
+ return [ [k, v] ];
3015
+ }).sort(function (a, b) {
3016
+ return -(a[1].length - b[1].length);
3017
+ });
3018
+
3019
+ $.each(names, function (i, pair) {
3020
+ var name = pair[1];
3021
+ if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
3022
+ index = pair[0];
3023
+ iValue += name.length;
3024
+ return false;
3025
+ }
3026
+ });
3027
+ if (index !== -1) {
3028
+ return index + 1;
3029
+ } else {
3030
+ throw "Unknown name at position " + iValue;
3031
+ }
3032
+ },
3033
+ // Confirm that a literal character matches the string value
3034
+ checkLiteral = function() {
3035
+ if (value.charAt(iValue) !== format.charAt(iFormat)) {
3036
+ throw "Unexpected literal at position " + iValue;
3037
+ }
3038
+ iValue++;
3039
+ };
3040
+
3041
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
3042
+ if (literal) {
3043
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
3044
+ literal = false;
3045
+ } else {
3046
+ checkLiteral();
3047
+ }
3048
+ } else {
3049
+ switch (format.charAt(iFormat)) {
3050
+ case "d":
3051
+ day = getNumber("d");
3052
+ break;
3053
+ case "D":
3054
+ getName("D", dayNamesShort, dayNames);
3055
+ break;
3056
+ case "o":
3057
+ doy = getNumber("o");
3058
+ break;
3059
+ case "m":
3060
+ month = getNumber("m");
3061
+ break;
3062
+ case "M":
3063
+ month = getName("M", monthNamesShort, monthNames);
3064
+ break;
3065
+ case "y":
3066
+ year = getNumber("y");
3067
+ break;
3068
+ case "@":
3069
+ date = new Date(getNumber("@"));
3070
+ year = date.getFullYear();
3071
+ month = date.getMonth() + 1;
3072
+ day = date.getDate();
3073
+ break;
3074
+ case "!":
3075
+ date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
3076
+ year = date.getFullYear();
3077
+ month = date.getMonth() + 1;
3078
+ day = date.getDate();
3079
+ break;
3080
+ case "'":
3081
+ if (lookAhead("'")){
3082
+ checkLiteral();
3083
+ } else {
3084
+ literal = true;
3085
+ }
3086
+ break;
3087
+ default:
3088
+ checkLiteral();
3089
+ }
3090
+ }
3091
+ }
3092
+
3093
+ if (iValue < value.length){
3094
+ extra = value.substr(iValue);
3095
+ if (!/^\s+/.test(extra)) {
3096
+ throw "Extra/unparsed characters found in date: " + extra;
3097
+ }
3098
+ }
3099
+
3100
+ if (year === -1) {
3101
+ year = new Date().getFullYear();
3102
+ } else if (year < 100) {
3103
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
3104
+ (year <= shortYearCutoff ? 0 : -100);
3105
+ }
3106
+
3107
+ if (doy > -1) {
3108
+ month = 1;
3109
+ day = doy;
3110
+ do {
3111
+ dim = this._getDaysInMonth(year, month - 1);
3112
+ if (day <= dim) {
3113
+ break;
3114
+ }
3115
+ month++;
3116
+ day -= dim;
3117
+ } while (true);
3118
+ }
3119
+
3120
+ date = this._daylightSavingAdjust(new Date(year, month - 1, day));
3121
+ if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
3122
+ throw "Invalid date"; // E.g. 31/02/00
3123
+ }
3124
+ return date;
3125
+ },
3126
+
3127
+ /* Standard date formats. */
3128
+ ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
3129
+ COOKIE: "D, dd M yy",
3130
+ ISO_8601: "yy-mm-dd",
3131
+ RFC_822: "D, d M y",
3132
+ RFC_850: "DD, dd-M-y",
3133
+ RFC_1036: "D, d M y",
3134
+ RFC_1123: "D, d M yy",
3135
+ RFC_2822: "D, d M yy",
3136
+ RSS: "D, d M y", // RFC 822
3137
+ TICKS: "!",
3138
+ TIMESTAMP: "@",
3139
+ W3C: "yy-mm-dd", // ISO 8601
3140
+
3141
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
3142
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
3143
+
3144
+ /* Format a date object into a string value.
3145
+ * The format can be combinations of the following:
3146
+ * d - day of month (no leading zero)
3147
+ * dd - day of month (two digit)
3148
+ * o - day of year (no leading zeros)
3149
+ * oo - day of year (three digit)
3150
+ * D - day name short
3151
+ * DD - day name long
3152
+ * m - month of year (no leading zero)
3153
+ * mm - month of year (two digit)
3154
+ * M - month name short
3155
+ * MM - month name long
3156
+ * y - year (two digit)
3157
+ * yy - year (four digit)
3158
+ * @ - Unix timestamp (ms since 01/01/1970)
3159
+ * ! - Windows ticks (100ns since 01/01/0001)
3160
+ * "..." - literal text
3161
+ * '' - single quote
3162
+ *
3163
+ * @param format string - the desired format of the date
3164
+ * @param date Date - the date value to format
3165
+ * @param settings Object - attributes include:
3166
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
3167
+ * dayNames string[7] - names of the days from Sunday (optional)
3168
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
3169
+ * monthNames string[12] - names of the months (optional)
3170
+ * @return string - the date in the above format
3171
+ */
3172
+ formatDate: function (format, date, settings) {
3173
+ if (!date) {
3174
+ return "";
3175
+ }
3176
+
3177
+ var iFormat,
3178
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
3179
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
3180
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
3181
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
3182
+ // Check whether a format character is doubled
3183
+ lookAhead = function(match) {
3184
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
3185
+ if (matches) {
3186
+ iFormat++;
3187
+ }
3188
+ return matches;
3189
+ },
3190
+ // Format a number, with leading zero if necessary
3191
+ formatNumber = function(match, value, len) {
3192
+ var num = "" + value;
3193
+ if (lookAhead(match)) {
3194
+ while (num.length < len) {
3195
+ num = "0" + num;
3196
+ }
3197
+ }
3198
+ return num;
3199
+ },
3200
+ // Format a name, short or long as requested
3201
+ formatName = function(match, value, shortNames, longNames) {
3202
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
3203
+ },
3204
+ output = "",
3205
+ literal = false;
3206
+
3207
+ if (date) {
3208
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
3209
+ if (literal) {
3210
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
3211
+ literal = false;
3212
+ } else {
3213
+ output += format.charAt(iFormat);
3214
+ }
3215
+ } else {
3216
+ switch (format.charAt(iFormat)) {
3217
+ case "d":
3218
+ output += formatNumber("d", date.getDate(), 2);
3219
+ break;
3220
+ case "D":
3221
+ output += formatName("D", date.getDay(), dayNamesShort, dayNames);
3222
+ break;
3223
+ case "o":
3224
+ output += formatNumber("o",
3225
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
3226
+ break;
3227
+ case "m":
3228
+ output += formatNumber("m", date.getMonth() + 1, 2);
3229
+ break;
3230
+ case "M":
3231
+ output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
3232
+ break;
3233
+ case "y":
3234
+ output += (lookAhead("y") ? date.getFullYear() :
3235
+ (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
3236
+ break;
3237
+ case "@":
3238
+ output += date.getTime();
3239
+ break;
3240
+ case "!":
3241
+ output += date.getTime() * 10000 + this._ticksTo1970;
3242
+ break;
3243
+ case "'":
3244
+ if (lookAhead("'")) {
3245
+ output += "'";
3246
+ } else {
3247
+ literal = true;
3248
+ }
3249
+ break;
3250
+ default:
3251
+ output += format.charAt(iFormat);
3252
+ }
3253
+ }
3254
+ }
3255
+ }
3256
+ return output;
3257
+ },
3258
+
3259
+ /* Extract all possible characters from the date format. */
3260
+ _possibleChars: function (format) {
3261
+ var iFormat,
3262
+ chars = "",
3263
+ literal = false,
3264
+ // Check whether a format character is doubled
3265
+ lookAhead = function(match) {
3266
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
3267
+ if (matches) {
3268
+ iFormat++;
3269
+ }
3270
+ return matches;
3271
+ };
3272
+
3273
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
3274
+ if (literal) {
3275
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
3276
+ literal = false;
3277
+ } else {
3278
+ chars += format.charAt(iFormat);
3279
+ }
3280
+ } else {
3281
+ switch (format.charAt(iFormat)) {
3282
+ case "d": case "m": case "y": case "@":
3283
+ chars += "0123456789";
3284
+ break;
3285
+ case "D": case "M":
3286
+ return null; // Accept anything
3287
+ case "'":
3288
+ if (lookAhead("'")) {
3289
+ chars += "'";
3290
+ } else {
3291
+ literal = true;
3292
+ }
3293
+ break;
3294
+ default:
3295
+ chars += format.charAt(iFormat);
3296
+ }
3297
+ }
3298
+ }
3299
+ return chars;
3300
+ },
3301
+
3302
+ /* Get a setting value, defaulting if necessary. */
3303
+ _get: function(inst, name) {
3304
+ return inst.settings[name] !== undefined ?
3305
+ inst.settings[name] : this._defaults[name];
3306
+ },
3307
+
3308
+ /* Parse existing date and initialise date picker. */
3309
+ _setDateFromField: function(inst, noDefault) {
3310
+ if (inst.input.val() === inst.lastVal) {
3311
+ return;
3312
+ }
3313
+
3314
+ var dateFormat = this._get(inst, "dateFormat"),
3315
+ dates = inst.lastVal = inst.input ? inst.input.val() : null,
3316
+ defaultDate = this._getDefaultDate(inst),
3317
+ date = defaultDate,
3318
+ settings = this._getFormatConfig(inst);
3319
+
3320
+ try {
3321
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
3322
+ } catch (event) {
3323
+ dates = (noDefault ? "" : dates);
3324
+ }
3325
+ inst.selectedDay = date.getDate();
3326
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
3327
+ inst.drawYear = inst.selectedYear = date.getFullYear();
3328
+ inst.currentDay = (dates ? date.getDate() : 0);
3329
+ inst.currentMonth = (dates ? date.getMonth() : 0);
3330
+ inst.currentYear = (dates ? date.getFullYear() : 0);
3331
+ this._adjustInstDate(inst);
3332
+ },
3333
+
3334
+ /* Retrieve the default date shown on opening. */
3335
+ _getDefaultDate: function(inst) {
3336
+ return this._restrictMinMax(inst,
3337
+ this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
3338
+ },
3339
+
3340
+ /* A date may be specified as an exact value or a relative one. */
3341
+ _determineDate: function(inst, date, defaultDate) {
3342
+ var offsetNumeric = function(offset) {
3343
+ var date = new Date();
3344
+ date.setDate(date.getDate() + offset);
3345
+ return date;
3346
+ },
3347
+ offsetString = function(offset) {
3348
+ try {
3349
+ return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
3350
+ offset, $.datepicker._getFormatConfig(inst));
3351
+ }
3352
+ catch (e) {
3353
+ // Ignore
3354
+ }
3355
+
3356
+ var date = (offset.toLowerCase().match(/^c/) ?
3357
+ $.datepicker._getDate(inst) : null) || new Date(),
3358
+ year = date.getFullYear(),
3359
+ month = date.getMonth(),
3360
+ day = date.getDate(),
3361
+ pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
3362
+ matches = pattern.exec(offset);
3363
+
3364
+ while (matches) {
3365
+ switch (matches[2] || "d") {
3366
+ case "d" : case "D" :
3367
+ day += parseInt(matches[1],10); break;
3368
+ case "w" : case "W" :
3369
+ day += parseInt(matches[1],10) * 7; break;
3370
+ case "m" : case "M" :
3371
+ month += parseInt(matches[1],10);
3372
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
3373
+ break;
3374
+ case "y": case "Y" :
3375
+ year += parseInt(matches[1],10);
3376
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
3377
+ break;
3378
+ }
3379
+ matches = pattern.exec(offset);
3380
+ }
3381
+ return new Date(year, month, day);
3382
+ },
3383
+ newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
3384
+ (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
3385
+
3386
+ newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
3387
+ if (newDate) {
3388
+ newDate.setHours(0);
3389
+ newDate.setMinutes(0);
3390
+ newDate.setSeconds(0);
3391
+ newDate.setMilliseconds(0);
3392
+ }
3393
+ return this._daylightSavingAdjust(newDate);
3394
+ },
3395
+
3396
+ /* Handle switch to/from daylight saving.
3397
+ * Hours may be non-zero on daylight saving cut-over:
3398
+ * > 12 when midnight changeover, but then cannot generate
3399
+ * midnight datetime, so jump to 1AM, otherwise reset.
3400
+ * @param date (Date) the date to check
3401
+ * @return (Date) the corrected date
3402
+ */
3403
+ _daylightSavingAdjust: function(date) {
3404
+ if (!date) {
3405
+ return null;
3406
+ }
3407
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
3408
+ return date;
3409
+ },
3410
+
3411
+ /* Set the date(s) directly. */
3412
+ _setDate: function(inst, date, noChange) {
3413
+ var clear = !date,
3414
+ origMonth = inst.selectedMonth,
3415
+ origYear = inst.selectedYear,
3416
+ newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
3417
+
3418
+ inst.selectedDay = inst.currentDay = newDate.getDate();
3419
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
3420
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
3421
+ if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
3422
+ this._notifyChange(inst);
3423
+ }
3424
+ this._adjustInstDate(inst);
3425
+ if (inst.input) {
3426
+ inst.input.val(clear ? "" : this._formatDate(inst));
3427
+ }
3428
+ },
3429
+
3430
+ /* Retrieve the date(s) directly. */
3431
+ _getDate: function(inst) {
3432
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
3433
+ this._daylightSavingAdjust(new Date(
3434
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
3435
+ return startDate;
3436
+ },
3437
+
3438
+ /* Attach the onxxx handlers. These are declared statically so
3439
+ * they work with static code transformers like Caja.
3440
+ */
3441
+ _attachHandlers: function(inst) {
3442
+ var stepMonths = this._get(inst, "stepMonths"),
3443
+ id = "#" + inst.id.replace( /\\\\/g, "\\" );
3444
+ inst.dpDiv.find("[data-handler]").map(function () {
3445
+ var handler = {
3446
+ prev: function () {
3447
+ $.datepicker._adjustDate(id, -stepMonths, "M");
3448
+ },
3449
+ next: function () {
3450
+ $.datepicker._adjustDate(id, +stepMonths, "M");
3451
+ },
3452
+ hide: function () {
3453
+ $.datepicker._hideDatepicker();
3454
+ },
3455
+ today: function () {
3456
+ $.datepicker._gotoToday(id);
3457
+ },
3458
+ selectDay: function () {
3459
+ $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
3460
+ return false;
3461
+ },
3462
+ selectMonth: function () {
3463
+ $.datepicker._selectMonthYear(id, this, "M");
3464
+ return false;
3465
+ },
3466
+ selectYear: function () {
3467
+ $.datepicker._selectMonthYear(id, this, "Y");
3468
+ return false;
3469
+ }
3470
+ };
3471
+ $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
3472
+ });
3473
+ },
3474
+
3475
+ /* Generate the HTML for the current state of the date picker. */
3476
+ _generateHTML: function(inst) {
3477
+ var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
3478
+ controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
3479
+ monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
3480
+ selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
3481
+ cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
3482
+ printDate, dRow, tbody, daySettings, otherMonth, unselectable,
3483
+ tempDate = new Date(),
3484
+ today = this._daylightSavingAdjust(
3485
+ new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
3486
+ isRTL = this._get(inst, "isRTL"),
3487
+ showButtonPanel = this._get(inst, "showButtonPanel"),
3488
+ hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
3489
+ navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
3490
+ numMonths = this._getNumberOfMonths(inst),
3491
+ showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
3492
+ stepMonths = this._get(inst, "stepMonths"),
3493
+ isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
3494
+ currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
3495
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
3496
+ minDate = this._getMinMaxDate(inst, "min"),
3497
+ maxDate = this._getMinMaxDate(inst, "max"),
3498
+ drawMonth = inst.drawMonth - showCurrentAtPos,
3499
+ drawYear = inst.drawYear;
3500
+
3501
+ if (drawMonth < 0) {
3502
+ drawMonth += 12;
3503
+ drawYear--;
3504
+ }
3505
+ if (maxDate) {
3506
+ maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
3507
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
3508
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
3509
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
3510
+ drawMonth--;
3511
+ if (drawMonth < 0) {
3512
+ drawMonth = 11;
3513
+ drawYear--;
3514
+ }
3515
+ }
3516
+ }
3517
+ inst.drawMonth = drawMonth;
3518
+ inst.drawYear = drawYear;
3519
+
3520
+ prevText = this._get(inst, "prevText");
3521
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
3522
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
3523
+ this._getFormatConfig(inst)));
3524
+
3525
+ prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
3526
+ "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
3527
+ " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
3528
+ (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>"));
3529
+
3530
+ nextText = this._get(inst, "nextText");
3531
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
3532
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
3533
+ this._getFormatConfig(inst)));
3534
+
3535
+ next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
3536
+ "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
3537
+ " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
3538
+ (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>"));
3539
+
3540
+ currentText = this._get(inst, "currentText");
3541
+ gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
3542
+ currentText = (!navigationAsDateFormat ? currentText :
3543
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
3544
+
3545
+ 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'>" +
3546
+ this._get(inst, "closeText") + "</button>" : "");
3547
+
3548
+ buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
3549
+ (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'" +
3550
+ ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
3551
+
3552
+ firstDay = parseInt(this._get(inst, "firstDay"),10);
3553
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
3554
+
3555
+ showWeek = this._get(inst, "showWeek");
3556
+ dayNames = this._get(inst, "dayNames");
3557
+ dayNamesMin = this._get(inst, "dayNamesMin");
3558
+ monthNames = this._get(inst, "monthNames");
3559
+ monthNamesShort = this._get(inst, "monthNamesShort");
3560
+ beforeShowDay = this._get(inst, "beforeShowDay");
3561
+ showOtherMonths = this._get(inst, "showOtherMonths");
3562
+ selectOtherMonths = this._get(inst, "selectOtherMonths");
3563
+ defaultDate = this._getDefaultDate(inst);
3564
+ html = "";
3565
+ dow;
3566
+ for (row = 0; row < numMonths[0]; row++) {
3567
+ group = "";
3568
+ this.maxRows = 4;
3569
+ for (col = 0; col < numMonths[1]; col++) {
3570
+ selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
3571
+ cornerClass = " ui-corner-all";
3572
+ calender = "";
3573
+ if (isMultiMonth) {
3574
+ calender += "<div class='ui-datepicker-group";
3575
+ if (numMonths[1] > 1) {
3576
+ switch (col) {
3577
+ case 0: calender += " ui-datepicker-group-first";
3578
+ cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
3579
+ case numMonths[1]-1: calender += " ui-datepicker-group-last";
3580
+ cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
3581
+ default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
3582
+ }
3583
+ }
3584
+ calender += "'>";
3585
+ }
3586
+ calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
3587
+ (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
3588
+ (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
3589
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
3590
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
3591
+ "</div><table class='ui-datepicker-calendar'><thead>" +
3592
+ "<tr>";
3593
+ thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
3594
+ for (dow = 0; dow < 7; dow++) { // days of the week
3595
+ day = (dow + firstDay) % 7;
3596
+ thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
3597
+ "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
3598
+ }
3599
+ calender += thead + "</tr></thead><tbody>";
3600
+ daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
3601
+ if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
3602
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
3603
+ }
3604
+ leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
3605
+ curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
3606
+ numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
3607
+ this.maxRows = numRows;
3608
+ printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
3609
+ for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
3610
+ calender += "<tr>";
3611
+ tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
3612
+ this._get(inst, "calculateWeek")(printDate) + "</td>");
3613
+ for (dow = 0; dow < 7; dow++) { // create date picker days
3614
+ daySettings = (beforeShowDay ?
3615
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
3616
+ otherMonth = (printDate.getMonth() !== drawMonth);
3617
+ unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
3618
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
3619
+ tbody += "<td class='" +
3620
+ ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
3621
+ (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
3622
+ ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
3623
+ (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
3624
+ // or defaultDate is current printedDate and defaultDate is selectedDate
3625
+ " " + this._dayOverClass : "") + // highlight selected day
3626
+ (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
3627
+ (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
3628
+ (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
3629
+ (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
3630
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
3631
+ (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
3632
+ (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
3633
+ (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
3634
+ (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
3635
+ (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
3636
+ (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
3637
+ "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
3638
+ printDate.setDate(printDate.getDate() + 1);
3639
+ printDate = this._daylightSavingAdjust(printDate);
3640
+ }
3641
+ calender += tbody + "</tr>";
3642
+ }
3643
+ drawMonth++;
3644
+ if (drawMonth > 11) {
3645
+ drawMonth = 0;
3646
+ drawYear++;
3647
+ }
3648
+ calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
3649
+ ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
3650
+ group += calender;
3651
+ }
3652
+ html += group;
3653
+ }
3654
+ html += buttonPanel;
3655
+ inst._keyEvent = false;
3656
+ return html;
3657
+ },
3658
+
3659
+ /* Generate the month and year header. */
3660
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
3661
+ secondary, monthNames, monthNamesShort) {
3662
+
3663
+ var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
3664
+ changeMonth = this._get(inst, "changeMonth"),
3665
+ changeYear = this._get(inst, "changeYear"),
3666
+ showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
3667
+ html = "<div class='ui-datepicker-title'>",
3668
+ monthHtml = "";
3669
+
3670
+ // month selection
3671
+ if (secondary || !changeMonth) {
3672
+ monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
3673
+ } else {
3674
+ inMinYear = (minDate && minDate.getFullYear() === drawYear);
3675
+ inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
3676
+ monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
3677
+ for ( month = 0; month < 12; month++) {
3678
+ if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
3679
+ monthHtml += "<option value='" + month + "'" +
3680
+ (month === drawMonth ? " selected='selected'" : "") +
3681
+ ">" + monthNamesShort[month] + "</option>";
3682
+ }
3683
+ }
3684
+ monthHtml += "</select>";
3685
+ }
3686
+
3687
+ if (!showMonthAfterYear) {
3688
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
3689
+ }
3690
+
3691
+ // year selection
3692
+ if ( !inst.yearshtml ) {
3693
+ inst.yearshtml = "";
3694
+ if (secondary || !changeYear) {
3695
+ html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
3696
+ } else {
3697
+ // determine range of years to display
3698
+ years = this._get(inst, "yearRange").split(":");
3699
+ thisYear = new Date().getFullYear();
3700
+ determineYear = function(value) {
3701
+ var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
3702
+ (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
3703
+ parseInt(value, 10)));
3704
+ return (isNaN(year) ? thisYear : year);
3705
+ };
3706
+ year = determineYear(years[0]);
3707
+ endYear = Math.max(year, determineYear(years[1] || ""));
3708
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
3709
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
3710
+ inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
3711
+ for (; year <= endYear; year++) {
3712
+ inst.yearshtml += "<option value='" + year + "'" +
3713
+ (year === drawYear ? " selected='selected'" : "") +
3714
+ ">" + year + "</option>";
3715
+ }
3716
+ inst.yearshtml += "</select>";
3717
+
3718
+ html += inst.yearshtml;
3719
+ inst.yearshtml = null;
3720
+ }
3721
+ }
3722
+
3723
+ html += this._get(inst, "yearSuffix");
3724
+ if (showMonthAfterYear) {
3725
+ html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
3726
+ }
3727
+ html += "</div>"; // Close datepicker_header
3728
+ return html;
3729
+ },
3730
+
3731
+ /* Adjust one of the date sub-fields. */
3732
+ _adjustInstDate: function(inst, offset, period) {
3733
+ var year = inst.drawYear + (period === "Y" ? offset : 0),
3734
+ month = inst.drawMonth + (period === "M" ? offset : 0),
3735
+ day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
3736
+ date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
3737
+
3738
+ inst.selectedDay = date.getDate();
3739
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
3740
+ inst.drawYear = inst.selectedYear = date.getFullYear();
3741
+ if (period === "M" || period === "Y") {
3742
+ this._notifyChange(inst);
3743
+ }
3744
+ },
3745
+
3746
+ /* Ensure a date is within any min/max bounds. */
3747
+ _restrictMinMax: function(inst, date) {
3748
+ var minDate = this._getMinMaxDate(inst, "min"),
3749
+ maxDate = this._getMinMaxDate(inst, "max"),
3750
+ newDate = (minDate && date < minDate ? minDate : date);
3751
+ return (maxDate && newDate > maxDate ? maxDate : newDate);
3752
+ },
3753
+
3754
+ /* Notify change of month/year. */
3755
+ _notifyChange: function(inst) {
3756
+ var onChange = this._get(inst, "onChangeMonthYear");
3757
+ if (onChange) {
3758
+ onChange.apply((inst.input ? inst.input[0] : null),
3759
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
3760
+ }
3761
+ },
3762
+
3763
+ /* Determine the number of months to show. */
3764
+ _getNumberOfMonths: function(inst) {
3765
+ var numMonths = this._get(inst, "numberOfMonths");
3766
+ return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
3767
+ },
3768
+
3769
+ /* Determine the current maximum date - ensure no time components are set. */
3770
+ _getMinMaxDate: function(inst, minMax) {
3771
+ return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
3772
+ },
3773
+
3774
+ /* Find the number of days in a given month. */
3775
+ _getDaysInMonth: function(year, month) {
3776
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
3777
+ },
3778
+
3779
+ /* Find the day of the week of the first of a month. */
3780
+ _getFirstDayOfMonth: function(year, month) {
3781
+ return new Date(year, month, 1).getDay();
3782
+ },
3783
+
3784
+ /* Determines if we should allow a "next/prev" month display change. */
3785
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
3786
+ var numMonths = this._getNumberOfMonths(inst),
3787
+ date = this._daylightSavingAdjust(new Date(curYear,
3788
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
3789
+
3790
+ if (offset < 0) {
3791
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
3792
+ }
3793
+ return this._isInRange(inst, date);
3794
+ },
3795
+
3796
+ /* Is the given date in the accepted range? */
3797
+ _isInRange: function(inst, date) {
3798
+ var yearSplit, currentYear,
3799
+ minDate = this._getMinMaxDate(inst, "min"),
3800
+ maxDate = this._getMinMaxDate(inst, "max"),
3801
+ minYear = null,
3802
+ maxYear = null,
3803
+ years = this._get(inst, "yearRange");
3804
+ if (years){
3805
+ yearSplit = years.split(":");
3806
+ currentYear = new Date().getFullYear();
3807
+ minYear = parseInt(yearSplit[0], 10);
3808
+ maxYear = parseInt(yearSplit[1], 10);
3809
+ if ( yearSplit[0].match(/[+\-].*/) ) {
3810
+ minYear += currentYear;
3811
+ }
3812
+ if ( yearSplit[1].match(/[+\-].*/) ) {
3813
+ maxYear += currentYear;
3814
+ }
3815
+ }
3816
+
3817
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
3818
+ (!maxDate || date.getTime() <= maxDate.getTime()) &&
3819
+ (!minYear || date.getFullYear() >= minYear) &&
3820
+ (!maxYear || date.getFullYear() <= maxYear));
3821
+ },
3822
+
3823
+ /* Provide the configuration settings for formatting/parsing. */
3824
+ _getFormatConfig: function(inst) {
3825
+ var shortYearCutoff = this._get(inst, "shortYearCutoff");
3826
+ shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
3827
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
3828
+ return {shortYearCutoff: shortYearCutoff,
3829
+ dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
3830
+ monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
3831
+ },
3832
+
3833
+ /* Format the given date for display. */
3834
+ _formatDate: function(inst, day, month, year) {
3835
+ if (!day) {
3836
+ inst.currentDay = inst.selectedDay;
3837
+ inst.currentMonth = inst.selectedMonth;
3838
+ inst.currentYear = inst.selectedYear;
3839
+ }
3840
+ var date = (day ? (typeof day === "object" ? day :
3841
+ this._daylightSavingAdjust(new Date(year, month, day))) :
3842
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
3843
+ return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
3844
+ }
3845
+ });
3846
+
3847
+ /*
3848
+ * Bind hover events for datepicker elements.
3849
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
3850
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
3851
+ */
3852
+ function bindHover(dpDiv) {
3853
+ var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
3854
+ return dpDiv.delegate(selector, "mouseout", function() {
3855
+ $(this).removeClass("ui-state-hover");
3856
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
3857
+ $(this).removeClass("ui-datepicker-prev-hover");
3858
+ }
3859
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
3860
+ $(this).removeClass("ui-datepicker-next-hover");
3861
+ }
3862
+ })
3863
+ .delegate(selector, "mouseover", function(){
3864
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
3865
+ $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
3866
+ $(this).addClass("ui-state-hover");
3867
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
3868
+ $(this).addClass("ui-datepicker-prev-hover");
3869
+ }
3870
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
3871
+ $(this).addClass("ui-datepicker-next-hover");
3872
+ }
3873
+ }
3874
+ });
3875
+ }
3876
+
3877
+ /* jQuery extend now ignores nulls! */
3878
+ function extendRemove(target, props) {
3879
+ $.extend(target, props);
3880
+ for (var name in props) {
3881
+ if (props[name] == null) {
3882
+ target[name] = props[name];
3883
+ }
3884
+ }
3885
+ return target;
3886
+ }
3887
+
3888
+ /* Invoke the datepicker functionality.
3889
+ @param options string - a command, optionally followed by additional parameters or
3890
+ Object - settings for attaching new datepicker functionality
3891
+ @return jQuery object */
3892
+ $.fn.datepicker = function(options){
3893
+
3894
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
3895
+ if ( !this.length ) {
3896
+ return this;
3897
+ }
3898
+
3899
+ /* Initialise the date picker. */
3900
+ if (!$.datepicker.initialized) {
3901
+ $(document).mousedown($.datepicker._checkExternalClick);
3902
+ $.datepicker.initialized = true;
3903
+ }
3904
+
3905
+ /* Append datepicker main container to body if not exist. */
3906
+ if ($("#"+$.datepicker._mainDivId).length === 0) {
3907
+ $("body").append($.datepicker.dpDiv);
3908
+ }
3909
+
3910
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
3911
+ if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
3912
+ return $.datepicker["_" + options + "Datepicker"].
3913
+ apply($.datepicker, [this[0]].concat(otherArgs));
3914
+ }
3915
+ if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
3916
+ return $.datepicker["_" + options + "Datepicker"].
3917
+ apply($.datepicker, [this[0]].concat(otherArgs));
3918
+ }
3919
+ return this.each(function() {
3920
+ typeof options === "string" ?
3921
+ $.datepicker["_" + options + "Datepicker"].
3922
+ apply($.datepicker, [this].concat(otherArgs)) :
3923
+ $.datepicker._attachDatepicker(this, options);
3924
+ });
3925
+ };
3926
+
3927
+ $.datepicker = new Datepicker(); // singleton instance
3928
+ $.datepicker.initialized = false;
3929
+ $.datepicker.uuid = new Date().getTime();
3930
+ $.datepicker.version = "1.10.3";
3931
+
3932
+ })(jQuery);
3933
+ (function( $, undefined ) {
3934
+
3935
+ $.widget( "ui.menu", {
3936
+ version: "1.10.3",
3937
+ defaultElement: "<ul>",
3938
+ delay: 300,
3939
+ options: {
3940
+ icons: {
3941
+ submenu: "ui-icon-carat-1-e"
3942
+ },
3943
+ menus: "ul",
3944
+ position: {
3945
+ my: "left top",
3946
+ at: "right top"
3947
+ },
3948
+ role: "menu",
3949
+
3950
+ // callbacks
3951
+ blur: null,
3952
+ focus: null,
3953
+ select: null
3954
+ },
3955
+
3956
+ _create: function() {
3957
+ this.activeMenu = this.element;
3958
+ // flag used to prevent firing of the click handler
3959
+ // as the event bubbles up through nested menus
3960
+ this.mouseHandled = false;
3961
+ this.element
3962
+ .uniqueId()
3963
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
3964
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
3965
+ .attr({
3966
+ role: this.options.role,
3967
+ tabIndex: 0
3968
+ })
3969
+ // need to catch all clicks on disabled menu
3970
+ // not possible through _on
3971
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
3972
+ if ( this.options.disabled ) {
3973
+ event.preventDefault();
3974
+ }
3975
+ }, this ));
3976
+
3977
+ if ( this.options.disabled ) {
3978
+ this.element
3979
+ .addClass( "ui-state-disabled" )
3980
+ .attr( "aria-disabled", "true" );
3981
+ }
3982
+
3983
+ this._on({
3984
+ // Prevent focus from sticking to links inside menu after clicking
3985
+ // them (focus should always stay on UL during navigation).
3986
+ "mousedown .ui-menu-item > a": function( event ) {
3987
+ event.preventDefault();
3988
+ },
3989
+ "click .ui-state-disabled > a": function( event ) {
3990
+ event.preventDefault();
3991
+ },
3992
+ "click .ui-menu-item:has(a)": function( event ) {
3993
+ var target = $( event.target ).closest( ".ui-menu-item" );
3994
+ if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
3995
+ this.mouseHandled = true;
3996
+
3997
+ this.select( event );
3998
+ // Open submenu on click
3999
+ if ( target.has( ".ui-menu" ).length ) {
4000
+ this.expand( event );
4001
+ } else if ( !this.element.is( ":focus" ) ) {
4002
+ // Redirect focus to the menu
4003
+ this.element.trigger( "focus", [ true ] );
4004
+
4005
+ // If the active item is on the top level, let it stay active.
4006
+ // Otherwise, blur the active item since it is no longer visible.
4007
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
4008
+ clearTimeout( this.timer );
4009
+ }
4010
+ }
4011
+ }
4012
+ },
4013
+ "mouseenter .ui-menu-item": function( event ) {
4014
+ var target = $( event.currentTarget );
4015
+ // Remove ui-state-active class from siblings of the newly focused menu item
4016
+ // to avoid a jump caused by adjacent elements both having a class with a border
4017
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
4018
+ this.focus( event, target );
4019
+ },
4020
+ mouseleave: "collapseAll",
4021
+ "mouseleave .ui-menu": "collapseAll",
4022
+ focus: function( event, keepActiveItem ) {
4023
+ // If there's already an active item, keep it active
4024
+ // If not, activate the first item
4025
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
4026
+
4027
+ if ( !keepActiveItem ) {
4028
+ this.focus( event, item );
4029
+ }
4030
+ },
4031
+ blur: function( event ) {
4032
+ this._delay(function() {
4033
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
4034
+ this.collapseAll( event );
4035
+ }
4036
+ });
4037
+ },
4038
+ keydown: "_keydown"
4039
+ });
4040
+
4041
+ this.refresh();
4042
+
4043
+ // Clicks outside of a menu collapse any open menus
4044
+ this._on( this.document, {
4045
+ click: function( event ) {
4046
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
4047
+ this.collapseAll( event );
4048
+ }
4049
+
4050
+ // Reset the mouseHandled flag
4051
+ this.mouseHandled = false;
4052
+ }
4053
+ });
4054
+ },
4055
+
4056
+ _destroy: function() {
4057
+ // Destroy (sub)menus
4058
+ this.element
4059
+ .removeAttr( "aria-activedescendant" )
4060
+ .find( ".ui-menu" ).addBack()
4061
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
4062
+ .removeAttr( "role" )
4063
+ .removeAttr( "tabIndex" )
4064
+ .removeAttr( "aria-labelledby" )
4065
+ .removeAttr( "aria-expanded" )
4066
+ .removeAttr( "aria-hidden" )
4067
+ .removeAttr( "aria-disabled" )
4068
+ .removeUniqueId()
4069
+ .show();
4070
+
4071
+ // Destroy menu items
4072
+ this.element.find( ".ui-menu-item" )
4073
+ .removeClass( "ui-menu-item" )
4074
+ .removeAttr( "role" )
4075
+ .removeAttr( "aria-disabled" )
4076
+ .children( "a" )
4077
+ .removeUniqueId()
4078
+ .removeClass( "ui-corner-all ui-state-hover" )
4079
+ .removeAttr( "tabIndex" )
4080
+ .removeAttr( "role" )
4081
+ .removeAttr( "aria-haspopup" )
4082
+ .children().each( function() {
4083
+ var elem = $( this );
4084
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
4085
+ elem.remove();
4086
+ }
4087
+ });
4088
+
4089
+ // Destroy menu dividers
4090
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
4091
+ },
4092
+
4093
+ _keydown: function( event ) {
4094
+ /*jshint maxcomplexity:20*/
4095
+ var match, prev, character, skip, regex,
4096
+ preventDefault = true;
4097
+
4098
+ function escape( value ) {
4099
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
4100
+ }
4101
+
4102
+ switch ( event.keyCode ) {
4103
+ case $.ui.keyCode.PAGE_UP:
4104
+ this.previousPage( event );
4105
+ break;
4106
+ case $.ui.keyCode.PAGE_DOWN:
4107
+ this.nextPage( event );
4108
+ break;
4109
+ case $.ui.keyCode.HOME:
4110
+ this._move( "first", "first", event );
4111
+ break;
4112
+ case $.ui.keyCode.END:
4113
+ this._move( "last", "last", event );
4114
+ break;
4115
+ case $.ui.keyCode.UP:
4116
+ this.previous( event );
4117
+ break;
4118
+ case $.ui.keyCode.DOWN:
4119
+ this.next( event );
4120
+ break;
4121
+ case $.ui.keyCode.LEFT:
4122
+ this.collapse( event );
4123
+ break;
4124
+ case $.ui.keyCode.RIGHT:
4125
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
4126
+ this.expand( event );
4127
+ }
4128
+ break;
4129
+ case $.ui.keyCode.ENTER:
4130
+ case $.ui.keyCode.SPACE:
4131
+ this._activate( event );
4132
+ break;
4133
+ case $.ui.keyCode.ESCAPE:
4134
+ this.collapse( event );
4135
+ break;
4136
+ default:
4137
+ preventDefault = false;
4138
+ prev = this.previousFilter || "";
4139
+ character = String.fromCharCode( event.keyCode );
4140
+ skip = false;
4141
+
4142
+ clearTimeout( this.filterTimer );
4143
+
4144
+ if ( character === prev ) {
4145
+ skip = true;
4146
+ } else {
4147
+ character = prev + character;
4148
+ }
4149
+
4150
+ regex = new RegExp( "^" + escape( character ), "i" );
4151
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
4152
+ return regex.test( $( this ).children( "a" ).text() );
4153
+ });
4154
+ match = skip && match.index( this.active.next() ) !== -1 ?
4155
+ this.active.nextAll( ".ui-menu-item" ) :
4156
+ match;
4157
+
4158
+ // If no matches on the current filter, reset to the last character pressed
4159
+ // to move down the menu to the first item that starts with that character
4160
+ if ( !match.length ) {
4161
+ character = String.fromCharCode( event.keyCode );
4162
+ regex = new RegExp( "^" + escape( character ), "i" );
4163
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
4164
+ return regex.test( $( this ).children( "a" ).text() );
4165
+ });
4166
+ }
4167
+
4168
+ if ( match.length ) {
4169
+ this.focus( event, match );
4170
+ if ( match.length > 1 ) {
4171
+ this.previousFilter = character;
4172
+ this.filterTimer = this._delay(function() {
4173
+ delete this.previousFilter;
4174
+ }, 1000 );
4175
+ } else {
4176
+ delete this.previousFilter;
4177
+ }
4178
+ } else {
4179
+ delete this.previousFilter;
4180
+ }
4181
+ }
4182
+
4183
+ if ( preventDefault ) {
4184
+ event.preventDefault();
4185
+ }
4186
+ },
4187
+
4188
+ _activate: function( event ) {
4189
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
4190
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
4191
+ this.expand( event );
4192
+ } else {
4193
+ this.select( event );
4194
+ }
4195
+ }
4196
+ },
4197
+
4198
+ refresh: function() {
4199
+ var menus,
4200
+ icon = this.options.icons.submenu,
4201
+ submenus = this.element.find( this.options.menus );
4202
+
4203
+ // Initialize nested menus
4204
+ submenus.filter( ":not(.ui-menu)" )
4205
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
4206
+ .hide()
4207
+ .attr({
4208
+ role: this.options.role,
4209
+ "aria-hidden": "true",
4210
+ "aria-expanded": "false"
4211
+ })
4212
+ .each(function() {
4213
+ var menu = $( this ),
4214
+ item = menu.prev( "a" ),
4215
+ submenuCarat = $( "<span>" )
4216
+ .addClass( "ui-menu-icon ui-icon " + icon )
4217
+ .data( "ui-menu-submenu-carat", true );
4218
+
4219
+ item
4220
+ .attr( "aria-haspopup", "true" )
4221
+ .prepend( submenuCarat );
4222
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
4223
+ });
4224
+
4225
+ menus = submenus.add( this.element );
4226
+
4227
+ // Don't refresh list items that are already adapted
4228
+ menus.children( ":not(.ui-menu-item):has(a)" )
4229
+ .addClass( "ui-menu-item" )
4230
+ .attr( "role", "presentation" )
4231
+ .children( "a" )
4232
+ .uniqueId()
4233
+ .addClass( "ui-corner-all" )
4234
+ .attr({
4235
+ tabIndex: -1,
4236
+ role: this._itemRole()
4237
+ });
4238
+
4239
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
4240
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
4241
+ var item = $( this );
4242
+ // hyphen, em dash, en dash
4243
+ if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
4244
+ item.addClass( "ui-widget-content ui-menu-divider" );
4245
+ }
4246
+ });
4247
+
4248
+ // Add aria-disabled attribute to any disabled menu item
4249
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
4250
+
4251
+ // If the active item has been removed, blur the menu
4252
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
4253
+ this.blur();
4254
+ }
4255
+ },
4256
+
4257
+ _itemRole: function() {
4258
+ return {
4259
+ menu: "menuitem",
4260
+ listbox: "option"
4261
+ }[ this.options.role ];
4262
+ },
4263
+
4264
+ _setOption: function( key, value ) {
4265
+ if ( key === "icons" ) {
4266
+ this.element.find( ".ui-menu-icon" )
4267
+ .removeClass( this.options.icons.submenu )
4268
+ .addClass( value.submenu );
4269
+ }
4270
+ this._super( key, value );
4271
+ },
4272
+
4273
+ focus: function( event, item ) {
4274
+ var nested, focused;
4275
+ this.blur( event, event && event.type === "focus" );
4276
+
4277
+ this._scrollIntoView( item );
4278
+
4279
+ this.active = item.first();
4280
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
4281
+ // Only update aria-activedescendant if there's a role
4282
+ // otherwise we assume focus is managed elsewhere
4283
+ if ( this.options.role ) {
4284
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
4285
+ }
4286
+
4287
+ // Highlight active parent menu item, if any
4288
+ this.active
4289
+ .parent()
4290
+ .closest( ".ui-menu-item" )
4291
+ .children( "a:first" )
4292
+ .addClass( "ui-state-active" );
4293
+
4294
+ if ( event && event.type === "keydown" ) {
4295
+ this._close();
4296
+ } else {
4297
+ this.timer = this._delay(function() {
4298
+ this._close();
4299
+ }, this.delay );
4300
+ }
4301
+
4302
+ nested = item.children( ".ui-menu" );
4303
+ if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
4304
+ this._startOpening(nested);
4305
+ }
4306
+ this.activeMenu = item.parent();
4307
+
4308
+ this._trigger( "focus", event, { item: item } );
4309
+ },
4310
+
4311
+ _scrollIntoView: function( item ) {
4312
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
4313
+ if ( this._hasScroll() ) {
4314
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
4315
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
4316
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
4317
+ scroll = this.activeMenu.scrollTop();
4318
+ elementHeight = this.activeMenu.height();
4319
+ itemHeight = item.height();
4320
+
4321
+ if ( offset < 0 ) {
4322
+ this.activeMenu.scrollTop( scroll + offset );
4323
+ } else if ( offset + itemHeight > elementHeight ) {
4324
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
4325
+ }
4326
+ }
4327
+ },
4328
+
4329
+ blur: function( event, fromFocus ) {
4330
+ if ( !fromFocus ) {
4331
+ clearTimeout( this.timer );
4332
+ }
4333
+
4334
+ if ( !this.active ) {
4335
+ return;
4336
+ }
4337
+
4338
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
4339
+ this.active = null;
4340
+
4341
+ this._trigger( "blur", event, { item: this.active } );
4342
+ },
4343
+
4344
+ _startOpening: function( submenu ) {
4345
+ clearTimeout( this.timer );
4346
+
4347
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
4348
+ // shift in the submenu position when mousing over the carat icon
4349
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
4350
+ return;
4351
+ }
4352
+
4353
+ this.timer = this._delay(function() {
4354
+ this._close();
4355
+ this._open( submenu );
4356
+ }, this.delay );
4357
+ },
4358
+
4359
+ _open: function( submenu ) {
4360
+ var position = $.extend({
4361
+ of: this.active
4362
+ }, this.options.position );
4363
+
4364
+ clearTimeout( this.timer );
4365
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
4366
+ .hide()
4367
+ .attr( "aria-hidden", "true" );
4368
+
4369
+ submenu
4370
+ .show()
4371
+ .removeAttr( "aria-hidden" )
4372
+ .attr( "aria-expanded", "true" )
4373
+ .position( position );
4374
+ },
4375
+
4376
+ collapseAll: function( event, all ) {
4377
+ clearTimeout( this.timer );
4378
+ this.timer = this._delay(function() {
4379
+ // If we were passed an event, look for the submenu that contains the event
4380
+ var currentMenu = all ? this.element :
4381
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
4382
+
4383
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
4384
+ if ( !currentMenu.length ) {
4385
+ currentMenu = this.element;
4386
+ }
4387
+
4388
+ this._close( currentMenu );
4389
+
4390
+ this.blur( event );
4391
+ this.activeMenu = currentMenu;
4392
+ }, this.delay );
4393
+ },
4394
+
4395
+ // With no arguments, closes the currently active menu - if nothing is active
4396
+ // it closes all menus. If passed an argument, it will search for menus BELOW
4397
+ _close: function( startMenu ) {
4398
+ if ( !startMenu ) {
4399
+ startMenu = this.active ? this.active.parent() : this.element;
4400
+ }
4401
+
4402
+ startMenu
4403
+ .find( ".ui-menu" )
4404
+ .hide()
4405
+ .attr( "aria-hidden", "true" )
4406
+ .attr( "aria-expanded", "false" )
4407
+ .end()
4408
+ .find( "a.ui-state-active" )
4409
+ .removeClass( "ui-state-active" );
4410
+ },
4411
+
4412
+ collapse: function( event ) {
4413
+ var newItem = this.active &&
4414
+ this.active.parent().closest( ".ui-menu-item", this.element );
4415
+ if ( newItem && newItem.length ) {
4416
+ this._close();
4417
+ this.focus( event, newItem );
4418
+ }
4419
+ },
4420
+
4421
+ expand: function( event ) {
4422
+ var newItem = this.active &&
4423
+ this.active
4424
+ .children( ".ui-menu " )
4425
+ .children( ".ui-menu-item" )
4426
+ .first();
4427
+
4428
+ if ( newItem && newItem.length ) {
4429
+ this._open( newItem.parent() );
4430
+
4431
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
4432
+ this._delay(function() {
4433
+ this.focus( event, newItem );
4434
+ });
4435
+ }
4436
+ },
4437
+
4438
+ next: function( event ) {
4439
+ this._move( "next", "first", event );
4440
+ },
4441
+
4442
+ previous: function( event ) {
4443
+ this._move( "prev", "last", event );
4444
+ },
4445
+
4446
+ isFirstItem: function() {
4447
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
4448
+ },
4449
+
4450
+ isLastItem: function() {
4451
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
4452
+ },
4453
+
4454
+ _move: function( direction, filter, event ) {
4455
+ var next;
4456
+ if ( this.active ) {
4457
+ if ( direction === "first" || direction === "last" ) {
4458
+ next = this.active
4459
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
4460
+ .eq( -1 );
4461
+ } else {
4462
+ next = this.active
4463
+ [ direction + "All" ]( ".ui-menu-item" )
4464
+ .eq( 0 );
4465
+ }
4466
+ }
4467
+ if ( !next || !next.length || !this.active ) {
4468
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
4469
+ }
4470
+
4471
+ this.focus( event, next );
4472
+ },
4473
+
4474
+ nextPage: function( event ) {
4475
+ var item, base, height;
4476
+
4477
+ if ( !this.active ) {
4478
+ this.next( event );
4479
+ return;
4480
+ }
4481
+ if ( this.isLastItem() ) {
4482
+ return;
4483
+ }
4484
+ if ( this._hasScroll() ) {
4485
+ base = this.active.offset().top;
4486
+ height = this.element.height();
4487
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
4488
+ item = $( this );
4489
+ return item.offset().top - base - height < 0;
4490
+ });
4491
+
4492
+ this.focus( event, item );
4493
+ } else {
4494
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
4495
+ [ !this.active ? "first" : "last" ]() );
4496
+ }
4497
+ },
4498
+
4499
+ previousPage: function( event ) {
4500
+ var item, base, height;
4501
+ if ( !this.active ) {
4502
+ this.next( event );
4503
+ return;
4504
+ }
4505
+ if ( this.isFirstItem() ) {
4506
+ return;
4507
+ }
4508
+ if ( this._hasScroll() ) {
4509
+ base = this.active.offset().top;
4510
+ height = this.element.height();
4511
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
4512
+ item = $( this );
4513
+ return item.offset().top - base + height > 0;
4514
+ });
4515
+
4516
+ this.focus( event, item );
4517
+ } else {
4518
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
4519
+ }
4520
+ },
4521
+
4522
+ _hasScroll: function() {
4523
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
4524
+ },
4525
+
4526
+ select: function( event ) {
4527
+ // TODO: It should never be possible to not have an active item at this
4528
+ // point, but the tests don't trigger mouseenter before click.
4529
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
4530
+ var ui = { item: this.active };
4531
+ if ( !this.active.has( ".ui-menu" ).length ) {
4532
+ this.collapseAll( event, true );
4533
+ }
4534
+ this._trigger( "select", event, ui );
4535
+ }
4536
+ });
4537
+
4538
+ }( jQuery ));