summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/lib/datejs/core.js864
-rw-r--r--addons/web/static/lib/datejs/date.js21
-rw-r--r--addons/web/static/lib/datejs/extras.js331
-rw-r--r--addons/web/static/lib/datejs/globalization/af-ZA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-AE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-BH.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-DZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-EG.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-IQ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-JO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-KW.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-LB.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-LY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-MA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-OM.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-QA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-SA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-SY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-TN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ar-YE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/az-Cyrl-AZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/az-Latn-AZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/be-BY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/bg-BG.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/bs-Latn-BA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ca-ES.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/cs-CZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/cy-GB.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/da-DK.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/de-AT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/de-CH.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/de-DE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/de-LI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/de-LU.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/dv-MV.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/el-GR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-029.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-AU.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-BZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-CA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-GB.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-IE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-JM.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-NZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-PH.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-TT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-US.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-ZA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/en-ZW.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-AR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-BO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-CL.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-CO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-CR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-DO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-EC.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-ES.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-GT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-HN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-MX.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-NI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-PA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-PE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-PR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-PY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-SV.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-UY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/es-VE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/et-EE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/eu-ES.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fa-IR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fi-FI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fo-FO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fr-BE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fr-CA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fr-CH.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fr-FR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fr-LU.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/fr-MC.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/gl-ES.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/gu-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/he-IL.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/hi-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/hr-BA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/hr-HR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/hu-HU.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/hy-AM.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/id-ID.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/is-IS.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/it-CH.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/it-IT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ja-JP.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ka-GE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/kk-KZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/kn-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ko-KR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/kok-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ky-KG.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/lt-LT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/lv-LV.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/mi-NZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/mk-MK.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/mn-MN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/mr-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ms-BN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ms-MY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/mt-MT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/nb-NO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/nl-BE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/nl-NL.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/nn-NO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ns-ZA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/pa-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/pl-PL.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/pt-BR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/pt-PT.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/quz-BO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/quz-EC.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/quz-PE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ro-RO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ru-RU.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sa-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/se-FI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/se-NO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/se-SE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sk-SK.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sl-SI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sma-NO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sma-SE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/smj-NO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/smj-SE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/smn-FI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sms-FI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sq-AL.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sr-Cyrl-BA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sr-Cyrl-CS.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sr-Latn-BA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sr-Latn-CS.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sv-FI.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sv-SE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/sw-KE.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/syr-SY.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ta-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/te-IN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/th-TH.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/tn-ZA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/tr-TR.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/tt-RU.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/uk-UA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/ur-PK.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/uz-Cyrl-UZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/uz-Latn-UZ.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/vi-VN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/xh-ZA.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/zh-CN.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/zh-HK.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/zh-MO.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/zh-SG.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/zh-TW.js195
-rw-r--r--addons/web/static/lib/datejs/globalization/zu-ZA.js195
-rw-r--r--addons/web/static/lib/datejs/parser.js1116
-rw-r--r--addons/web/static/lib/datejs/sugarpak.js475
-rw-r--r--addons/web/static/lib/datejs/time.js269
-rw-r--r--addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js1137
-rw-r--r--addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.min.js18
-rw-r--r--addons/web/static/lib/jquery.blockUI/jquery.blockUI.js499
-rw-r--r--addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js126
-rw-r--r--addons/web/static/lib/jquery.form/jquery.form.js911
-rw-r--r--addons/web/static/lib/jquery.superfish/changelog.txt74
-rw-r--r--addons/web/static/lib/jquery.superfish/css/superfish-navbar.css93
-rw-r--r--addons/web/static/lib/jquery.superfish/css/superfish-vertical.css23
-rw-r--r--addons/web/static/lib/jquery.superfish/css/superfish.css136
-rw-r--r--addons/web/static/lib/jquery.superfish/example.html123
-rw-r--r--addons/web/static/lib/jquery.superfish/images/arrows-ffffff.pngbin0 -> 244 bytes
-rw-r--r--addons/web/static/lib/jquery.superfish/images/shadow.pngbin0 -> 1698 bytes
-rw-r--r--addons/web/static/lib/jquery.superfish/js/hoverIntent.js84
-rw-r--r--addons/web/static/lib/jquery.superfish/js/jquery-1.2.6.min.js32
-rw-r--r--addons/web/static/lib/jquery.superfish/js/jquery.bgiframe.min.js10
-rw-r--r--addons/web/static/lib/jquery.superfish/js/superfish.js121
-rw-r--r--addons/web/static/lib/jquery.superfish/js/supersubs.js90
-rw-r--r--addons/web/static/lib/jquery.ui.notify/css/ui.notify.css13
-rw-r--r--addons/web/static/lib/jquery.ui.notify/js/jquery.notify.js140
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.pngbin0 -> 180 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.pngbin0 -> 178 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 120 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 105 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 111 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 110 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 119 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 101 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_222222_256x240.pngbin0 -> 4369 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_2e83ff_256x240.pngbin0 -> 4369 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_454545_256x240.pngbin0 -> 4369 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_888888_256x240.pngbin0 -> 4369 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4369 bytes
-rw-r--r--addons/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css573
-rw-r--r--addons/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js781
-rw-r--r--addons/web/static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js911
-rw-r--r--addons/web/static/lib/jquery.validate/jquery.validate.js1166
-rw-r--r--addons/web/static/lib/jquery/jquery-1.6.2.js8981
-rwxr-xr-xaddons/web/static/lib/json/json2.js480
-rw-r--r--addons/web/static/lib/labjs/LAB.src.js514
-rw-r--r--addons/web/static/lib/qunit/qunit-2011-23-22.css248
-rw-r--r--addons/web/static/lib/qunit/qunit-2011-23-22.js1456
-rw-r--r--addons/web/static/lib/qweb/qweb-benchmark.html43
-rw-r--r--addons/web/static/lib/qweb/qweb-benchmark.xml60
-rw-r--r--addons/web/static/lib/qweb/qweb-test-attributes.xml22
-rw-r--r--addons/web/static/lib/qweb/qweb-test-call.xml30
-rw-r--r--addons/web/static/lib/qweb/qweb-test-conditionals.xml59
-rw-r--r--addons/web/static/lib/qweb/qweb-test-extend.xml32
-rw-r--r--addons/web/static/lib/qweb/qweb-test-foreach.xml17
-rw-r--r--addons/web/static/lib/qweb/qweb-test-output.xml51
-rw-r--r--addons/web/static/lib/qweb/qweb-test-set.xml15
-rw-r--r--addons/web/static/lib/qweb/qweb-test.js.html271
-rw-r--r--addons/web/static/lib/qweb/qweb.js413
-rw-r--r--addons/web/static/lib/qweb/qweb2.js712
-rw-r--r--addons/web/static/lib/underscore/underscore.js839
-rw-r--r--addons/web/static/lib/underscore/underscore.string.js304
-rw-r--r--addons/web/static/src/css/base-ie7.css4
-rw-r--r--addons/web/static/src/css/base.css1317
-rw-r--r--addons/web/static/src/css/data_export.css84
-rw-r--r--addons/web/static/src/img/accessories-archiver.pngbin0 -> 822 bytes
-rw-r--r--addons/web/static/src/img/add-shortcut.pngbin0 -> 395 bytes
-rw-r--r--addons/web/static/src/img/attachments-close.pngbin0 -> 486 bytes
-rw-r--r--addons/web/static/src/img/collapse.gifbin0 -> 80 bytes
-rw-r--r--addons/web/static/src/img/db.pngbin0 -> 2042 bytes
-rw-r--r--addons/web/static/src/img/down-arrow.pngbin0 -> 263 bytes
-rw-r--r--addons/web/static/src/img/expand.gifbin0 -> 81 bytes
-rw-r--r--addons/web/static/src/img/favicon.icobin0 -> 1150 bytes
-rw-r--r--addons/web/static/src/img/header-about.pngbin0 -> 442 bytes
-rw-r--r--addons/web/static/src/img/header-background.pngbin0 -> 149 bytes
-rw-r--r--addons/web/static/src/img/header-help.pngbin0 -> 454 bytes
-rw-r--r--addons/web/static/src/img/header-home.pngbin0 -> 452 bytes
-rw-r--r--addons/web/static/src/img/header-preferences.pngbin0 -> 420 bytes
-rw-r--r--addons/web/static/src/img/header-requests.pngbin0 -> 353 bytes
-rw-r--r--addons/web/static/src/img/header.gifbin0 -> 182 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ABOUT.pngbin0 -> 523 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ADD.pngbin0 -> 212 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_APPLY.pngbin0 -> 709 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_BOLD.pngbin0 -> 604 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CANCEL.pngbin0 -> 407 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CDROM.pngbin0 -> 711 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CLEAR.pngbin0 -> 682 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CLOSE.pngbin0 -> 274 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_COLOR_PICKER.pngbin0 -> 470 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CONNECT.pngbin0 -> 558 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CONVERT.pngbin0 -> 500 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_COPY.pngbin0 -> 339 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_CUT.pngbin0 -> 626 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DELETE.pngbin0 -> 531 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DIALOG_AUTHENTICATION.pngbin0 -> 590 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DIALOG_ERROR.pngbin0 -> 559 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DIALOG_INFO.pngbin0 -> 687 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DIALOG_QUESTION.pngbin0 -> 491 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DIALOG_WARNING.pngbin0 -> 428 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DIRECTORY.pngbin0 -> 392 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DISCONNECT.pngbin0 -> 566 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DND.pngbin0 -> 585 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_DND_MULTIPLE.pngbin0 -> 501 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_EDIT.pngbin0 -> 350 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_EXECUTE.pngbin0 -> 318 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_FILE.pngbin0 -> 289 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_FIND.pngbin0 -> 465 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_FIND_AND_REPLACE.pngbin0 -> 580 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_FLOPPY.pngbin0 -> 565 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_FULLSCREEN.pngbin0 -> 450 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GOTO_BOTTOM.pngbin0 -> 574 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GOTO_FIRST.pngbin0 -> 573 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GOTO_LAST.pngbin0 -> 575 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GOTO_TOP.pngbin0 -> 580 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GO_BACK.pngbin0 -> 570 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GO_DOWN.pngbin0 -> 572 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GO_FORWARD.pngbin0 -> 575 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_GO_UP.pngbin0 -> 596 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_HARDDISK.pngbin0 -> 354 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_HELP.pngbin0 -> 789 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_HOME.pngbin0 -> 477 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_INDENT.pngbin0 -> 276 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_INDEX.pngbin0 -> 590 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_INFO.pngbin0 -> 738 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ITALIC.pngbin0 -> 529 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_JUMP_TO.pngbin0 -> 591 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_JUSTIFY_CENTER.pngbin0 -> 251 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_JUSTIFY_FILL.pngbin0 -> 243 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_JUSTIFY_LEFT.pngbin0 -> 240 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_JUSTIFY_RIGHT.pngbin0 -> 254 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_LEAVE_FULLSCREEN.pngbin0 -> 448 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_FORWARD.pngbin0 -> 704 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_NEXT.pngbin0 -> 693 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_PAUSE.pngbin0 -> 466 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_PLAY.pngbin0 -> 556 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_PREVIOUS.pngbin0 -> 686 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_RECORD.pngbin0 -> 594 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_REWIND.pngbin0 -> 704 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MEDIA_STOP.pngbin0 -> 421 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_MISSING_IMAGE.pngbin0 -> 330 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_NETWORK.pngbin0 -> 324 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_NEW.pngbin0 -> 405 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_NO.pngbin0 -> 751 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_OK.pngbin0 -> 795 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_OPEN.pngbin0 -> 418 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_PASTE.pngbin0 -> 473 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_PREFERENCES.pngbin0 -> 339 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_PRINT.pngbin0 -> 411 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_PRINT_PREVIEW.pngbin0 -> 616 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_PROPERTIES.pngbin0 -> 313 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_QUIT.pngbin0 -> 394 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_REDO.pngbin0 -> 430 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_REFRESH.pngbin0 -> 753 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_REMOVE.pngbin0 -> 176 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_REVERT_TO_SAVED.pngbin0 -> 413 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SAVE.pngbin0 -> 599 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SAVE_AS.pngbin0 -> 560 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SELECT_COLOR.pngbin0 -> 656 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SELECT_FONT.pngbin0 -> 598 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SORT_ASCENDING.pngbin0 -> 371 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SORT_DESCENDING.pngbin0 -> 370 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_SPELL_CHECK.pngbin0 -> 485 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_STOP.pngbin0 -> 678 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_STRIKETHROUGH.pngbin0 -> 459 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_UNDELETE.pngbin0 -> 875 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_UNDERLINE.pngbin0 -> 539 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_UNDO.pngbin0 -> 459 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_UNINDENT.pngbin0 -> 295 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_YES.pngbin0 -> 830 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ZOOM_100.pngbin0 -> 469 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ZOOM_FIT.pngbin0 -> 466 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ZOOM_IN.pngbin0 -> 446 bytes
-rw-r--r--addons/web/static/src/img/icons/STOCK_ZOOM_OUT.pngbin0 -> 463 bytes
-rw-r--r--addons/web/static/src/img/icons/color-picker.pngbin0 -> 767 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-about.pngbin0 -> 523 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-add.pngbin0 -> 212 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-apply.pngbin0 -> 709 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-bold.pngbin0 -> 604 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-cancel.pngbin0 -> 407 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-cdrom.pngbin0 -> 711 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-clear.pngbin0 -> 682 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-close.pngbin0 -> 274 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-color-picker.pngbin0 -> 470 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-connect.pngbin0 -> 558 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-convert.pngbin0 -> 500 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-copy.pngbin0 -> 339 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-cut.pngbin0 -> 626 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-delete.pngbin0 -> 531 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dialog-authentication.pngbin0 -> 590 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dialog-error.pngbin0 -> 559 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dialog-info.pngbin0 -> 687 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dialog-question.pngbin0 -> 491 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dialog-warning.pngbin0 -> 428 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-directory-remote.pngbin0 -> 455 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-directory.pngbin0 -> 392 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-disconnect.pngbin0 -> 566 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dnd-multiple.pngbin0 -> 501 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-dnd.pngbin0 -> 585 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-edit.pngbin0 -> 350 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-execute.pngbin0 -> 318 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-file.pngbin0 -> 289 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-find-and-replace.pngbin0 -> 580 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-find.pngbin0 -> 465 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-floppy.pngbin0 -> 565 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-fullscreen.pngbin0 -> 450 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-go-back.pngbin0 -> 570 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-go-down.pngbin0 -> 572 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-go-forward.pngbin0 -> 575 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-go-up.pngbin0 -> 596 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-goto-bottom.pngbin0 -> 574 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-goto-first.pngbin0 -> 573 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-goto-last.pngbin0 -> 575 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-goto-top.pngbin0 -> 580 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-harddisk.pngbin0 -> 354 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-help.pngbin0 -> 789 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-home.pngbin0 -> 477 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-indent.pngbin0 -> 276 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-index.pngbin0 -> 590 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-info.pngbin0 -> 738 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-italic.pngbin0 -> 529 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-jump-to.pngbin0 -> 591 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-justify-center.pngbin0 -> 251 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-justify-fill.pngbin0 -> 243 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-justify-left.pngbin0 -> 240 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-justify-right.pngbin0 -> 254 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-leave-fullscreen.pngbin0 -> 448 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-forward.pngbin0 -> 704 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-next.pngbin0 -> 693 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-pause.pngbin0 -> 466 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-play.pngbin0 -> 556 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-previous.pngbin0 -> 686 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-record.pngbin0 -> 594 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-rewind.pngbin0 -> 704 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-media-stop.pngbin0 -> 421 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-missing-image.pngbin0 -> 330 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-network.pngbin0 -> 324 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-new.pngbin0 -> 405 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-no.pngbin0 -> 751 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-ok.pngbin0 -> 795 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-open.pngbin0 -> 418 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-paste-v.pngbin0 -> 689 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-paste.pngbin0 -> 473 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-preferences.pngbin0 -> 339 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-print-preview.pngbin0 -> 616 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-print.pngbin0 -> 411 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-properties.pngbin0 -> 313 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-quit.pngbin0 -> 394 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-redo.pngbin0 -> 430 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-refresh.pngbin0 -> 753 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-remove.pngbin0 -> 176 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-revert-to-saved.pngbin0 -> 413 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-save-as.pngbin0 -> 560 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-save.pngbin0 -> 599 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-select-color.pngbin0 -> 656 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-select-font.pngbin0 -> 598 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-sort-ascending.pngbin0 -> 371 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-sort-descending.pngbin0 -> 370 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-spell-check.pngbin0 -> 485 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-stop.pngbin0 -> 678 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-strikethrough.pngbin0 -> 459 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-undelete.pngbin0 -> 875 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-underline.pngbin0 -> 539 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-undo.pngbin0 -> 459 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-unindent.pngbin0 -> 295 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-yes.pngbin0 -> 830 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-zoom-100.pngbin0 -> 469 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-zoom-fit.pngbin0 -> 466 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-zoom-in.pngbin0 -> 446 bytes
-rw-r--r--addons/web/static/src/img/icons/gtk-zoom-out.pngbin0 -> 463 bytes
-rw-r--r--addons/web/static/src/img/icons/index1.jpegbin0 -> 473 bytes
-rw-r--r--addons/web/static/src/img/icons/index2.jpegbin0 -> 471 bytes
-rw-r--r--addons/web/static/src/img/icons/lead-stage-lost.pngbin0 -> 692 bytes
-rw-r--r--addons/web/static/src/img/icons/lead-stage-pending.pngbin0 -> 882 bytes
-rw-r--r--addons/web/static/src/img/icons/lead-stage-won.pngbin0 -> 918 bytes
-rw-r--r--addons/web/static/src/img/icons/star-off.pngbin0 -> 614 bytes
-rw-r--r--addons/web/static/src/img/icons/star-on.pngbin0 -> 636 bytes
-rw-r--r--addons/web/static/src/img/icons/stock.pngbin0 -> 953 bytes
-rw-r--r--addons/web/static/src/img/icons/stock_calendar.pngbin0 -> 454 bytes
-rw-r--r--addons/web/static/src/img/icons/stock_gantt.pngbin0 -> 293 bytes
-rw-r--r--addons/web/static/src/img/icons/stock_graph.pngbin0 -> 606 bytes
-rw-r--r--addons/web/static/src/img/icons/stock_log.pngbin0 -> 748 bytes
-rw-r--r--addons/web/static/src/img/icons/stock_person.pngbin0 -> 1074 bytes
-rw-r--r--addons/web/static/src/img/icons/stock_translate.pngbin0 -> 519 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-accessories-archiver+.pngbin0 -> 838 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-accessories-archiver-minus.pngbin0 -> 838 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-accessories-archiver.pngbin0 -> 822 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-account.pngbin0 -> 784 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-administration.pngbin0 -> 1015 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-calendar.pngbin0 -> 908 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-call-start.pngbin0 -> 492 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-camera_test.pngbin0 -> 739 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-check.pngbin0 -> 832 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-crm.pngbin0 -> 877 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-dialog-close.pngbin0 -> 305 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-document-new.pngbin0 -> 738 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-dolar.pngbin0 -> 270 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-dolar_ok!.pngbin0 -> 220 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-emblem-important.pngbin0 -> 703 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-face-plain.pngbin0 -> 788 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-folder-blue.pngbin0 -> 438 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-folder-green.pngbin0 -> 453 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-folder-orange.pngbin0 -> 411 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-folder-violet.pngbin0 -> 538 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-folder-yellow.pngbin0 -> 432 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gdu-smart-failing.pngbin0 -> 451 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gnome-cpu-frequency-applet+.pngbin0 -> 488 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-go-home.pngbin0 -> 378 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-go-month.pngbin0 -> 517 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-go-today.pngbin0 -> 501 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-go-week.pngbin0 -> 442 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-go-year.pngbin0 -> 514 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-graph.pngbin0 -> 784 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-go-back-ltr.pngbin0 -> 759 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-go-back-rtl.pngbin0 -> 762 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-jump-to-ltr.pngbin0 -> 859 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-jump-to-rtl.pngbin0 -> 851 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-media-pause.pngbin0 -> 544 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-select-all.pngbin0 -> 554 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-gtk-stop.pngbin0 -> 622 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-hr.pngbin0 -> 699 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-idea.pngbin0 -> 384 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-locked.pngbin0 -> 588 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-mail-.pngbin0 -> 427 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-mail-forward.pngbin0 -> 382 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-mail-message-new.pngbin0 -> 696 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-mail-replied.pngbin0 -> 637 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-mail_delete.pngbin0 -> 988 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-marketing.pngbin0 -> 808 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-mrp.pngbin0 -> 880 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-partner.pngbin0 -> 905 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-personal+.pngbin0 -> 735 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-personal-.pngbin0 -> 791 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-personal.pngbin0 -> 930 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-product.pngbin0 -> 708 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-project.pngbin0 -> 993 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-purchase.pngbin0 -> 885 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-rating-rated.pngbin0 -> 559 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-report.pngbin0 -> 831 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-sale.pngbin0 -> 699 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stage.pngbin0 -> 742 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock.pngbin0 -> 967 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock_align_left_24.pngbin0 -> 358 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock_effects-object-colorize.pngbin0 -> 173 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock_format-default.pngbin0 -> 267 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock_format-scientific.pngbin0 -> 201 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock_symbol-selection.pngbin0 -> 382 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-stock_zoom.pngbin0 -> 425 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-tools.pngbin0 -> 914 bytes
-rw-r--r--addons/web/static/src/img/icons/terp-translate.pngbin0 -> 519 bytes
-rw-r--r--addons/web/static/src/img/iconset-d-drop.gifbin0 -> 238 bytes
-rw-r--r--addons/web/static/src/img/logo.pngbin0 -> 3551 bytes
-rw-r--r--addons/web/static/src/img/partner.pngbin0 -> 905 bytes
-rw-r--r--addons/web/static/src/img/placeholder.pngbin0 -> 1362 bytes
-rw-r--r--addons/web/static/src/img/product.pngbin0 -> 708 bytes
-rw-r--r--addons/web/static/src/img/remove-shortcut.pngbin0 -> 559 bytes
-rw-r--r--addons/web/static/src/img/stock_person.pngbin0 -> 1074 bytes
-rw-r--r--addons/web/static/src/img/throbber.gifbin0 -> 673 bytes
-rw-r--r--addons/web/static/src/img/throbber2.gifbin0 -> 7195 bytes
-rw-r--r--addons/web/static/src/img/toggle-a-bg.pngbin0 -> 412 bytes
-rw-r--r--addons/web/static/src/img/ui/field_calendar.pngbin0 -> 454 bytes
-rw-r--r--addons/web/static/src/img/ui/group-expanded.pngbin0 -> 229 bytes
-rw-r--r--addons/web/static/src/img/ui/group-folded.pngbin0 -> 259 bytes
-rw-r--r--addons/web/static/src/img/warning.pngbin0 -> 1342 bytes
-rw-r--r--addons/web/static/src/js/boot.js69
-rw-r--r--addons/web/static/src/js/chrome.js978
-rw-r--r--addons/web/static/src/js/core.js992
-rw-r--r--addons/web/static/src/js/data.js833
-rw-r--r--addons/web/static/src/js/data_export.js391
-rw-r--r--addons/web/static/src/js/dates.js138
-rw-r--r--addons/web/static/src/js/form.js2588
-rw-r--r--addons/web/static/src/js/formats.js197
-rw-r--r--addons/web/static/src/js/list-editable.js336
-rw-r--r--addons/web/static/src/js/list.js1523
-rw-r--r--addons/web/static/src/js/search.js1220
-rw-r--r--addons/web/static/src/js/view_editor.js147
-rw-r--r--addons/web/static/src/js/view_help.js15
-rw-r--r--addons/web/static/src/js/view_tree.js216
-rw-r--r--addons/web/static/src/js/views.js829
-rw-r--r--addons/web/static/src/xml/base.xml1418
-rw-r--r--addons/web/static/test/class.js138
-rw-r--r--addons/web/static/test/form.js58
-rw-r--r--addons/web/static/test/formats.js54
-rw-r--r--addons/web/static/test/list-utils.js297
-rw-r--r--addons/web/static/test/qunit-doc.js143
-rw-r--r--addons/web/static/test/registry.js33
-rw-r--r--addons/web/static/test/test.html53
542 files changed, 69370 insertions, 0 deletions
diff --git a/addons/web/static/lib/datejs/core.js b/addons/web/static/lib/datejs/core.js
new file mode 100644
index 00000000000..3e87087c476
--- /dev/null
+++ b/addons/web/static/lib/datejs/core.js
@@ -0,0 +1,864 @@
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+
+ /**
+ * Resets the time of this Date object to 12:00 AM (00:00), which is the start of the day.
+ * @param {Boolean} .clone() this date instance before clearing Time
+ * @return {Date} this
+ */
+ $P.clearTime = function () {
+ this.setHours(0);
+ this.setMinutes(0);
+ this.setSeconds(0);
+ this.setMilliseconds(0);
+ return this;
+ };
+
+ /**
+ * Resets the time of this Date object to the current time ('now').
+ * @return {Date} this
+ */
+ $P.setTimeToNow = function () {
+ var n = new Date();
+ this.setHours(n.getHours());
+ this.setMinutes(n.getMinutes());
+ this.setSeconds(n.getSeconds());
+ this.setMilliseconds(n.getMilliseconds());
+ return this;
+ };
+
+ /**
+ * Gets a date that is set to the current date. The time is set to the start of the day (00:00 or 12:00 AM).
+ * @return {Date} The current date.
+ */
+ $D.today = function () {
+ return new Date().clearTime();
+ };
+
+ /**
+ * Compares the first date to the second date and returns an number indication of their relative values.
+ * @param {Date} First Date object to compare [Required].
+ * @param {Date} Second Date object to compare to [Required].
+ * @return {Number} -1 = date1 is lessthan date2. 0 = values are equal. 1 = date1 is greaterthan date2.
+ */
+ $D.compare = function (date1, date2) {
+ if (isNaN(date1) || isNaN(date2)) {
+ throw new Error(date1 + " - " + date2);
+ } else if (date1 instanceof Date && date2 instanceof Date) {
+ return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0;
+ } else {
+ throw new TypeError(date1 + " - " + date2);
+ }
+ };
+
+ /**
+ * Compares the first Date object to the second Date object and returns true if they are equal.
+ * @param {Date} First Date object to compare [Required]
+ * @param {Date} Second Date object to compare to [Required]
+ * @return {Boolean} true if dates are equal. false if they are not equal.
+ */
+ $D.equals = function (date1, date2) {
+ return (date1.compareTo(date2) === 0);
+ };
+
+ /**
+ * Gets the day number (0-6) if given a CultureInfo specific string which is a valid dayName, abbreviatedDayName or shortestDayName (two char).
+ * @param {String} The name of the day (eg. "Monday, "Mon", "tuesday", "tue", "We", "we").
+ * @return {Number} The day number
+ */
+ $D.getDayNumberFromName = function (name) {
+ var n = $D.CultureInfo.dayNames, m = $D.CultureInfo.abbreviatedDayNames, o = $D.CultureInfo.shortestDayNames, s = name.toLowerCase();
+ for (var i = 0; i < n.length; i++) {
+ if (n[i].toLowerCase() == s || m[i].toLowerCase() == s || o[i].toLowerCase() == s) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * Gets the month number (0-11) if given a Culture Info specific string which is a valid monthName or abbreviatedMonthName.
+ * @param {String} The name of the month (eg. "February, "Feb", "october", "oct").
+ * @return {Number} The day number
+ */
+ $D.getMonthNumberFromName = function (name) {
+ var n = $D.CultureInfo.monthNames, m = $D.CultureInfo.abbreviatedMonthNames, s = name.toLowerCase();
+ for (var i = 0; i < n.length; i++) {
+ if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * Determines if the current date instance is within a LeapYear.
+ * @param {Number} The year.
+ * @return {Boolean} true if date is within a LeapYear, otherwise false.
+ */
+ $D.isLeapYear = function (year) {
+ return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
+ };
+
+ /**
+ * Gets the number of days in the month, given a year and month value. Automatically corrects for LeapYear.
+ * @param {Number} The year.
+ * @param {Number} The month (0-11).
+ * @return {Number} The number of days in the month.
+ */
+ $D.getDaysInMonth = function (year, month) {
+ return [31, ($D.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
+ };
+
+ $D.getTimezoneAbbreviation = function (offset) {
+ var z = $D.CultureInfo.timezones, p;
+ for (var i = 0; i < z.length; i++) {
+ if (z[i].offset === offset) {
+ return z[i].name;
+ }
+ }
+ return null;
+ };
+
+ $D.getTimezoneOffset = function (name) {
+ var z = $D.CultureInfo.timezones, p;
+ for (var i = 0; i < z.length; i++) {
+ if (z[i].name === name.toUpperCase()) {
+ return z[i].offset;
+ }
+ }
+ return null;
+ };
+
+ /**
+ * Returns a new Date object that is an exact date and time copy of the original instance.
+ * @return {Date} A new Date instance
+ */
+ $P.clone = function () {
+ return new Date(this.getTime());
+ };
+
+ /**
+ * Compares this instance to a Date object and returns an number indication of their relative values.
+ * @param {Date} Date object to compare [Required]
+ * @return {Number} -1 = this is lessthan date. 0 = values are equal. 1 = this is greaterthan date.
+ */
+ $P.compareTo = function (date) {
+ return Date.compare(this, date);
+ };
+
+ /**
+ * Compares this instance to another Date object and returns true if they are equal.
+ * @param {Date} Date object to compare. If no date to compare, new Date() [now] is used.
+ * @return {Boolean} true if dates are equal. false if they are not equal.
+ */
+ $P.equals = function (date) {
+ return Date.equals(this, date || new Date());
+ };
+
+ /**
+ * Determines if this instance is between a range of two dates or equal to either the start or end dates.
+ * @param {Date} Start of range [Required]
+ * @param {Date} End of range [Required]
+ * @return {Boolean} true is this is between or equal to the start and end dates, else false
+ */
+ $P.between = function (start, end) {
+ return this.getTime() >= start.getTime() && this.getTime() <= end.getTime();
+ };
+
+ /**
+ * Determines if this date occurs after the date to compare to.
+ * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used.
+ * @return {Boolean} true if this date instance is greater than the date to compare to (or "now"), otherwise false.
+ */
+ $P.isAfter = function (date) {
+ return this.compareTo(date || new Date()) === 1;
+ };
+
+ /**
+ * Determines if this date occurs before the date to compare to.
+ * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used.
+ * @return {Boolean} true if this date instance is less than the date to compare to (or "now").
+ */
+ $P.isBefore = function (date) {
+ return (this.compareTo(date || new Date()) === -1);
+ };
+
+ /**
+ * Determines if the current Date instance occurs today.
+ * @return {Boolean} true if this date instance is 'today', otherwise false.
+ */
+
+ /**
+ * Determines if the current Date instance occurs on the same Date as the supplied 'date'.
+ * If no 'date' to compare to is provided, the current Date instance is compared to 'today'.
+ * @param {date} Date object to compare. If no date to compare, the current Date ("now") is used.
+ * @return {Boolean} true if this Date instance occurs on the same Day as the supplied 'date'.
+ */
+ $P.isToday = $P.isSameDay = function (date) {
+ return this.clone().clearTime().equals((date || new Date()).clone().clearTime());
+ };
+
+ /**
+ * Adds the specified number of milliseconds to this instance.
+ * @param {Number} The number of milliseconds to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addMilliseconds = function (value) {
+ this.setMilliseconds(this.getMilliseconds() + value * 1);
+ return this;
+ };
+
+ /**
+ * Adds the specified number of seconds to this instance.
+ * @param {Number} The number of seconds to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addSeconds = function (value) {
+ return this.addMilliseconds(value * 1000);
+ };
+
+ /**
+ * Adds the specified number of seconds to this instance.
+ * @param {Number} The number of seconds to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addMinutes = function (value) {
+ return this.addMilliseconds(value * 60000); /* 60*1000 */
+ };
+
+ /**
+ * Adds the specified number of hours to this instance.
+ * @param {Number} The number of hours to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addHours = function (value) {
+ return this.addMilliseconds(value * 3600000); /* 60*60*1000 */
+ };
+
+ /**
+ * Adds the specified number of days to this instance.
+ * @param {Number} The number of days to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addDays = function (value) {
+ this.setDate(this.getDate() + value * 1);
+ return this;
+ };
+
+ /**
+ * Adds the specified number of weeks to this instance.
+ * @param {Number} The number of weeks to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addWeeks = function (value) {
+ return this.addDays(value * 7);
+ };
+
+ /**
+ * Adds the specified number of months to this instance.
+ * @param {Number} The number of months to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addMonths = function (value) {
+ var n = this.getDate();
+ this.setDate(1);
+ this.setMonth(this.getMonth() + value * 1);
+ this.setDate(Math.min(n, $D.getDaysInMonth(this.getFullYear(), this.getMonth())));
+ return this;
+ };
+
+ /**
+ * Adds the specified number of years to this instance.
+ * @param {Number} The number of years to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addYears = function (value) {
+ return this.addMonths(value * 12);
+ };
+
+ /**
+ * Adds (or subtracts) to the value of the years, months, weeks, days, hours, minutes, seconds, milliseconds of the date instance using given configuration object. Positive and Negative values allowed.
+ * Example
+ <pre><code>
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+ </code></pre>
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config == "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ var $y, $m, $d;
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * This algorithm is a JavaScript port of the work presented by Claus T�ndering at http://www.tondering.dk/claus/cal/node8.html#SECTION00880000000000000000
+ * .getWeek() Algorithm Copyright (c) 2008 Claus Tondering.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used. Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function () {
+ var a, b, c, d, e, f, g, n, s, w;
+
+ $y = (!$y) ? this.getFullYear() : $y;
+ $m = (!$m) ? this.getMonth() + 1 : $m;
+ $d = (!$d) ? this.getDate() : $d;
+
+ if ($m <= 2) {
+ a = $y - 1;
+ b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
+ c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
+ s = b - c;
+ e = 0;
+ f = $d - 1 + (31 * ($m - 1));
+ } else {
+ a = $y;
+ b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
+ c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
+ s = b - c;
+ e = s + 1;
+ f = $d + ((153 * ($m - 3) + 2) / 5) + 58 + s;
+ }
+
+ g = (a + b) % 7;
+ d = (f + g - e) % 7;
+ n = (f + 3 - d) | 0;
+
+ if (n < 0) {
+ w = 53 - ((g - s) / 5 | 0);
+ } else if (n > 364 + s) {
+ w = 1;
+ } else {
+ w = (n / 7 | 0) + 1;
+ }
+
+ $y = $m = $d = null;
+
+ return w;
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ $y = this.getUTCFullYear();
+ $m = this.getUTCMonth() + 1;
+ $d = this.getUTCDate();
+ return p(this.getWeek());
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ return this.moveToDayOfWeek(1).addWeeks(n - this.getWeek());
+ };
+
+ // private
+ var validate = function (n, min, max, name) {
+ if (typeof n == "undefined") {
+ return false;
+ } else if (typeof n != "number") {
+ throw new TypeError(n + " is not a Number.");
+ } else if (n < min || n > max) {
+ throw new RangeError(n + " is not a valid value for " + name + ".");
+ }
+ return true;
+ };
+
+ /**
+ * Validates the number is within an acceptable range for milliseconds [0-999].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMillisecond = function (value) {
+ return validate(value, 0, 999, "millisecond");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for seconds [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateSecond = function (value) {
+ return validate(value, 0, 59, "second");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for minutes [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMinute = function (value) {
+ return validate(value, 0, 59, "minute");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for hours [0-23].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateHour = function (value) {
+ return validate(value, 0, 23, "hour");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for the days in a month [0-MaxDaysInMonth].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateDay = function (value, year, month) {
+ return validate(value, 1, $D.getDaysInMonth(year, month), "day");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for months [0-11].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMonth = function (value) {
+ return validate(value, 0, 11, "month");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for years.
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateYear = function (value) {
+ return validate(value, 0, 9999, "year");
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+ <pre><code>
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+ </code></pre>
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ if ($D.validateMillisecond(config.millisecond)) {
+ this.addMilliseconds(config.millisecond - this.getMilliseconds());
+ }
+
+ if ($D.validateSecond(config.second)) {
+ this.addSeconds(config.second - this.getSeconds());
+ }
+
+ if ($D.validateMinute(config.minute)) {
+ this.addMinutes(config.minute - this.getMinutes());
+ }
+
+ if ($D.validateHour(config.hour)) {
+ this.addHours(config.hour - this.getHours());
+ }
+
+ if ($D.validateMonth(config.month)) {
+ this.addMonths(config.month - this.getMonth());
+ }
+
+ if ($D.validateYear(config.year)) {
+ this.addYears(config.year - this.getFullYear());
+ }
+
+ /* day has to go last because you can't validate the day without first knowing the month */
+ if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ if (config.timezone) {
+ this.setTimezone(config.timezone);
+ }
+
+ if (config.timezoneOffset) {
+ this.setTimezoneOffset(config.timezoneOffset);
+ }
+
+ if (config.week && validate(config.week, 0, 53, "week")) {
+ this.setWeek(config.week);
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = function (dayOfWeek, orient) {
+ var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7;
+ return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
+ };
+
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = function (month, orient) {
+ var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
+ return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
+ };
+
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return this.addMinutes(there - here);
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() != this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function () {
+ var n = this.getTimezoneOffset() * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ if (!$P.toISOString) {
+ /**
+ * Converts the current date instance into a string with an ISO 8601 format. The date is converted to it's UTC value.
+ * @return {String} ISO 8601 string of date
+ */
+ $P.toISOString = function () {
+ // From http://www.json.org/json.js. Public Domain.
+ function f(n) {
+ return n < 10 ? '0' + n : n;
+ }
+
+ return '"' + this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z"';
+ };
+ }
+
+ // private
+ $P._toString = $P.toString;
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ <pre>
+ CUSTOM DATE AND TIME FORMAT STRINGS
+ Format Description Example
+ ------ --------------------------------------------------------------------------- -----------------------
+ s The seconds of the minute between 0-59. "0" to "59"
+ ss The seconds of the minute with leading zero if required. "00" to "59"
+
+ m The minute of the hour between 0-59. "0" or "59"
+ mm The minute of the hour with leading zero if required. "00" or "59"
+
+ h The hour of the day between 1-12. "1" to "12"
+ hh The hour of the day with leading zero if required. "01" to "12"
+
+ H The hour of the day between 0-23. "0" to "23"
+ HH The hour of the day with leading zero if required. "00" to "23"
+
+ d The day of the month between 1 and 31. "1" to "31"
+ dd The day of the month with leading zero if required. "01" to "31"
+ ddd Abbreviated day name. $D.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ dddd The full day name. $D.CultureInfo.dayNames. "Monday" to "Sunday"
+
+ M The month of the year between 1-12. "1" to "12"
+ MM The month of the year with leading zero if required. "01" to "12"
+ MMM Abbreviated month name. $D.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ MMMM The full month name. $D.CultureInfo.monthNames. "January" to "December"
+
+ yy The year as a two-digit number. "99" or "08"
+ yyyy The full four digit year. "1999" or "2008"
+
+ t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ $D.CultureInfo.amDesignator or $D.CultureInfo.pmDesignator
+ tt Displays the A.M./P.M. designator. "AM" or "PM"
+ $D.CultureInfo.amDesignator or $D.CultureInfo.pmDesignator
+
+ S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+
+|| *Format* || *Description* || *Example* ||
+|| d || The CultureInfo shortDate Format Pattern || "M/d/yyyy" ||
+|| D || The CultureInfo longDate Format Pattern || "dddd, MMMM dd, yyyy" ||
+|| F || The CultureInfo fullDateTime Format Pattern || "dddd, MMMM dd, yyyy h:mm:ss tt" ||
+|| m || The CultureInfo monthDay Format Pattern || "MMMM dd" ||
+|| r || The CultureInfo rfc1123 Format Pattern || "ddd, dd MMM yyyy HH:mm:ss GMT" ||
+|| s || The CultureInfo sortableDateTime Format Pattern || "yyyy-MM-ddTHH:mm:ss" ||
+|| t || The CultureInfo shortTime Format Pattern || "h:mm tt" ||
+|| T || The CultureInfo longTime Format Pattern || "h:mm:ss tt" ||
+|| u || The CultureInfo universalSortableDateTime Format Pattern || "yyyy-MM-dd HH:mm:ssZ" ||
+|| y || The CultureInfo yearMonth Format Pattern || "MMMM, yyyy" ||
+
+
+ STANDARD DATE AND TIME FORMAT STRINGS
+ Format Description Example ("en-US")
+ ------ --------------------------------------------------------------------------- -----------------------
+ d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ m The CultureInfo monthDay Format Pattern "MMMM dd"
+ r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ t The CultureInfo shortTime Format Pattern "h:mm tt"
+ T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ $P.toString = function (format) {
+ var x = this;
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (format && format.length == 1) {
+ var c = $D.CultureInfo.formatPatterns;
+ x.t = x.toString;
+ switch (format) {
+ case "d":
+ return x.t(c.shortDate);
+ case "D":
+ return x.t(c.longDate);
+ case "F":
+ return x.t(c.fullDateTime);
+ case "m":
+ return x.t(c.monthDay);
+ case "r":
+ return x.t(c.rfc1123);
+ case "s":
+ return x.t(c.sortableDateTime);
+ case "t":
+ return x.t(c.shortTime);
+ case "T":
+ return x.t(c.longTime);
+ case "u":
+ return x.t(c.universalSortableDateTime);
+ case "y":
+ return x.t(c.yearMonth);
+ }
+ }
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+
+ return format ? format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,
+ function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ x.h = x.getHours;
+ switch (m) {
+ case "hh":
+ return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
+ case "h":
+ return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
+ case "HH":
+ return p(x.h());
+ case "H":
+ return x.h();
+ case "mm":
+ return p(x.getMinutes());
+ case "m":
+ return x.getMinutes();
+ case "ss":
+ return p(x.getSeconds());
+ case "s":
+ return x.getSeconds();
+ case "yyyy":
+ return p(x.getFullYear(), 4);
+ case "yy":
+ return p(x.getFullYear());
+ case "dddd":
+ return $D.CultureInfo.dayNames[x.getDay()];
+ case "ddd":
+ return $D.CultureInfo.abbreviatedDayNames[x.getDay()];
+ case "dd":
+ return p(x.getDate());
+ case "d":
+ return x.getDate();
+ case "MMMM":
+ return $D.CultureInfo.monthNames[x.getMonth()];
+ case "MMM":
+ return $D.CultureInfo.abbreviatedMonthNames[x.getMonth()];
+ case "MM":
+ return p((x.getMonth() + 1));
+ case "M":
+ return x.getMonth() + 1;
+ case "t":
+ return x.h() < 12 ? $D.CultureInfo.amDesignator.substring(0, 1) : $D.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return x.h() < 12 ? $D.CultureInfo.amDesignator : $D.CultureInfo.pmDesignator;
+ case "S":
+ return ord(x.getDate());
+ default:
+ return m;
+ }
+ }
+ ) : this._toString();
+ };
+}()); \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/date.js b/addons/web/static/lib/datejs/date.js
new file mode 100644
index 00000000000..eda450113bb
--- /dev/null
+++ b/addons/web/static/lib/datejs/date.js
@@ -0,0 +1,21 @@
+/**
+ * Please include a date.js file from the /build/ folder.
+ *
+ * Individual date.js files have been compiled for each of the 150+ supported Cultures.
+ *
+ * Example
+ * date.js // English (United States)
+ * date-en-US.js // English (United States)
+ * date-de-DE.js // Deutsch (Deutschland)
+ * date-es-MX.js // français (France)
+ */
+
+alert(
+ "Please include a date.js file from the /build/ folder.\n\n" +
+ "Individual date.js files have been compiled for each of the 150+ supported Cultures.\n\n" +
+ "Example\n" +
+ " date.js // English (United States)\n" +
+ " date-en-US.js // English (United States)\n" +
+ " date-de-DE.js // Deutsch (Deutschland)\n" +
+ " date-es-MX.js // français (France)\n"
+ ); \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/extras.js b/addons/web/static/lib/datejs/extras.js
new file mode 100644
index 00000000000..5ea64b9ed30
--- /dev/null
+++ b/addons/web/static/lib/datejs/extras.js
@@ -0,0 +1,331 @@
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ $f = [],
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with .$format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ <pre>
+ var f1 = "%m/%d/%y"
+ var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+
+ new Date().format(f1); // "04/13/08"
+ new Date().$format(f1); // "04/13/08"
+ new Date().toString(f2); // "04/13/08"
+
+ var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ </pre>
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ $D.normalizeFormat = function (format) {
+ $f = [];
+ var t = new Date().$format(format);
+ return $f.join("");
+ };
+
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example
+ <pre>
+ Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ return new Date(time * 1000).$format(format);
+ };
+
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example
+ <pre>
+ Date.strtotime("04/13/08"); // 1208044800
+ Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ d.addMinutes(d.getTimezoneOffset() * -1);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ *
+ * The following descriptions are from http://www.php.net/strftime and http://www.php.net/manual/en/function.date.php.
+ * Copyright � 2001-2008 The PHP Group
+ *
+ * Format Specifiers
+ <pre>
+ Format Description Example
+ ------ --------------------------------------------------------------------------- -----------------------
+ %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ %A full weekday name according to the current locale "Sunday" through "Saturday"
+ %b abbreviated month name according to the current locale "Jan" through "Dec"
+ %B full month name according to the current locale "January" through "December"
+ %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ %d day of the month as a decimal number "01" to "31"
+ %D same as %m/%d/%y "04/13/08"
+ %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ %g like %G, but without the century "08"
+ %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ This has the same format and value as %Y, except that if the ISO week number
+ belongs to the previous or next year, that year is used instead.
+ %h same as %b "Jan" through "Dec"
+ %H hour as a decimal number using a 24-hour clock "00" to "23"
+ %I hour as a decimal number using a 12-hour clock "01" to "12"
+ %j day of the year as a decimal number "001" to "366"
+ %m month as a decimal number "01" to "12"
+ %M minute as a decimal number "00" to "59"
+ %n newline character "\n"
+ %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ corresponding strings for the current locale
+ %r time in a.m. and p.m. notation "8:44 PM"
+ %R time in 24 hour notation "20:44"
+ %S second as a decimal number "00" to "59"
+ %t tab character "\t"
+ %T current time, equal to %H:%M:%S "12:49:11"
+ %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ first Sunday as the first day of the first week
+ %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ range 01 to 53, where week 1 is the first week that has at least 4 days
+ in the current year, and with Monday as the first day of the week.
+ (Use %G or %g for the year component that corresponds to the week number
+ for the specified timestamp.)
+ %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ first Monday as the first day of the first week
+ %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ %x preferred date representation for the current locale without the time "4/13/2008"
+ %X preferred time representation for the current locale without the date "12:53:05"
+ %y year as a decimal number without a century "00" "99"
+ %Y year as a decimal number including the century "2008"
+ %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ %z same as %Z
+ %% a literal "%" character "%"
+
+ d Day of the month, 2 digits with leading zeros "01" to "31"
+ D A textual representation of a day, three letters "Mon" through "Sun"
+ j Day of the month without leading zeros "1" to "31"
+ l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ z The day of the year (starting from "0") "0" through "365"
+ W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ F A full textual representation of a month, such as January or March "January" through "December"
+ m Numeric representation of a month, with leading zeros "01" through "12"
+ M A short textual representation of a month, three letters "Jan" through "Dec"
+ n Numeric representation of a month, without leading zeros "1" through "12"
+ t Number of days in the given month "28" through "31"
+ L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ ISO week number (W) belongs to the previous or next year, that year
+ is used instead.
+ Y A full numeric representation of a year, 4 digits "2008"
+ y A two digit representation of a year "08"
+ a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ B Swatch Internet time "000" through "999"
+ g 12-hour format of an hour without leading zeros "1" through "12"
+ G 24-hour format of an hour without leading zeros "0" through "23"
+ h 12-hour format of an hour with leading zeros "01" through "12"
+ H 24-hour format of an hour with leading zeros "00" through "23"
+ i Minutes with leading zeros "00" to "59"
+ s Seconds, with leading zeros "00" through "59"
+ u Milliseconds "54321"
+ e Timezone identifier "UTC", "EST", "PST"
+ I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ T Timezone abbreviation "UTC", "EST", "PST"
+ Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ always negative, and for those east of UTC is always positive.
+ c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ $P.$format = function (format) {
+ var x = this,
+ y,
+ t = function (v) {
+ $f.push(v);
+ return x.toString(v);
+ };
+
+ return format ? format.replace(/(%|\\)?.|%%/g,
+ function (m) {
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+ switch (m) {
+ case "d":
+ case "%d":
+ return t("dd");
+ case "D":
+ case "%a":
+ return t("ddd");
+ case "j":
+ case "%e":
+ return t("d");
+ case "l":
+ case "%A":
+ return t("dddd");
+ case "N":
+ case "%u":
+ return x.getDay() + 1;
+ case "S":
+ return t("S");
+ case "w":
+ case "%w":
+ return x.getDay();
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+ case "W":
+ case "%V":
+ return x.getISOWeek();
+ case "%W":
+ return p(x.getWeek());
+ case "F":
+ case "%B":
+ return t("MMMM");
+ case "m":
+ case "%m":
+ return t("MM");
+ case "M":
+ case "%b":
+ case "%h":
+ return t("MMM");
+ case "n":
+ return t("M");
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "L":
+ return ($D.isLeapYear(x.getFullYear())) ? 1 : 0;
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x.$format("%G").slice(-2);
+ case "Y":
+ case "%Y":
+ return t("yyyy");
+ case "y":
+ case "%y":
+ return t("yy");
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "g":
+ case "%I":
+ return t("h");
+ case "G":
+ return t("H");
+ case "h":
+ return t("hh");
+ case "H":
+ case "%H":
+ return t("HH");
+ case "i":
+ case "%M":
+ return t("mm");
+ case "s":
+ case "%S":
+ return t("ss");
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "e":
+ case "T":
+ case "%z":
+ case "%Z":
+ return x.getTimezone();
+ case "Z":
+ return x.getTimezoneOffset() * -60;
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ case "%D":
+ return t("MM/dd/yy");
+ case "%n":
+ return "\\n";
+ case "%t":
+ return "\\t";
+ case "%r":
+ return t("hh:mm tt");
+ case "%R":
+ return t("H:mm");
+ case "%T":
+ return t("H:mm:ss");
+ case "%x":
+ return t("d");
+ case "%X":
+ return t("t");
+ default:
+ $f.push(m);
+ return m;
+ }
+ }
+ ) : this._toString();
+ };
+
+ if (!$P.format) {
+ $P.format = $P.$format;
+ }
+}()); \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/af-ZA.js b/addons/web/static/lib/datejs/globalization/af-ZA.js
new file mode 100644
index 00000000000..579b8ff29c7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/af-ZA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "af-ZA",
+ englishName: "Afrikaans (South Africa)",
+ nativeName: "Afrikaans (Suid Afrika)",
+
+ /* Day Name Strings */
+ dayNames: ["Sondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrydag", "Saterdag"],
+ abbreviatedDayNames: ["Son", "Maan", "Dins", "Woen", "Dond", "Vry", "Sat"],
+ shortestDayNames: ["So", "Ma", "Di", "Wo", "Do", "Vr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "W", "D", "V", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januarie", "Februarie", "Maart", "April", "Mei", "Junie", "Julie", "Augustus", "September", "Oktober", "November", "Desember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "nm",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dd MMMM yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uarie)?/i,
+ feb: /^feb(ruarie)?/i,
+ mar: /^maart/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun(ie)?/i,
+ jul: /^jul(ie)?/i,
+ aug: /^aug(ustus)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^so(n(dag)?)?/i,
+ mon: /^ma(an(dag)?)?/i,
+ tue: /^di(ns(dag)?)?/i,
+ wed: /^wo(en(sdag)?)?/i,
+ thu: /^do(nd(erdag)?)?/i,
+ fri: /^vr(y(dag)?)?/i,
+ sat: /^sa(t(erdag)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-AE.js b/addons/web/static/lib/datejs/globalization/ar-AE.js
new file mode 100644
index 00000000000..ce88ff57256
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-AE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-AE",
+ englishName: "Arabic (U.A.E.)",
+ nativeName: "العربية (الإمارات العربية المتحدة)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-BH.js b/addons/web/static/lib/datejs/globalization/ar-BH.js
new file mode 100644
index 00000000000..bdd31de5ab9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-BH.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-BH",
+ englishName: "Arabic (Bahrain)",
+ nativeName: "العربية (البحرين)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-DZ.js b/addons/web/static/lib/datejs/globalization/ar-DZ.js
new file mode 100644
index 00000000000..404b26e2b34
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-DZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-DZ",
+ englishName: "Arabic (Algeria)",
+ nativeName: "العربية (الجزائر)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["جانفييه", "فيفرييه", "مارس", "أفريل", "مي", "جوان", "جوييه", "أوت", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["جانفييه", "فيفرييه", "مارس", "أفريل", "مي", "جوان", "جوييه", "أوت", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM, yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^جانفييه/i,
+ feb: /^فيفرييه/i,
+ mar: /^مارس/i,
+ apr: /^أفريل/i,
+ may: /^مي/i,
+ jun: /^جوان/i,
+ jul: /^جوييه/i,
+ aug: /^أوت/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-EG.js b/addons/web/static/lib/datejs/globalization/ar-EG.js
new file mode 100644
index 00000000000..eaf2850ee61
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-EG.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-EG",
+ englishName: "Arabic (Egypt)",
+ nativeName: "العربية (مصر)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-IQ.js b/addons/web/static/lib/datejs/globalization/ar-IQ.js
new file mode 100644
index 00000000000..5263d32d44f
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-IQ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-IQ",
+ englishName: "Arabic (Iraq)",
+ nativeName: "العربية (العراق)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+ abbreviatedMonthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^كانون الثاني/i,
+ feb: /^شباط/i,
+ mar: /^آذار/i,
+ apr: /^نيسان/i,
+ may: /^أيار/i,
+ jun: /^حزيران/i,
+ jul: /^تموز/i,
+ aug: /^آب/i,
+ sep: /^أيلول/i,
+ oct: /^تشرين الأول/i,
+ nov: /^تشرين الثاني/i,
+ dec: /^كانون الأول/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-JO.js b/addons/web/static/lib/datejs/globalization/ar-JO.js
new file mode 100644
index 00000000000..94d5797ec82
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-JO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-JO",
+ englishName: "Arabic (Jordan)",
+ nativeName: "العربية (الأردن)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+ abbreviatedMonthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^كانون الثاني/i,
+ feb: /^شباط/i,
+ mar: /^آذار/i,
+ apr: /^نيسان/i,
+ may: /^أيار/i,
+ jun: /^حزيران/i,
+ jul: /^تموز/i,
+ aug: /^آب/i,
+ sep: /^أيلول/i,
+ oct: /^تشرين الأول/i,
+ nov: /^تشرين الثاني/i,
+ dec: /^كانون الأول/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-KW.js b/addons/web/static/lib/datejs/globalization/ar-KW.js
new file mode 100644
index 00000000000..0918c330c1b
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-KW.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-KW",
+ englishName: "Arabic (Kuwait)",
+ nativeName: "العربية (الكويت)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-LB.js b/addons/web/static/lib/datejs/globalization/ar-LB.js
new file mode 100644
index 00000000000..dc06351ff66
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-LB.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-LB",
+ englishName: "Arabic (Lebanon)",
+ nativeName: "العربية (لبنان)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+ abbreviatedMonthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^كانون الثاني/i,
+ feb: /^شباط/i,
+ mar: /^آذار/i,
+ apr: /^نيسان/i,
+ may: /^أيار/i,
+ jun: /^حزيران/i,
+ jul: /^تموز/i,
+ aug: /^آب/i,
+ sep: /^أيلول/i,
+ oct: /^تشرين الأول/i,
+ nov: /^تشرين الثاني/i,
+ dec: /^كانون الأول/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-LY.js b/addons/web/static/lib/datejs/globalization/ar-LY.js
new file mode 100644
index 00000000000..95981d38f37
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-LY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-LY",
+ englishName: "Arabic (Libya)",
+ nativeName: "العربية (ليبيا)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-MA.js b/addons/web/static/lib/datejs/globalization/ar-MA.js
new file mode 100644
index 00000000000..050afc944da
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-MA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-MA",
+ englishName: "Arabic (Morocco)",
+ nativeName: "العربية (المملكة المغربية)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "ماي", "يونيو", "يوليوز", "غشت", "شتنبر", "اكتوبر", "نونبر", "دجنبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "ماي", "يونيو", "يوليوز", "غشت", "شتنبر", "اكتوبر", "نونبر", "دجنبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM, yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^ماي/i,
+ jun: /^يونيو/i,
+ jul: /^يوليوز/i,
+ aug: /^غشت/i,
+ sep: /^شتنبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نونبر/i,
+ dec: /^دجنبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-OM.js b/addons/web/static/lib/datejs/globalization/ar-OM.js
new file mode 100644
index 00000000000..133a782bec1
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-OM.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-OM",
+ englishName: "Arabic (Oman)",
+ nativeName: "العربية (عمان)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-QA.js b/addons/web/static/lib/datejs/globalization/ar-QA.js
new file mode 100644
index 00000000000..55bb6ee84d2
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-QA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-QA",
+ englishName: "Arabic (Qatar)",
+ nativeName: "العربية (قطر)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-SA.js b/addons/web/static/lib/datejs/globalization/ar-SA.js
new file mode 100644
index 00000000000..6ec866913b1
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-SA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-SA",
+ englishName: "Arabic (Saudi Arabia)",
+ nativeName: "العربية (المملكة العربية السعودية)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["ح", "ن", "ث", "ر", "خ", "ج", "س"],
+ firstLetterDayNames: ["ح", "ن", "ث", "ر", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["محرم", "صفر", "ربيع الأول", "ربيع الثاني", "جمادى الأولى", "جمادى الثانية", "رجب", "شعبان", "رمضان", "شوال", "ذو القعدة", "ذو الحجة"],
+ abbreviatedMonthNames: ["محرم", "صفر", "ربيع الاول", "ربيع الثاني", "جمادى الاولى", "جمادى الثانية", "رجب", "شعبان", "رمضان", "شوال", "ذو القعدة", "ذو الحجة"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 1451,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yy",
+ longDate: "dd/MMMM/yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd/MMMM/yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^محرم/i,
+ feb: /^صفر/i,
+ mar: /^ربيع الأول/i,
+ apr: /^ربيع الثاني/i,
+ may: /^جمادى الأولى/i,
+ jun: /^جمادى الثانية/i,
+ jul: /^رجب/i,
+ aug: /^شعبان/i,
+ sep: /^رمضان/i,
+ oct: /^شوال/i,
+ nov: /^ذو القعدة/i,
+ dec: /^ذو الحجة/i,
+
+ sun: /^الاحد/i,
+ mon: /^الاثنين/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-SY.js b/addons/web/static/lib/datejs/globalization/ar-SY.js
new file mode 100644
index 00000000000..317881211e6
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-SY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-SY",
+ englishName: "Arabic (Syria)",
+ nativeName: "العربية (سوريا)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+ abbreviatedMonthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^كانون الثاني/i,
+ feb: /^شباط/i,
+ mar: /^آذار/i,
+ apr: /^نيسان/i,
+ may: /^أيار/i,
+ jun: /^حزيران/i,
+ jul: /^تموز/i,
+ aug: /^آب/i,
+ sep: /^أيلول/i,
+ oct: /^تشرين الأول/i,
+ nov: /^تشرين الثاني/i,
+ dec: /^كانون الأول/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-TN.js b/addons/web/static/lib/datejs/globalization/ar-TN.js
new file mode 100644
index 00000000000..2e08507f434
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-TN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-TN",
+ englishName: "Arabic (Tunisia)",
+ nativeName: "العربية (تونس)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["جانفي", "فيفري", "مارس", "افريل", "ماي", "جوان", "جويلية", "اوت", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["جانفي", "فيفري", "مارس", "افريل", "ماي", "جوان", "جويلية", "اوت", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM, yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^جانفي/i,
+ feb: /^فيفري/i,
+ mar: /^مارس/i,
+ apr: /^افريل/i,
+ may: /^ماي/i,
+ jun: /^جوان/i,
+ jul: /^جويلية/i,
+ aug: /^اوت/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ar-YE.js b/addons/web/static/lib/datejs/globalization/ar-YE.js
new file mode 100644
index 00000000000..15f3e280842
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ar-YE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-YE",
+ englishName: "Arabic (Yemen)",
+ nativeName: "العربية (اليمن)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+ abbreviatedMonthNames: ["يناير", "فبراير", "مارس", "ابريل", "مايو", "يونيو", "يوليو", "اغسطس", "سبتمبر", "اكتوبر", "نوفمبر", "ديسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^يناير/i,
+ feb: /^فبراير/i,
+ mar: /^مارس/i,
+ apr: /^ابريل/i,
+ may: /^مايو/i,
+ jun: /^يونيو/i,
+ jul: /^يوليو/i,
+ aug: /^اغسطس/i,
+ sep: /^سبتمبر/i,
+ oct: /^اكتوبر/i,
+ nov: /^نوفمبر/i,
+ dec: /^ديسمبر/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/az-Cyrl-AZ.js b/addons/web/static/lib/datejs/globalization/az-Cyrl-AZ.js
new file mode 100644
index 00000000000..f4332edbf3a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/az-Cyrl-AZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "az-Cyrl-AZ",
+ englishName: "Azeri (Cyrillic, Azerbaijan)",
+ nativeName: "Азәрбајҹан (Азәрбајҹан)",
+
+ /* Day Name Strings */
+ dayNames: ["Базар", "Базар ертәси", "Чәршәнбә ахшамы", "Чәршәнбә", "Ҹүмә ахшамы", "Ҹүмә", "Шәнбә"],
+ abbreviatedDayNames: ["Б", "Бе", "Ча", "Ч", "Ҹа", "Ҹ", "Ш"],
+ shortestDayNames: ["Б", "Бе", "Ча", "Ч", "Ҹа", "Ҹ", "Ш"],
+ firstLetterDayNames: ["Б", "Б", "Ч", "Ч", "Ҹ", "Ҹ", "Ш"],
+
+ /* Month Name Strings */
+ monthNames: ["Јанвар", "Феврал", "Март", "Апрел", "Мај", "Ијун", "Ијул", "Август", "Сентјабр", "Октјабр", "Нојабр", "Декабр"],
+ abbreviatedMonthNames: ["Јан", "Фев", "Мар", "Апр", "Мај", "Ијун", "Ијул", "Авг", "Сен", "Окт", "Ноя", "Дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^јан(вар)?/i,
+ feb: /^фев(рал)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ел)?/i,
+ may: /^мај/i,
+ jun: /^ијун/i,
+ jul: /^ијул/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сен(тјабр)?/i,
+ oct: /^окт(јабр)?/i,
+ nov: /^нојабр/i,
+ dec: /^дек(абр)?/i,
+
+ sun: /^базар/i,
+ mon: /^базар ертәси/i,
+ tue: /^чәршәнбә ахшамы/i,
+ wed: /^чәршәнбә/i,
+ thu: /^ҹүмә ахшамы/i,
+ fri: /^ҹүмә/i,
+ sat: /^шәнбә/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/az-Latn-AZ.js b/addons/web/static/lib/datejs/globalization/az-Latn-AZ.js
new file mode 100644
index 00000000000..448c185813c
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/az-Latn-AZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "az-Latn-AZ",
+ englishName: "Azeri (Latin, Azerbaijan)",
+ nativeName: "Azərbaycan­ılı (Azərbaycanca)",
+
+ /* Day Name Strings */
+ dayNames: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə"],
+ abbreviatedDayNames: ["B", "Be", "Ça", "Ç", "Ca", "C", "Ş"],
+ shortestDayNames: ["B", "Be", "Ça", "Ç", "Ca", "C", "Ş"],
+ firstLetterDayNames: ["B", "B", "Ç", "Ç", "C", "C", "Ş"],
+
+ /* Month Name Strings */
+ monthNames: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avgust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"],
+ abbreviatedMonthNames: ["Yan", "Fev", "Mar", "Apr", "May", "İyun", "İyul", "Avg", "Sen", "Okt", "Noy", "Dek"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^yan(var)?/i,
+ feb: /^fev(ral)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^apr(el)?/i,
+ may: /^may/i,
+ jun: /^iyun/i,
+ jul: /^iyul/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sen(tyabr)?/i,
+ oct: /^okt(yabr)?/i,
+ nov: /^noy(abr)?/i,
+ dec: /^dek(abr)?/i,
+
+ sun: /^bazar/i,
+ mon: /^bazar ertəsi/i,
+ tue: /^çərşənbə axşamı/i,
+ wed: /^çərşənbə/i,
+ thu: /^cümə axşamı/i,
+ fri: /^cümə/i,
+ sat: /^şənbə/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/be-BY.js b/addons/web/static/lib/datejs/globalization/be-BY.js
new file mode 100644
index 00000000000..5add2e4d419
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/be-BY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "be-BY",
+ englishName: "Belarusian (Belarus)",
+ nativeName: "Беларускі (Беларусь)",
+
+ /* Day Name Strings */
+ dayNames: ["нядзеля", "панядзелак", "аўторак", "серада", "чацвер", "пятніца", "субота"],
+ abbreviatedDayNames: ["нд", "пн", "аў", "ср", "чц", "пт", "сб"],
+ shortestDayNames: ["нд", "пн", "аў", "ср", "чц", "пт", "сб"],
+ firstLetterDayNames: ["н", "п", "а", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["Студзень", "Люты", "Сакавік", "Красавік", "Май", "Чэрвень", "Ліпень", "Жнівень", "Верасень", "Кастрычнік", "Лістапад", "Снежань"],
+ abbreviatedMonthNames: ["Сту", "Лют", "Сак", "Кра", "Май", "Чэр", "Ліп", "Жні", "Вер", "Кас", "Ліс", "Сне"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^сту(дзень)?/i,
+ feb: /^лют(ы)?/i,
+ mar: /^сак(авік)?/i,
+ apr: /^кра(савік)?/i,
+ may: /^май/i,
+ jun: /^чэр(вень)?/i,
+ jul: /^ліп(ень)?/i,
+ aug: /^жні(вень)?/i,
+ sep: /^вер(асень)?/i,
+ oct: /^кас(трычнік)?/i,
+ nov: /^ліс(тапад)?/i,
+ dec: /^сне(жань)?/i,
+
+ sun: /^нядзеля/i,
+ mon: /^панядзелак/i,
+ tue: /^аўторак/i,
+ wed: /^серада/i,
+ thu: /^чацвер/i,
+ fri: /^пятніца/i,
+ sat: /^субота/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/bg-BG.js b/addons/web/static/lib/datejs/globalization/bg-BG.js
new file mode 100644
index 00000000000..d331ea7d70a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/bg-BG.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "bg-BG",
+ englishName: "Bulgarian (Bulgaria)",
+ nativeName: "български (България)",
+
+ /* Day Name Strings */
+ dayNames: ["неделя", "понеделник", "вторник", "сряда", "четвъртък", "петък", "събота"],
+ abbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ shortestDayNames: ["не", "по", "вт", "ср", "че", "пе", "съ"],
+ firstLetterDayNames: ["н", "п", "в", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
+ abbreviatedMonthNames: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.M.yyyy 'г.'",
+ longDate: "dd MMMM yyyy 'г.'",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy 'г.' HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy 'г.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^януари/i,
+ feb: /^февруари/i,
+ mar: /^март/i,
+ apr: /^април/i,
+ may: /^май/i,
+ jun: /^юни/i,
+ jul: /^юли/i,
+ aug: /^август/i,
+ sep: /^септември/i,
+ oct: /^октомври/i,
+ nov: /^ноември/i,
+ dec: /^декември/i,
+
+ sun: /^не((деля)?)?/i,
+ mon: /^по((неделник)?)?/i,
+ tue: /^вторник/i,
+ wed: /^сряда/i,
+ thu: /^че((твъртък)?)?/i,
+ fri: /^пе((тък)?)?/i,
+ sat: /^съ((бота)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/bs-Latn-BA.js b/addons/web/static/lib/datejs/globalization/bs-Latn-BA.js
new file mode 100644
index 00000000000..a63ccd154cf
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/bs-Latn-BA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "bs-Latn-BA",
+ englishName: "Bosnian (Bosnia and Herzegovina)",
+ nativeName: "bosanski (Bosna i Hercegovina)",
+
+ /* Day Name Strings */
+ dayNames: ["nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak", "petak", "subota"],
+ abbreviatedDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ shortestDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun/i,
+ jul: /^jul/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sep(tembar)?/i,
+ oct: /^okt(obar)?/i,
+ nov: /^nov(embar)?/i,
+ dec: /^dec(embar)?/i,
+
+ sun: /^nedjelja/i,
+ mon: /^ponedjeljak/i,
+ tue: /^utorak/i,
+ wed: /^srijeda/i,
+ thu: /^četvrtak/i,
+ fri: /^petak/i,
+ sat: /^subota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ca-ES.js b/addons/web/static/lib/datejs/globalization/ca-ES.js
new file mode 100644
index 00000000000..d2e426bc6c2
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ca-ES.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ca-ES",
+ englishName: "Catalan (Catalan)",
+ nativeName: "català (català)",
+
+ /* Day Name Strings */
+ dayNames: ["diumenge", "dilluns", "dimarts", "dimecres", "dijous", "divendres", "dissabte"],
+ abbreviatedDayNames: ["dg.", "dl.", "dt.", "dc.", "dj.", "dv.", "ds."],
+ shortestDayNames: ["dg", "dl", "dt", "dc", "dj", "dv", "ds"],
+ firstLetterDayNames: ["d", "d", "d", "d", "d", "d", "d"],
+
+ /* Month Name Strings */
+ monthNames: ["gener", "febrer", "març", "abril", "maig", "juny", "juliol", "agost", "setembre", "octubre", "novembre", "desembre"],
+ abbreviatedMonthNames: ["gen", "feb", "març", "abr", "maig", "juny", "jul", "ag", "set", "oct", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, d' / 'MMMM' / 'yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d' / 'MMMM' / 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' / 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^gen(er)?/i,
+ feb: /^feb(rer)?/i,
+ mar: /^març/i,
+ apr: /^abr(il)?/i,
+ may: /^maig/i,
+ jun: /^juny/i,
+ jul: /^jul(iol)?/i,
+ aug: /^ag(ost)?/i,
+ sep: /^set(embre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(embre)?/i,
+ dec: /^des(embre)?/i,
+
+ sun: /^dg((.(umenge)?)?)?/i,
+ mon: /^dl((.(lluns)?)?)?/i,
+ tue: /^dt((.(marts)?)?)?/i,
+ wed: /^dc((.(mecres)?)?)?/i,
+ thu: /^dj((.(jous)?)?)?/i,
+ fri: /^dv((.(vendres)?)?)?/i,
+ sat: /^ds((.(ssabte)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/cs-CZ.js b/addons/web/static/lib/datejs/globalization/cs-CZ.js
new file mode 100644
index 00000000000..1c573d3a320
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/cs-CZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "cs-CZ",
+ englishName: "Czech (Czech Republic)",
+ nativeName: "čeština (Česká republika)",
+
+ /* Day Name Strings */
+ dayNames: ["neděle", "pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota"],
+ abbreviatedDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"],
+ shortestDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"],
+ firstLetterDayNames: ["n", "p", "ú", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["leden", "únor", "březen", "duben", "květen", "červen", "červenec", "srpen", "září", "říjen", "listopad", "prosinec"],
+ abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"],
+
+ /* AM/PM Designators */
+ amDesignator: "dop.",
+ pmDesignator: "odp.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^leden/i,
+ feb: /^únor/i,
+ mar: /^březen/i,
+ apr: /^duben/i,
+ may: /^květen/i,
+ jun: /^červen/i,
+ jul: /^červenec/i,
+ aug: /^srpen/i,
+ sep: /^září/i,
+ oct: /^říjen/i,
+ nov: /^listopad/i,
+ dec: /^prosinec/i,
+
+ sun: /^neděle/i,
+ mon: /^pondělí/i,
+ tue: /^úterý/i,
+ wed: /^středa/i,
+ thu: /^čtvrtek/i,
+ fri: /^pátek/i,
+ sat: /^sobota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/cy-GB.js b/addons/web/static/lib/datejs/globalization/cy-GB.js
new file mode 100644
index 00000000000..95aa8ec8805
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/cy-GB.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "cy-GB",
+ englishName: "Welsh (United Kingdom)",
+ nativeName: "Cymraeg (y Deyrnas Unedig)",
+
+ /* Day Name Strings */
+ dayNames: ["Dydd Sul", "Dydd Llun", "Dydd Mawrth", "Dydd Mercher", "Dydd Iau", "Dydd Gwener", "Dydd Sadwrn"],
+ abbreviatedDayNames: ["Sul", "Llun", "Maw", "Mer", "Iau", "Gwe", "Sad"],
+ shortestDayNames: ["Sul", "Llun", "Maw", "Mer", "Iau", "Gwe", "Sad"],
+ firstLetterDayNames: ["S", "L", "M", "M", "I", "G", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Ionawr", "Chwefror", "Mawrth", "Ebrill", "Mai", "Mehefin", "Gorffennaf", "Awst", "Medi", "Hydref", "Tachwedd", "Rhagfyr"],
+ abbreviatedMonthNames: ["Ion", "Chwe", "Maw", "Ebr", "Mai", "Meh", "Gor", "Aws", "Med", "Hyd", "Tach", "Rhag"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ion(awr)?/i,
+ feb: /^chwe(fror)?/i,
+ mar: /^maw(rth)?/i,
+ apr: /^ebr(ill)?/i,
+ may: /^mai/i,
+ jun: /^meh(efin)?/i,
+ jul: /^gor(ffennaf)?/i,
+ aug: /^aws(t)?/i,
+ sep: /^med(i)?/i,
+ oct: /^hyd(ref)?/i,
+ nov: /^tach(wedd)?/i,
+ dec: /^rhag(fyr)?/i,
+
+ sun: /^dydd sul/i,
+ mon: /^dydd llun/i,
+ tue: /^dydd mawrth/i,
+ wed: /^dydd mercher/i,
+ thu: /^dydd iau/i,
+ fri: /^dydd gwener/i,
+ sat: /^dydd sadwrn/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/da-DK.js b/addons/web/static/lib/datejs/globalization/da-DK.js
new file mode 100644
index 00000000000..7299b5b393a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/da-DK.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "da-DK",
+ englishName: "Danish (Denmark)",
+ nativeName: "dansk (Danmark)",
+
+ /* Day Name Strings */
+ dayNames: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
+ abbreviatedDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ shortestDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "marts", "april", "maj", "juni", "juli", "august", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(ts)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^søndag/i,
+ mon: /^mandag/i,
+ tue: /^tirsdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lørdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/de-AT.js b/addons/web/static/lib/datejs/globalization/de-AT.js
new file mode 100644
index 00000000000..f9bfe255ae9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/de-AT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "de-AT",
+ englishName: "German (Austria)",
+ nativeName: "Deutsch (Österreich)",
+
+ /* Day Name Strings */
+ dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
+ abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Jänner", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
+ abbreviatedMonthNames: ["Jän", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, dd. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, dd. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jän(ner)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mär(z)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dez(ember)?/i,
+
+ sun: /^sonntag/i,
+ mon: /^montag/i,
+ tue: /^dienstag/i,
+ wed: /^mittwoch/i,
+ thu: /^donnerstag/i,
+ fri: /^freitag/i,
+ sat: /^samstag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/de-CH.js b/addons/web/static/lib/datejs/globalization/de-CH.js
new file mode 100644
index 00000000000..d8230611eb8
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/de-CH.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "de-CH",
+ englishName: "German (Switzerland)",
+ nativeName: "Deutsch (Schweiz)",
+
+ /* Day Name Strings */
+ dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
+ abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^märz/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dez(ember)?/i,
+
+ sun: /^sonntag/i,
+ mon: /^montag/i,
+ tue: /^dienstag/i,
+ wed: /^mittwoch/i,
+ thu: /^donnerstag/i,
+ fri: /^freitag/i,
+ sat: /^samstag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/de-DE.js b/addons/web/static/lib/datejs/globalization/de-DE.js
new file mode 100644
index 00000000000..757f15281a3
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/de-DE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "de-DE",
+ englishName: "German (Germany)",
+ nativeName: "Deutsch (Deutschland)",
+
+ /* Day Name Strings */
+ dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
+ abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^märz/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dez(ember)?/i,
+
+ sun: /^sonntag/i,
+ mon: /^montag/i,
+ tue: /^dienstag/i,
+ wed: /^mittwoch/i,
+ thu: /^donnerstag/i,
+ fri: /^freitag/i,
+ sat: /^samstag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/de-LI.js b/addons/web/static/lib/datejs/globalization/de-LI.js
new file mode 100644
index 00000000000..42423d8e664
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/de-LI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "de-LI",
+ englishName: "German (Liechtenstein)",
+ nativeName: "Deutsch (Liechtenstein)",
+
+ /* Day Name Strings */
+ dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
+ abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^märz/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dez(ember)?/i,
+
+ sun: /^sonntag/i,
+ mon: /^montag/i,
+ tue: /^dienstag/i,
+ wed: /^mittwoch/i,
+ thu: /^donnerstag/i,
+ fri: /^freitag/i,
+ sat: /^samstag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/de-LU.js b/addons/web/static/lib/datejs/globalization/de-LU.js
new file mode 100644
index 00000000000..bf0c0846ef9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/de-LU.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "de-LU",
+ englishName: "German (Luxembourg)",
+ nativeName: "Deutsch (Luxemburg)",
+
+ /* Day Name Strings */
+ dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
+ abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^märz/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dez(ember)?/i,
+
+ sun: /^sonntag/i,
+ mon: /^montag/i,
+ tue: /^dienstag/i,
+ wed: /^mittwoch/i,
+ thu: /^donnerstag/i,
+ fri: /^freitag/i,
+ sat: /^samstag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/dv-MV.js b/addons/web/static/lib/datejs/globalization/dv-MV.js
new file mode 100644
index 00000000000..fa15fdc4d6d
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/dv-MV.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "dv-MV",
+ englishName: "Divehi (Maldives)",
+ nativeName: "ދިވެހިބަސް (ދިވެހި ރާއްޖެ)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["ح", "ن", "ث", "ر", "خ", "ج", "س"],
+ firstLetterDayNames: ["ح", "ن", "ث", "ر", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["محرم", "صفر", "ربيع الأول", "ربيع الثاني", "جمادى الأولى", "جمادى الثانية", "رجب", "شعبان", "رمضان", "شوال", "ذو القعدة", "ذو الحجة"],
+ abbreviatedMonthNames: ["محرم", "صفر", "ربيع الاول", "ربيع الثاني", "جمادى الاولى", "جمادى الثانية", "رجب", "شعبان", "رمضان", "شوال", "ذو القعدة", "ذو الحجة"],
+
+ /* AM/PM Designators */
+ amDesignator: "މކ",
+ pmDesignator: "މފ",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 1451,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yy",
+ longDate: "dd/MMMM/yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd/MMMM/yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^محرم/i,
+ feb: /^صفر/i,
+ mar: /^ربيع الأول/i,
+ apr: /^ربيع الثاني/i,
+ may: /^جمادى الأولى/i,
+ jun: /^جمادى الثانية/i,
+ jul: /^رجب/i,
+ aug: /^شعبان/i,
+ sep: /^رمضان/i,
+ oct: /^شوال/i,
+ nov: /^ذو القعدة/i,
+ dec: /^ذو الحجة/i,
+
+ sun: /^الاحد/i,
+ mon: /^الاثنين/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/el-GR.js b/addons/web/static/lib/datejs/globalization/el-GR.js
new file mode 100644
index 00000000000..7d16738dce9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/el-GR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "el-GR",
+ englishName: "Greek (Greece)",
+ nativeName: "ελληνικά (Ελλάδα)",
+
+ /* Day Name Strings */
+ dayNames: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"],
+ abbreviatedDayNames: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"],
+ shortestDayNames: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σά"],
+ firstLetterDayNames: ["Κ", "Δ", "Τ", "Τ", "Π", "Π", "Σ"],
+
+ /* Month Name Strings */
+ monthNames: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"],
+ abbreviatedMonthNames: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαϊ", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"],
+
+ /* AM/PM Designators */
+ amDesignator: "πμ",
+ pmDesignator: "μμ",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d MMMM yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ιαν(ουάριος)?/i,
+ feb: /^φεβ(ρουάριος)?/i,
+ mar: /^μάρτιος/i,
+ apr: /^απρ(ίλιος)?/i,
+ may: /^μάιος/i,
+ jun: /^ιούνιος/i,
+ jul: /^ιούλιος/i,
+ aug: /^αύγουστος/i,
+ sep: /^σεπ(τέμβριος)?/i,
+ oct: /^οκτ(ώβριος)?/i,
+ nov: /^νοέμβριος/i,
+ dec: /^δεκ(έμβριος)?/i,
+
+ sun: /^κυ(ρ(ιακή)?)?/i,
+ mon: /^δε(υ(τέρα)?)?/i,
+ tue: /^τρ(ι(τη)?)?/i,
+ wed: /^τε(τ(άρτη)?)?/i,
+ thu: /^πε(μ(πτη)?)?/i,
+ fri: /^πα(ρ(ασκευή)?)?/i,
+ sat: /^σά(β(βατο)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-029.js b/addons/web/static/lib/datejs/globalization/en-029.js
new file mode 100644
index 00000000000..3a338ac72b5
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-029.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-029",
+ englishName: "English (Caribbean)",
+ nativeName: "English (Caribbean)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "MM/dd/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-AU.js b/addons/web/static/lib/datejs/globalization/en-AU.js
new file mode 100644
index 00000000000..7a8b0b36593
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-AU.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-AU",
+ englishName: "English (Australia)",
+ nativeName: "English (Australia)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/MM/yyyy",
+ longDate: "dddd, d MMMM yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-BZ.js b/addons/web/static/lib/datejs/globalization/en-BZ.js
new file mode 100644
index 00000000000..d92880048ec
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-BZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-BZ",
+ englishName: "English (Belize)",
+ nativeName: "English (Belize)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd MMMM yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-CA.js b/addons/web/static/lib/datejs/globalization/en-CA.js
new file mode 100644
index 00000000000..e919e1a48e9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-CA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-CA",
+ englishName: "English (Canada)",
+ nativeName: "English (Canada)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "MMMM d, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "MMMM d, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-GB.js b/addons/web/static/lib/datejs/globalization/en-GB.js
new file mode 100644
index 00000000000..6c43f4eb652
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-GB.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-GB",
+ englishName: "English (United Kingdom)",
+ nativeName: "English (United Kingdom)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-IE.js b/addons/web/static/lib/datejs/globalization/en-IE.js
new file mode 100644
index 00000000000..47538ef003b
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-IE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-IE",
+ englishName: "English (Ireland)",
+ nativeName: "English (Eire)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-JM.js b/addons/web/static/lib/datejs/globalization/en-JM.js
new file mode 100644
index 00000000000..f7bcf959de0
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-JM.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-JM",
+ englishName: "English (Jamaica)",
+ nativeName: "English (Jamaica)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-NZ.js b/addons/web/static/lib/datejs/globalization/en-NZ.js
new file mode 100644
index 00000000000..2d87ecc5907
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-NZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-NZ",
+ englishName: "English (New Zealand)",
+ nativeName: "English (New Zealand)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/MM/yyyy",
+ longDate: "dddd, d MMMM yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-PH.js b/addons/web/static/lib/datejs/globalization/en-PH.js
new file mode 100644
index 00000000000..cb72d0e6de6
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-PH.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-PH",
+ englishName: "English (Republic of the Philippines)",
+ nativeName: "English (Philippines)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-TT.js b/addons/web/static/lib/datejs/globalization/en-TT.js
new file mode 100644
index 00000000000..4ce78de5e13
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-TT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-TT",
+ englishName: "English (Trinidad and Tobago)",
+ nativeName: "English (Trinidad y Tobago)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd MMMM yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-US.js b/addons/web/static/lib/datejs/globalization/en-US.js
new file mode 100644
index 00000000000..190edc918b8
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-US.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-US",
+ englishName: "English (United States)",
+ nativeName: "English (United States)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-ZA.js b/addons/web/static/lib/datejs/globalization/en-ZA.js
new file mode 100644
index 00000000000..22219a329ca
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-ZA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-ZA",
+ englishName: "English (South Africa)",
+ nativeName: "English (South Africa)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dd MMMM yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/en-ZW.js b/addons/web/static/lib/datejs/globalization/en-ZW.js
new file mode 100644
index 00000000000..ab88bcd1a5c
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/en-ZW.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-ZW",
+ englishName: "English (Zimbabwe)",
+ nativeName: "English (Zimbabwe)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-AR.js b/addons/web/static/lib/datejs/globalization/es-AR.js
new file mode 100644
index 00000000000..6fb5e6b0e02
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-AR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-AR",
+ englishName: "Spanish (Argentina)",
+ nativeName: "Español (Argentina)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-BO.js b/addons/web/static/lib/datejs/globalization/es-BO.js
new file mode 100644
index 00000000000..c2d422919b2
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-BO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-BO",
+ englishName: "Spanish (Bolivia)",
+ nativeName: "Español (Bolivia)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-CL.js b/addons/web/static/lib/datejs/globalization/es-CL.js
new file mode 100644
index 00000000000..8cf18922932
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-CL.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-CL",
+ englishName: "Spanish (Chile)",
+ nativeName: "Español (Chile)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-CO.js b/addons/web/static/lib/datejs/globalization/es-CO.js
new file mode 100644
index 00000000000..7d4cbfa5bf3
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-CO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-CO",
+ englishName: "Spanish (Colombia)",
+ nativeName: "Español (Colombia)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-CR.js b/addons/web/static/lib/datejs/globalization/es-CR.js
new file mode 100644
index 00000000000..1a5012c14e7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-CR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-CR",
+ englishName: "Spanish (Costa Rica)",
+ nativeName: "Español (Costa Rica)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-DO.js b/addons/web/static/lib/datejs/globalization/es-DO.js
new file mode 100644
index 00000000000..2ff8a2ea531
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-DO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-DO",
+ englishName: "Spanish (Dominican Republic)",
+ nativeName: "Español (República Dominicana)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-EC.js b/addons/web/static/lib/datejs/globalization/es-EC.js
new file mode 100644
index 00000000000..9847d0c6d35
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-EC.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-EC",
+ englishName: "Spanish (Ecuador)",
+ nativeName: "Español (Ecuador)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-ES.js b/addons/web/static/lib/datejs/globalization/es-ES.js
new file mode 100644
index 00000000000..91e7183dd8d
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-ES.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-ES",
+ englishName: "Spanish (Spain)",
+ nativeName: "español (España)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-GT.js b/addons/web/static/lib/datejs/globalization/es-GT.js
new file mode 100644
index 00000000000..7a7edaf863f
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-GT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-GT",
+ englishName: "Spanish (Guatemala)",
+ nativeName: "Español (Guatemala)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-HN.js b/addons/web/static/lib/datejs/globalization/es-HN.js
new file mode 100644
index 00000000000..c1dc596ee87
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-HN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-HN",
+ englishName: "Spanish (Honduras)",
+ nativeName: "Español (Honduras)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-MX.js b/addons/web/static/lib/datejs/globalization/es-MX.js
new file mode 100644
index 00000000000..52ef0ab2b12
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-MX.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-MX",
+ englishName: "Spanish (Mexico)",
+ nativeName: "Español (México)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-NI.js b/addons/web/static/lib/datejs/globalization/es-NI.js
new file mode 100644
index 00000000000..850dbcb6abb
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-NI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-NI",
+ englishName: "Spanish (Nicaragua)",
+ nativeName: "Español (Nicaragua)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-PA.js b/addons/web/static/lib/datejs/globalization/es-PA.js
new file mode 100644
index 00000000000..85351d74dc2
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-PA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-PA",
+ englishName: "Spanish (Panama)",
+ nativeName: "Español (Panamá)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "MM/dd/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-PE.js b/addons/web/static/lib/datejs/globalization/es-PE.js
new file mode 100644
index 00000000000..3084ad4c120
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-PE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-PE",
+ englishName: "Spanish (Peru)",
+ nativeName: "Español (Perú)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-PR.js b/addons/web/static/lib/datejs/globalization/es-PR.js
new file mode 100644
index 00000000000..a1c86c413c9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-PR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-PR",
+ englishName: "Spanish (Puerto Rico)",
+ nativeName: "Español (Puerto Rico)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-PY.js b/addons/web/static/lib/datejs/globalization/es-PY.js
new file mode 100644
index 00000000000..96f61aeeced
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-PY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-PY",
+ englishName: "Spanish (Paraguay)",
+ nativeName: "Español (Paraguay)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-SV.js b/addons/web/static/lib/datejs/globalization/es-SV.js
new file mode 100644
index 00000000000..f92011935e4
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-SV.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-SV",
+ englishName: "Spanish (El Salvador)",
+ nativeName: "Español (El Salvador)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-UY.js b/addons/web/static/lib/datejs/globalization/es-UY.js
new file mode 100644
index 00000000000..dc8ae404a53
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-UY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-UY",
+ englishName: "Spanish (Uruguay)",
+ nativeName: "Español (Uruguay)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/es-VE.js b/addons/web/static/lib/datejs/globalization/es-VE.js
new file mode 100644
index 00000000000..087110fb229
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/es-VE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-VE",
+ englishName: "Spanish (Venezuela)",
+ nativeName: "Español (Republica Bolivariana de Venezuela)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/et-EE.js b/addons/web/static/lib/datejs/globalization/et-EE.js
new file mode 100644
index 00000000000..aef9fddf778
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/et-EE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "et-EE",
+ englishName: "Estonian (Estonia)",
+ nativeName: "eesti (Eesti)",
+
+ /* Day Name Strings */
+ dayNames: ["pühapäev", "esmaspäev", "teisipäev", "kolmapäev", "neljapäev", "reede", "laupäev"],
+ abbreviatedDayNames: ["P", "E", "T", "K", "N", "R", "L"],
+ shortestDayNames: ["P", "E", "T", "K", "N", "R", "L"],
+ firstLetterDayNames: ["P", "E", "T", "K", "N", "R", "L"],
+
+ /* Month Name Strings */
+ monthNames: ["jaanuar", "veebruar", "märts", "aprill", "mai", "juuni", "juuli", "august", "september", "oktoober", "november", "detsember"],
+ abbreviatedMonthNames: ["jaan", "veebr", "märts", "apr", "mai", "juuni", "juuli", "aug", "sept", "okt", "nov", "dets"],
+
+ /* AM/PM Designators */
+ amDesignator: "EL",
+ pmDesignator: "PL",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.MM.yyyy",
+ longDate: "d. MMMM yyyy'. a.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy'. a.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy'. a.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jaan(uar)?/i,
+ feb: /^veebr(uar)?/i,
+ mar: /^märts/i,
+ apr: /^apr(ill)?/i,
+ may: /^mai/i,
+ jun: /^juuni/i,
+ jul: /^juuli/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(oober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dets(ember)?/i,
+
+ sun: /^pühapäev/i,
+ mon: /^esmaspäev/i,
+ tue: /^teisipäev/i,
+ wed: /^kolmapäev/i,
+ thu: /^neljapäev/i,
+ fri: /^reede/i,
+ sat: /^laupäev/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/eu-ES.js b/addons/web/static/lib/datejs/globalization/eu-ES.js
new file mode 100644
index 00000000000..44d0cfa12ba
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/eu-ES.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "eu-ES",
+ englishName: "Basque (Basque)",
+ nativeName: "euskara (euskara)",
+
+ /* Day Name Strings */
+ dayNames: ["igandea", "astelehena", "asteartea", "asteazkena", "osteguna", "ostirala", "larunbata"],
+ abbreviatedDayNames: ["ig.", "al.", "as.", "az.", "og.", "or.", "lr."],
+ shortestDayNames: ["ig", "al", "as", "az", "og", "or", "lr"],
+ firstLetterDayNames: ["i", "a", "a", "a", "o", "o", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["urtarrila", "otsaila", "martxoa", "apirila", "maiatza", "ekaina", "uztaila", "abuztua", "iraila", "urria", "azaroa", "abendua"],
+ abbreviatedMonthNames: ["urt.", "ots.", "mar.", "api.", "mai.", "eka.", "uzt.", "abu.", "ira.", "urr.", "aza.", "abe."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dddd, yyyy.'eko' MMMM'k 'd",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, yyyy.'eko' MMMM'k 'd HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "yyyy.'eko' MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^urt(.(arrila)?)?/i,
+ feb: /^ots(.(aila)?)?/i,
+ mar: /^mar(.(txoa)?)?/i,
+ apr: /^api(.(rila)?)?/i,
+ may: /^mai(.(atza)?)?/i,
+ jun: /^eka(.(ina)?)?/i,
+ jul: /^uzt(.(aila)?)?/i,
+ aug: /^abu(.(ztua)?)?/i,
+ sep: /^ira(.(ila)?)?/i,
+ oct: /^urr(.(ia)?)?/i,
+ nov: /^aza(.(roa)?)?/i,
+ dec: /^abe(.(ndua)?)?/i,
+
+ sun: /^ig((.(andea)?)?)?/i,
+ mon: /^al((.(telehena)?)?)?/i,
+ tue: /^as((.(teartea)?)?)?/i,
+ wed: /^az((.(teazkena)?)?)?/i,
+ thu: /^og((.(teguna)?)?)?/i,
+ fri: /^or((.(tirala)?)?)?/i,
+ sat: /^lr((.(runbata)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fa-IR.js b/addons/web/static/lib/datejs/globalization/fa-IR.js
new file mode 100644
index 00000000000..03941d6142e
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fa-IR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fa-IR",
+ englishName: "Persian (Iran)",
+ nativeName: "فارسى (ايران)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "ق.ظ",
+ pmDesignator: "ب.ظ",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fi-FI.js b/addons/web/static/lib/datejs/globalization/fi-FI.js
new file mode 100644
index 00000000000..21febcc311a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fi-FI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fi-FI",
+ englishName: "Finnish (Finland)",
+ nativeName: "suomi (Suomi)",
+
+ /* Day Name Strings */
+ dayNames: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"],
+ abbreviatedDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"],
+ shortestDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"],
+ firstLetterDayNames: ["s", "m", "t", "k", "t", "p", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
+ abbreviatedMonthNames: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM'ta 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM'ta 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM'ta'",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^tammi(kuu)?/i,
+ feb: /^helmi(kuu)?/i,
+ mar: /^maalis(kuu)?/i,
+ apr: /^huhti(kuu)?/i,
+ may: /^touko(kuu)?/i,
+ jun: /^kesä(kuu)?/i,
+ jul: /^heinä(kuu)?/i,
+ aug: /^elo(kuu)?/i,
+ sep: /^syys(kuu)?/i,
+ oct: /^loka(kuu)?/i,
+ nov: /^marras(kuu)?/i,
+ dec: /^joulu(kuu)?/i,
+
+ sun: /^sunnuntai/i,
+ mon: /^maanantai/i,
+ tue: /^tiistai/i,
+ wed: /^keskiviikko/i,
+ thu: /^torstai/i,
+ fri: /^perjantai/i,
+ sat: /^lauantai/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fo-FO.js b/addons/web/static/lib/datejs/globalization/fo-FO.js
new file mode 100644
index 00000000000..4deb50d8d82
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fo-FO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fo-FO",
+ englishName: "Faroese (Faroe Islands)",
+ nativeName: "føroyskt (Føroyar)",
+
+ /* Day Name Strings */
+ dayNames: ["sunnudagur", "mánadagur", "týsdagur", "mikudagur", "hósdagur", "fríggjadagur", "leygardagur"],
+ abbreviatedDayNames: ["sun", "mán", "týs", "mik", "hós", "frí", "leyg"],
+ shortestDayNames: ["su", "má", "tý", "mi", "hó", "fr", "ley"],
+ firstLetterDayNames: ["s", "m", "t", "m", "h", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mars", "apríl", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH.mm",
+ longTime: "HH.mm.ss",
+ fullDateTime: "d. MMMM yyyy HH.mm.ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(íl)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^su(n(nudagur)?)?/i,
+ mon: /^má(n(adagur)?)?/i,
+ tue: /^tý(s(dagur)?)?/i,
+ wed: /^mi(k(udagur)?)?/i,
+ thu: /^hó(s(dagur)?)?/i,
+ fri: /^fr(í(ggjadagur)?)?/i,
+ sat: /^ley(g(ardagur)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fr-BE.js b/addons/web/static/lib/datejs/globalization/fr-BE.js
new file mode 100644
index 00000000000..d4592a8a01a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fr-BE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-BE",
+ englishName: "French (Belgium)",
+ nativeName: "français (Belgique)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fr-CA.js b/addons/web/static/lib/datejs/globalization/fr-CA.js
new file mode 100644
index 00000000000..28f0d6bb617
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fr-CA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-CA",
+ englishName: "French (Canada)",
+ nativeName: "français (Canada)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fr-CH.js b/addons/web/static/lib/datejs/globalization/fr-CH.js
new file mode 100644
index 00000000000..a1cb4efc5c0
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fr-CH.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-CH",
+ englishName: "French (Switzerland)",
+ nativeName: "français (Suisse)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fr-FR.js b/addons/web/static/lib/datejs/globalization/fr-FR.js
new file mode 100644
index 00000000000..50efe1e26d7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fr-FR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-FR",
+ englishName: "French (France)",
+ nativeName: "français (France)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fr-LU.js b/addons/web/static/lib/datejs/globalization/fr-LU.js
new file mode 100644
index 00000000000..0ee8fcbe333
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fr-LU.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-LU",
+ englishName: "French (Luxembourg)",
+ nativeName: "français (Luxembourg)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/fr-MC.js b/addons/web/static/lib/datejs/globalization/fr-MC.js
new file mode 100644
index 00000000000..d17af59e730
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/fr-MC.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-MC",
+ englishName: "French (Principality of Monaco)",
+ nativeName: "français (Principauté de Monaco)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/gl-ES.js b/addons/web/static/lib/datejs/globalization/gl-ES.js
new file mode 100644
index 00000000000..edadc90b9d0
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/gl-ES.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "gl-ES",
+ englishName: "Galician (Galician)",
+ nativeName: "galego (galego)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "luns", "martes", "mércores", "xoves", "venres", "sábado"],
+ abbreviatedDayNames: ["dom", "luns", "mar", "mér", "xov", "ven", "sab"],
+ shortestDayNames: ["do", "lu", "ma", "mé", "xo", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "x", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["xaneiro", "febreiro", "marzo", "abril", "maio", "xuño", "xullo", "agosto", "setembro", "outubro", "novembro", "decembro"],
+ abbreviatedMonthNames: ["xan", "feb", "mar", "abr", "maio", "xuñ", "xull", "ago", "set", "out", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^xan(eiro)?/i,
+ feb: /^feb(reiro)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^maio/i,
+ jun: /^xuñ(o)?/i,
+ jul: /^xull(o)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(embro)?/i,
+ oct: /^out(ubro)?/i,
+ nov: /^nov(embro)?/i,
+ dec: /^dec(embro)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(1)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mé(r(cores)?)?/i,
+ thu: /^xo(v(es)?)?/i,
+ fri: /^ve(n(res)?)?/i,
+ sat: /^sa(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/gu-IN.js b/addons/web/static/lib/datejs/globalization/gu-IN.js
new file mode 100644
index 00000000000..f7998099be6
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/gu-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "gu-IN",
+ englishName: "Gujarati (India)",
+ nativeName: "ગુજરાતી (ભારત)",
+
+ /* Day Name Strings */
+ dayNames: ["રવિવાર", "સોમવાર", "મંગળવાર", "બુધવાર", "ગુરુવાર", "શુક્રવાર", "શનિવાર"],
+ abbreviatedDayNames: ["રવિ", "સોમ", "મંગળ", "બુધ", "ગુરુ", "શુક્ર", "શનિ"],
+ shortestDayNames: ["ર", "સ", "મ", "બ", "ગ", "શ", "શ"],
+ firstLetterDayNames: ["ર", "સ", "મ", "બ", "ગ", "શ", "શ"],
+
+ /* Month Name Strings */
+ monthNames: ["જાન્યુઆરી", "ફેબ્રુઆરી", "માર્ચ", "એપ્રિલ", "મે", "જૂન", "જુલાઈ", "ઑગસ્ટ", "સપ્ટેમ્બર", "ઑક્ટ્બર", "નવેમ્બર", "ડિસેમ્બર"],
+ abbreviatedMonthNames: ["જાન્યુ", "ફેબ્રુ", "માર્ચ", "એપ્રિલ", "મે", "જૂન", "જુલાઈ", "ઑગસ્ટ", "સપ્ટે", "ઑક્ટો", "નવે", "ડિસે"],
+
+ /* AM/PM Designators */
+ amDesignator: "પૂર્વ મધ્યાહ્ન",
+ pmDesignator: "ઉત્તર મધ્યાહ્ન",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^જાન્યુ(આરી)?/i,
+ feb: /^ફેબ્રુ(આરી)?/i,
+ mar: /^માર્ચ/i,
+ apr: /^એપ્રિલ/i,
+ may: /^મે/i,
+ jun: /^જૂન/i,
+ jul: /^જુલાઈ/i,
+ aug: /^ઑગસ્ટ/i,
+ sep: /^સપ્ટે(મ્બર)?/i,
+ oct: /^ઑક્ટ્બર/i,
+ nov: /^નવે(મ્બર)?/i,
+ dec: /^ડિસે(મ્બર)?/i,
+
+ sun: /^ર(વિ(વાર)?)?/i,
+ mon: /^સ(ોમ(વાર)?)?/i,
+ tue: /^મ(ંગળ(વાર)?)?/i,
+ wed: /^બ(ુધ(વાર)?)?/i,
+ thu: /^ગ(ુરુ(વાર)?)?/i,
+ fri: /^શ(ુક્ર(વાર)?)?/i,
+ sat: /^શ(નિ(વાર)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/he-IL.js b/addons/web/static/lib/datejs/globalization/he-IL.js
new file mode 100644
index 00000000000..07ebb4ccb20
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/he-IL.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "he-IL",
+ englishName: "Hebrew (Israel)",
+ nativeName: "עברית (ישראל)",
+
+ /* Day Name Strings */
+ dayNames: ["יום ראשון", "יום שני", "יום שלישי", "יום רביעי", "יום חמישי", "יום שישי", "שבת"],
+ abbreviatedDayNames: ["יום א", "יום ב", "יום ג", "יום ד", "יום ה", "יום ו", "שבת"],
+ shortestDayNames: ["א", "ב", "ג", "ד", "ה", "ו", "ש"],
+ firstLetterDayNames: ["א", "ב", "ג", "ד", "ה", "ו", "ש"],
+
+ /* Month Name Strings */
+ monthNames: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"],
+ abbreviatedMonthNames: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ינו(אר)?/i,
+ feb: /^פבר(ואר)?/i,
+ mar: /^מרץ/i,
+ apr: /^אפר(יל)?/i,
+ may: /^מאי/i,
+ jun: /^יונ(י)?/i,
+ jul: /^יול(י)?/i,
+ aug: /^אוג(וסט)?/i,
+ sep: /^ספט(מבר)?/i,
+ oct: /^אוק(טובר)?/i,
+ nov: /^נוב(מבר)?/i,
+ dec: /^דצמ(בר)?/i,
+
+ sun: /^א(ום א(אשון)?)?/i,
+ mon: /^ב(ום ב(ני)?)?/i,
+ tue: /^ג(ום ג(לישי)?)?/i,
+ wed: /^ד(ום ד(ביעי)?)?/i,
+ thu: /^ה(ום ה(מישי)?)?/i,
+ fri: /^ו(ום ו(ישי)?)?/i,
+ sat: /^ש(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/hi-IN.js b/addons/web/static/lib/datejs/globalization/hi-IN.js
new file mode 100644
index 00000000000..3e65e2aea7d
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/hi-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "hi-IN",
+ englishName: "Hindi (India)",
+ nativeName: "हिंदी (भारत)",
+
+ /* Day Name Strings */
+ dayNames: ["रविवार", "सोमवार", "मंगलवार", "बुधवार", "गुरुवार", "शुक्रवार", "शनिवार"],
+ abbreviatedDayNames: ["रवि.", "सोम.", "मंगल.", "बुध.", "गुरु.", "शुक्र.", "शनि."],
+ shortestDayNames: ["र", "स", "म", "ब", "ग", "श", "श"],
+ firstLetterDayNames: ["र", "स", "म", "ब", "ग", "श", "श"],
+
+ /* Month Name Strings */
+ monthNames: ["जनवरी", "फरवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितम्बर", "अक्तूबर", "नवम्बर", "दिसम्बर"],
+ abbreviatedMonthNames: ["जनवरी", "फरवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितम्बर", "अक्तूबर", "नवम्बर", "दिसम्बर"],
+
+ /* AM/PM Designators */
+ amDesignator: "पूर्वाह्न",
+ pmDesignator: "अपराह्न",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^जनवरी/i,
+ feb: /^फरवरी/i,
+ mar: /^मार्च/i,
+ apr: /^अप्रैल/i,
+ may: /^मई/i,
+ jun: /^जून/i,
+ jul: /^जुलाई/i,
+ aug: /^अगस्त/i,
+ sep: /^सितम्बर/i,
+ oct: /^अक्तूबर/i,
+ nov: /^नवम्बर/i,
+ dec: /^दिसम्बर/i,
+
+ sun: /^र(वि(.(वार)?)?)?/i,
+ mon: /^स(ोम(.(वार)?)?)?/i,
+ tue: /^म(ंगल(.(वार)?)?)?/i,
+ wed: /^ब(ुध(.(वार)?)?)?/i,
+ thu: /^ग(ुरु(.(वार)?)?)?/i,
+ fri: /^श(ुक्र(.(वार)?)?)?/i,
+ sat: /^श(नि(.(वार)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/hr-BA.js b/addons/web/static/lib/datejs/globalization/hr-BA.js
new file mode 100644
index 00000000000..b7314386f30
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/hr-BA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "hr-BA",
+ englishName: "Croatian (Bosnia and Herzegovina)",
+ nativeName: "hrvatski (Bosna i Hercegovina)",
+
+ /* Day Name Strings */
+ dayNames: ["nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak", "petak", "subota"],
+ abbreviatedDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ shortestDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["siječanj", "veljača", "ožujak", "travanj", "svibanj", "lipanj", "srpanj", "kolovoz", "rujan", "listopad", "studeni", "prosinac"],
+ abbreviatedMonthNames: ["sij", "vlj", "ožu", "tra", "svi", "lip", "srp", "kol", "ruj", "lis", "stu", "pro"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^sij(ečanj)?/i,
+ feb: /^veljača/i,
+ mar: /^ožu(jak)?/i,
+ apr: /^tra(vanj)?/i,
+ may: /^svi(banj)?/i,
+ jun: /^lip(anj)?/i,
+ jul: /^srp(anj)?/i,
+ aug: /^kol(ovoz)?/i,
+ sep: /^ruj(an)?/i,
+ oct: /^lis(topad)?/i,
+ nov: /^stu(deni)?/i,
+ dec: /^pro(sinac)?/i,
+
+ sun: /^nedjelja/i,
+ mon: /^ponedjeljak/i,
+ tue: /^utorak/i,
+ wed: /^srijeda/i,
+ thu: /^četvrtak/i,
+ fri: /^petak/i,
+ sat: /^subota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/hr-HR.js b/addons/web/static/lib/datejs/globalization/hr-HR.js
new file mode 100644
index 00000000000..5f0ff352606
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/hr-HR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "hr-HR",
+ englishName: "Croatian (Croatia)",
+ nativeName: "hrvatski (Hrvatska)",
+
+ /* Day Name Strings */
+ dayNames: ["nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak", "petak", "subota"],
+ abbreviatedDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ shortestDayNames: ["ne", "po", "ut", "sr", "če", "pe", "su"],
+ firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["siječanj", "veljača", "ožujak", "travanj", "svibanj", "lipanj", "srpanj", "kolovoz", "rujan", "listopad", "studeni", "prosinac"],
+ abbreviatedMonthNames: ["sij", "vlj", "ožu", "tra", "svi", "lip", "srp", "kol", "ruj", "lis", "stu", "pro"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^sij(ečanj)?/i,
+ feb: /^veljača/i,
+ mar: /^ožu(jak)?/i,
+ apr: /^tra(vanj)?/i,
+ may: /^svi(banj)?/i,
+ jun: /^lip(anj)?/i,
+ jul: /^srp(anj)?/i,
+ aug: /^kol(ovoz)?/i,
+ sep: /^ruj(an)?/i,
+ oct: /^lis(topad)?/i,
+ nov: /^stu(deni)?/i,
+ dec: /^pro(sinac)?/i,
+
+ sun: /^ne(d(jelja)?)?/i,
+ mon: /^po(n(edjeljak)?)?/i,
+ tue: /^ut(o(rak)?)?/i,
+ wed: /^sr(i(jeda)?)?/i,
+ thu: /^če(t(vrtak)?)?/i,
+ fri: /^pe(t(ak)?)?/i,
+ sat: /^su(b(ota)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/hu-HU.js b/addons/web/static/lib/datejs/globalization/hu-HU.js
new file mode 100644
index 00000000000..c6518182e67
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/hu-HU.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "hu-HU",
+ englishName: "Hungarian (Hungary)",
+ nativeName: "magyar (Magyarország)",
+
+ /* Day Name Strings */
+ dayNames: ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"],
+ abbreviatedDayNames: ["V", "H", "K", "Sze", "Cs", "P", "Szo"],
+ shortestDayNames: ["V", "H", "K", "Sze", "Cs", "P", "Szo"],
+ firstLetterDayNames: ["V", "H", "K", "S", "C", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"],
+ abbreviatedMonthNames: ["jan.", "febr.", "márc.", "ápr.", "máj.", "jún.", "júl.", "aug.", "szept.", "okt.", "nov.", "dec."],
+
+ /* AM/PM Designators */
+ amDesignator: "de.",
+ pmDesignator: "du.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy. MM. dd.",
+ longDate: "yyyy. MMMM d.",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy. MMMM d. H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM d.",
+ yearMonth: "yyyy. MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(.(uár)?)?/i,
+ feb: /^febr(.(uár)?)?/i,
+ mar: /^márc(.(ius)?)?/i,
+ apr: /^ápr(.(ilis)?)?/i,
+ may: /^máj(.(us)?)?/i,
+ jun: /^jún(.(ius)?)?/i,
+ jul: /^júl(.(ius)?)?/i,
+ aug: /^aug(.(usztus)?)?/i,
+ sep: /^szept(.(ember)?)?/i,
+ oct: /^okt(.(óber)?)?/i,
+ nov: /^nov(.(ember)?)?/i,
+ dec: /^dec(.(ember)?)?/i,
+
+ sun: /^vasárnap/i,
+ mon: /^hétfő/i,
+ tue: /^kedd/i,
+ wed: /^szerda/i,
+ thu: /^csütörtök/i,
+ fri: /^péntek/i,
+ sat: /^szombat/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/hy-AM.js b/addons/web/static/lib/datejs/globalization/hy-AM.js
new file mode 100644
index 00000000000..d230461c6a5
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/hy-AM.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "hy-AM",
+ englishName: "Armenian (Armenia)",
+ nativeName: "Հայերեն (Հայաստան)",
+
+ /* Day Name Strings */
+ dayNames: ["Կիրակի", "Երկուշաբթի", "Երեքշաբթի", "Չորեքշաբթի", "Հինգշաբթի", "ՈՒրբաթ", "Շաբաթ"],
+ abbreviatedDayNames: ["Կիր", "Երկ", "Երք", "Չրք", "Հնգ", "ՈՒր", "Շբթ"],
+ shortestDayNames: ["Կ", "Ե", "Ե", "Չ", "Հ", "Ո", "Շ"],
+ firstLetterDayNames: ["Կ", "Ե", "Ե", "Չ", "Հ", "Ո", "Շ"],
+
+ /* Month Name Strings */
+ monthNames: ["Հունվար", "Փետրվար", "Մարտ", "Ապրիլ", "Մայիս", "Հունիս", "Հուլիս", "Օգոստոս", "Սեպտեմբեր", "Հոկտեմբեր", "Նոյեմբեր", "Դեկտեմբեր"],
+ abbreviatedMonthNames: ["ՀՆՎ", "ՓՏՎ", "ՄՐՏ", "ԱՊՐ", "ՄՅՍ", "ՀՆՍ", "ՀԼՍ", "ՕԳՍ", "ՍԵՊ", "ՀՈԿ", "ՆՈՅ", "ԴԵԿ"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM, yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM, yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^հունվար/i,
+ feb: /^փետրվար/i,
+ mar: /^մարտ/i,
+ apr: /^ապր(իլ)?/i,
+ may: /^մայիս/i,
+ jun: /^հունիս/i,
+ jul: /^հուլիս/i,
+ aug: /^օգոստոս/i,
+ sep: /^սեպ(տեմբեր)?/i,
+ oct: /^հոկ(տեմբեր)?/i,
+ nov: /^նոյ(եմբեր)?/i,
+ dec: /^դեկ(տեմբեր)?/i,
+
+ sun: /^կ(իր(ակի)?)?/i,
+ mon: /^ե(րկ(ուշաբթի)?)?/i,
+ tue: /^ե(րք(քշաբթի)?)?/i,
+ wed: /^չ(րք(եքշաբթի)?)?/i,
+ thu: /^հ(նգ(գշաբթի)?)?/i,
+ fri: /^ո(ւր(բաթ)?)?/i,
+ sat: /^շ(բթ(աթ)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/id-ID.js b/addons/web/static/lib/datejs/globalization/id-ID.js
new file mode 100644
index 00000000000..082e9c99dcf
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/id-ID.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "id-ID",
+ englishName: "Indonesian (Indonesia)",
+ nativeName: "Bahasa Indonesia (Indonesia)",
+
+ /* Day Name Strings */
+ dayNames: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"],
+ abbreviatedDayNames: ["Minggu", "Sen", "Sel", "Rabu", "Kamis", "Jumat", "Sabtu"],
+ shortestDayNames: ["M", "S", "S", "R", "K", "J", "S"],
+ firstLetterDayNames: ["M", "S", "S", "R", "K", "J", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "Nopember", "Desember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agust", "Sep", "Okt", "Nop", "Des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mar(et)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^agust(us)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nop(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^m(1)?/i,
+ mon: /^s(en(in)?)?/i,
+ tue: /^s(el(asa)?)?/i,
+ wed: /^r(1)?/i,
+ thu: /^k(1)?/i,
+ fri: /^j(1)?/i,
+ sat: /^s(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/is-IS.js b/addons/web/static/lib/datejs/globalization/is-IS.js
new file mode 100644
index 00000000000..929cad34a75
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/is-IS.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "is-IS",
+ englishName: "Icelandic (Iceland)",
+ nativeName: "íslenska (Ísland)",
+
+ /* Day Name Strings */
+ dayNames: ["sunnudagur", "mánudagur", "þriðjudagur", "miðvikudagur", "fimmtudagur", "föstudagur", "laugardagur"],
+ abbreviatedDayNames: ["sun.", "mán.", "þri.", "mið.", "fim.", "fös.", "lau."],
+ shortestDayNames: ["su", "má", "þr", "mi", "fi", "fö", "la"],
+ firstLetterDayNames: ["s", "m", "þ", "m", "f", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["janúar", "febrúar", "mars", "apríl", "maí", "júní", "júlí", "ágúst", "september", "október", "nóvember", "desember"],
+ abbreviatedMonthNames: ["jan.", "feb.", "mar.", "apr.", "maí", "jún.", "júl.", "ágú.", "sep.", "okt.", "nóv.", "des."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(.(úar)?)?/i,
+ feb: /^feb(.(rúar)?)?/i,
+ mar: /^mar(.(s)?)?/i,
+ apr: /^apr(.(íl)?)?/i,
+ may: /^maí/i,
+ jun: /^jún(.(í)?)?/i,
+ jul: /^júl(.(í)?)?/i,
+ aug: /^ágú(.(st)?)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(.(óber)?)?/i,
+ nov: /^nóv(.(ember)?)?/i,
+ dec: /^des(.(ember)?)?/i,
+
+ sun: /^su(n(.(nudagur)?)?)?/i,
+ mon: /^má(n(.(udagur)?)?)?/i,
+ tue: /^þr(i(.(ðjudagur)?)?)?/i,
+ wed: /^mi(ð(.(vikudagur)?)?)?/i,
+ thu: /^fi(m(.(mtudagur)?)?)?/i,
+ fri: /^fö(s(.(tudagur)?)?)?/i,
+ sat: /^la(u(.(gardagur)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/it-CH.js b/addons/web/static/lib/datejs/globalization/it-CH.js
new file mode 100644
index 00000000000..5470e951c96
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/it-CH.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "it-CH",
+ englishName: "Italian (Switzerland)",
+ nativeName: "italiano (Svizzera)",
+
+ /* Day Name Strings */
+ dayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"],
+ shortestDayNames: ["do", "lu", "ma", "me", "gi", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "g", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"],
+ abbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "gio", "lug", "ago", "set", "ott", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^gen(naio)?/i,
+ feb: /^feb(braio)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^apr(ile)?/i,
+ may: /^mag(gio)?/i,
+ jun: /^giugno/i,
+ jul: /^lug(lio)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(tembre)?/i,
+ oct: /^ott(obre)?/i,
+ nov: /^nov(embre)?/i,
+ dec: /^dic(embre)?/i,
+
+ sun: /^do(m(enica)?)?/i,
+ mon: /^lu(n(edì)?)?/i,
+ tue: /^ma(r(tedì)?)?/i,
+ wed: /^me(r(coledì)?)?/i,
+ thu: /^gi(o(vedì)?)?/i,
+ fri: /^ve(n(erdì)?)?/i,
+ sat: /^sa(b(ato)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/it-IT.js b/addons/web/static/lib/datejs/globalization/it-IT.js
new file mode 100644
index 00000000000..67789e1d32a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/it-IT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "it-IT",
+ englishName: "Italian (Italy)",
+ nativeName: "italiano (Italia)",
+
+ /* Day Name Strings */
+ dayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"],
+ shortestDayNames: ["do", "lu", "ma", "me", "gi", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "g", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"],
+ abbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "H.mm",
+ longTime: "H.mm.ss",
+ fullDateTime: "dddd d MMMM yyyy H.mm.ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^gen(naio)?/i,
+ feb: /^feb(braio)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^apr(ile)?/i,
+ may: /^mag(gio)?/i,
+ jun: /^giu(gno)?/i,
+ jul: /^lug(lio)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(tembre)?/i,
+ oct: /^ott(obre)?/i,
+ nov: /^nov(embre)?/i,
+ dec: /^dic(embre)?/i,
+
+ sun: /^do(m(enica)?)?/i,
+ mon: /^lu(n(edì)?)?/i,
+ tue: /^ma(r(tedì)?)?/i,
+ wed: /^me(r(coledì)?)?/i,
+ thu: /^gi(o(vedì)?)?/i,
+ fri: /^ve(n(erdì)?)?/i,
+ sat: /^sa(b(ato)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ja-JP.js b/addons/web/static/lib/datejs/globalization/ja-JP.js
new file mode 100644
index 00000000000..95414922c7a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ja-JP.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ja-JP",
+ englishName: "Japanese (Japan)",
+ nativeName: "日本語 (日本)",
+
+ /* Day Name Strings */
+ dayNames: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"],
+ abbreviatedDayNames: ["日", "月", "火", "水", "木", "金", "土"],
+ shortestDayNames: ["日", "月", "火", "水", "木", "金", "土"],
+ firstLetterDayNames: ["日", "月", "火", "水", "木", "金", "土"],
+
+ /* Month Name Strings */
+ monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
+ abbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
+
+ /* AM/PM Designators */
+ amDesignator: "午前",
+ pmDesignator: "午後",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "yyyy'年'M'月'd'日'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy'年'M'月'd'日' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'月'd'日'",
+ yearMonth: "yyyy'年'M'月'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^1(月)?/i,
+ feb: /^2(月)?/i,
+ mar: /^3(月)?/i,
+ apr: /^4(月)?/i,
+ may: /^5(月)?/i,
+ jun: /^6(月)?/i,
+ jul: /^7(月)?/i,
+ aug: /^8(月)?/i,
+ sep: /^9(月)?/i,
+ oct: /^10(月)?/i,
+ nov: /^11(月)?/i,
+ dec: /^12(月)?/i,
+
+ sun: /^日曜日/i,
+ mon: /^月曜日/i,
+ tue: /^火曜日/i,
+ wed: /^水曜日/i,
+ thu: /^木曜日/i,
+ fri: /^金曜日/i,
+ sat: /^土曜日/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ka-GE.js b/addons/web/static/lib/datejs/globalization/ka-GE.js
new file mode 100644
index 00000000000..917698c301d
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ka-GE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ka-GE",
+ englishName: "Georgian (Georgia)",
+ nativeName: "ქართული (საქართველო)",
+
+ /* Day Name Strings */
+ dayNames: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"],
+ abbreviatedDayNames: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"],
+ shortestDayNames: ["კ", "ო", "ს", "ო", "ხ", "პ", "შ"],
+ firstLetterDayNames: ["კ", "ო", "ს", "ო", "ხ", "პ", "შ"],
+
+ /* Month Name Strings */
+ monthNames: ["იანვარი", "თებერვალი", "მარტი", "აპრილი", "მაისი", "ივნისი", "ივლისი", "აგვისტო", "სექტემბერი", "ოქტომბერი", "ნოემბერი", "დეკემბერი"],
+ abbreviatedMonthNames: ["იან", "თებ", "მარ", "აპრ", "მაის", "ივნ", "ივლ", "აგვ", "სექ", "ოქტ", "ნოემ", "დეკ"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "yyyy 'წლის' dd MM, dddd",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy 'წლის' dd MM, dddd H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^იან(ვარი)?/i,
+ feb: /^თებ(ერვალი)?/i,
+ mar: /^მარ(ტი)?/i,
+ apr: /^აპრ(ილი)?/i,
+ may: /^მაის(ი)?/i,
+ jun: /^ივნ(ისი)?/i,
+ jul: /^ივლ(ისი)?/i,
+ aug: /^აგვ(ისტო)?/i,
+ sep: /^სექ(ტემბერი)?/i,
+ oct: /^ოქტ(ომბერი)?/i,
+ nov: /^ნოემ(ბერი)?/i,
+ dec: /^დეკ(ემბერი)?/i,
+
+ sun: /^კ(1)?/i,
+ mon: /^ო(1)?/i,
+ tue: /^ს(1)?/i,
+ wed: /^ო(1)?/i,
+ thu: /^ხ(1)?/i,
+ fri: /^პ(1)?/i,
+ sat: /^შ(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/kk-KZ.js b/addons/web/static/lib/datejs/globalization/kk-KZ.js
new file mode 100644
index 00000000000..4ec2e25fbb6
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/kk-KZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "kk-KZ",
+ englishName: "Kazakh (Kazakhstan)",
+ nativeName: "Қазақ (Қазақстан)",
+
+ /* Day Name Strings */
+ dayNames: ["Жексенбі", "Дүйсенбі", "Сейсенбі", "Сәрсенбі", "Бейсенбі", "Жұма", "Сенбі"],
+ abbreviatedDayNames: ["Жк", "Дс", "Сс", "Ср", "Бс", "Жм", "Сн"],
+ shortestDayNames: ["Жк", "Дс", "Сс", "Ср", "Бс", "Жм", "Сн"],
+ firstLetterDayNames: ["Ж", "Д", "С", "С", "Б", "Ж", "С"],
+
+ /* Month Name Strings */
+ monthNames: ["қаңтар", "ақпан", "наурыз", "сәуір", "мамыр", "маусым", "шілде", "тамыз", "қыркүйек", "қазан", "қараша", "желтоқсан"],
+ abbreviatedMonthNames: ["Қаң", "Ақп", "Нау", "Сәу", "Мам", "Мау", "Шіл", "Там", "Қыр", "Қаз", "Қар", "Жел"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy 'ж.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy 'ж.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^қаң(тар)?/i,
+ feb: /^ақп(ан)?/i,
+ mar: /^нау(рыз)?/i,
+ apr: /^сәу(ір)?/i,
+ may: /^мам(ыр)?/i,
+ jun: /^мау(сым)?/i,
+ jul: /^шіл(де)?/i,
+ aug: /^там(ыз)?/i,
+ sep: /^қыр(күйек)?/i,
+ oct: /^қаз(ан)?/i,
+ nov: /^қар(аша)?/i,
+ dec: /^жел(тоқсан)?/i,
+
+ sun: /^жексенбі/i,
+ mon: /^дүйсенбі/i,
+ tue: /^сейсенбі/i,
+ wed: /^сәрсенбі/i,
+ thu: /^бейсенбі/i,
+ fri: /^жұма/i,
+ sat: /^сенбі/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/kn-IN.js b/addons/web/static/lib/datejs/globalization/kn-IN.js
new file mode 100644
index 00000000000..aa5b5f4e999
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/kn-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "kn-IN",
+ englishName: "Kannada (India)",
+ nativeName: "ಕನ್ನಡ (ಭಾರತ)",
+
+ /* Day Name Strings */
+ dayNames: ["ಭಾನುವಾರ", "ಸೋಮವಾರ", "ಮಂಗಳವಾರ", "ಬುಧವಾರ", "ಗುರುವಾರ", "ಶುಕ್ರವಾರ", "ಶನಿವಾರ"],
+ abbreviatedDayNames: ["ಭಾನು.", "ಸೋಮ.", "ಮಂಗಳ.", "ಬುಧ.", "ಗುರು.", "ಶುಕ್ರ.", "ಶನಿ."],
+ shortestDayNames: ["ರ", "ಸ", "ಮ", "ಬ", "ಗ", "ಶ", "ಶ"],
+ firstLetterDayNames: ["ರ", "ಸ", "ಮ", "ಬ", "ಗ", "ಶ", "ಶ"],
+
+ /* Month Name Strings */
+ monthNames: ["ಜನವರಿ", "ಫೆಬ್ರವರಿ", "ಮಾರ್ಚ್", "ಎಪ್ರಿಲ್", "ಮೇ", "ಜೂನ್", "ಜುಲೈ", "ಆಗಸ್ಟ್", "ಸೆಪ್ಟಂಬರ್", "ಅಕ್ಟೋಬರ್", "ನವೆಂಬರ್", "ಡಿಸೆಂಬರ್"],
+ abbreviatedMonthNames: ["ಜನವರಿ", "ಫೆಬ್ರವರಿ", "ಮಾರ್ಚ್", "ಎಪ್ರಿಲ್", "ಮೇ", "ಜೂನ್", "ಜುಲೈ", "ಆಗಸ್ಟ್", "ಸೆಪ್ಟಂಬರ್", "ಅಕ್ಟೋಬರ್", "ನವೆಂಬರ್", "ಡಿಸೆಂಬರ್"],
+
+ /* AM/PM Designators */
+ amDesignator: "ಪೂರ್ವಾಹ್ನ",
+ pmDesignator: "ಅಪರಾಹ್ನ",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ಜನವರಿ/i,
+ feb: /^ಫೆಬ್ರವರಿ/i,
+ mar: /^ಮಾರ್ಚ್/i,
+ apr: /^ಎಪ್ರಿಲ್/i,
+ may: /^ಮೇ/i,
+ jun: /^ಜೂನ್/i,
+ jul: /^ಜುಲೈ/i,
+ aug: /^ಆಗಸ್ಟ್/i,
+ sep: /^ಸೆಪ್ಟಂಬರ್/i,
+ oct: /^ಅಕ್ಟೋಬರ್/i,
+ nov: /^ನವೆಂಬರ್/i,
+ dec: /^ಡಿಸೆಂಬರ್/i,
+
+ sun: /^ರ(ಾನು(.(ವಾರ)?)?)?/i,
+ mon: /^ಸ(ೋಮ(.(ವಾರ)?)?)?/i,
+ tue: /^ಮ(ಂಗಳ(.(ವಾರ)?)?)?/i,
+ wed: /^ಬ(ುಧ(.(ವಾರ)?)?)?/i,
+ thu: /^ಗ(ುರು(.(ವಾರ)?)?)?/i,
+ fri: /^ಶ(ುಕ್ರ(.(ವಾರ)?)?)?/i,
+ sat: /^ಶ(ನಿ(.(ವಾರ)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ko-KR.js b/addons/web/static/lib/datejs/globalization/ko-KR.js
new file mode 100644
index 00000000000..24c3d4abd34
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ko-KR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ko-KR",
+ englishName: "Korean (Korea)",
+ nativeName: "한국어 (대한민국)",
+
+ /* Day Name Strings */
+ dayNames: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
+ abbreviatedDayNames: ["일", "월", "화", "수", "목", "금", "토"],
+ shortestDayNames: ["일", "월", "화", "수", "목", "금", "토"],
+ firstLetterDayNames: ["일", "월", "화", "수", "목", "금", "토"],
+
+ /* Month Name Strings */
+ monthNames: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"],
+ abbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
+
+ /* AM/PM Designators */
+ amDesignator: "오전",
+ pmDesignator: "오후",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "yyyy'년' M'월' d'일' dddd",
+ shortTime: "tt h:mm",
+ longTime: "tt h:mm:ss",
+ fullDateTime: "yyyy'년' M'월' d'일' dddd tt h:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'월' d'일'",
+ yearMonth: "yyyy'년' M'월'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^1(월)?/i,
+ feb: /^2(월)?/i,
+ mar: /^3(월)?/i,
+ apr: /^4(월)?/i,
+ may: /^5(월)?/i,
+ jun: /^6(월)?/i,
+ jul: /^7(월)?/i,
+ aug: /^8(월)?/i,
+ sep: /^9(월)?/i,
+ oct: /^10(월)?/i,
+ nov: /^11(월)?/i,
+ dec: /^12(월)?/i,
+
+ sun: /^일요일/i,
+ mon: /^월요일/i,
+ tue: /^화요일/i,
+ wed: /^수요일/i,
+ thu: /^목요일/i,
+ fri: /^금요일/i,
+ sat: /^토요일/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/kok-IN.js b/addons/web/static/lib/datejs/globalization/kok-IN.js
new file mode 100644
index 00000000000..99668197060
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/kok-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "kok-IN",
+ englishName: "Konkani (India)",
+ nativeName: "कोंकणी (भारत)",
+
+ /* Day Name Strings */
+ dayNames: ["आयतार", "सोमार", "मंगळार", "बुधवार", "बिरेस्तार", "सुक्रार", "शेनवार"],
+ abbreviatedDayNames: ["आय.", "सोम.", "मंगळ.", "बुध.", "बिरे.", "सुक्र.", "शेन."],
+ shortestDayNames: ["आ", "स", "म", "ब", "ब", "स", "श"],
+ firstLetterDayNames: ["आ", "स", "म", "ब", "ब", "स", "श"],
+
+ /* Month Name Strings */
+ monthNames: ["जानेवारी", "फेब्रुवारी", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टेंबर", "ऑक्टोबर", "नोवेम्बर", "डिसेंबर"],
+ abbreviatedMonthNames: ["जानेवारी", "फेब्रुवारी", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टेंबर", "ऑक्टोबर", "नोवेम्बर", "डिसेंबर"],
+
+ /* AM/PM Designators */
+ amDesignator: "म.पू.",
+ pmDesignator: "म.नं.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^जानेवारी/i,
+ feb: /^फेब्रुवारी/i,
+ mar: /^मार्च/i,
+ apr: /^एप्रिल/i,
+ may: /^मे/i,
+ jun: /^जून/i,
+ jul: /^जुलै/i,
+ aug: /^ऑगस्ट/i,
+ sep: /^सप्टेंबर/i,
+ oct: /^ऑक्टोबर/i,
+ nov: /^नोवेम्बर/i,
+ dec: /^डिसेंबर/i,
+
+ sun: /^आ(य(.(तार)?)?)?/i,
+ mon: /^स(ोम(.(ार)?)?)?/i,
+ tue: /^म(ंगळ(.(ार)?)?)?/i,
+ wed: /^ब(ुध(.(वार)?)?)?/i,
+ thu: /^ब(िरे(.(स्तार)?)?)?/i,
+ fri: /^स(ुक्र(.(ार)?)?)?/i,
+ sat: /^श(ेन(.(वार)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ky-KG.js b/addons/web/static/lib/datejs/globalization/ky-KG.js
new file mode 100644
index 00000000000..aeeef00979a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ky-KG.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ky-KG",
+ englishName: "Kyrgyz (Kyrgyzstan)",
+ nativeName: "Кыргыз (Кыргызстан)",
+
+ /* Day Name Strings */
+ dayNames: ["Жекшемби", "Дүйшөмбү", "Шейшемби", "Шаршемби", "Бейшемби", "Жума", "Ишемби"],
+ abbreviatedDayNames: ["Жш", "Дш", "Шш", "Шр", "Бш", "Жм", "Иш"],
+ shortestDayNames: ["Жш", "Дш", "Шш", "Шр", "Бш", "Жм", "Иш"],
+ firstLetterDayNames: ["Ж", "Д", "Ш", "Ш", "Б", "Ж", "И"],
+
+ /* Month Name Strings */
+ monthNames: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
+ abbreviatedMonthNames: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yy",
+ longDate: "d'-'MMMM yyyy'-ж.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d'-'MMMM yyyy'-ж.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy'-ж.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^янв(арь)?/i,
+ feb: /^фев(раль)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ель)?/i,
+ may: /^май/i,
+ jun: /^июн(ь)?/i,
+ jul: /^июл(ь)?/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сен(тябрь)?/i,
+ oct: /^окт(ябрь)?/i,
+ nov: /^ноя(брь)?/i,
+ dec: /^дек(абрь)?/i,
+
+ sun: /^жекшемби/i,
+ mon: /^дүйшөмбү/i,
+ tue: /^шейшемби/i,
+ wed: /^шаршемби/i,
+ thu: /^бейшемби/i,
+ fri: /^жума/i,
+ sat: /^ишемби/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/lt-LT.js b/addons/web/static/lib/datejs/globalization/lt-LT.js
new file mode 100644
index 00000000000..0efcc5b170b
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/lt-LT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "lt-LT",
+ englishName: "Lithuanian (Lithuania)",
+ nativeName: "lietuvių (Lietuva)",
+
+ /* Day Name Strings */
+ dayNames: ["sekmadienis", "pirmadienis", "antradienis", "trečiadienis", "ketvirtadienis", "penktadienis", "šeštadienis"],
+ abbreviatedDayNames: ["Sk", "Pr", "An", "Tr", "Kt", "Pn", "Št"],
+ shortestDayNames: ["S", "P", "A", "T", "K", "Pn", "Š"],
+ firstLetterDayNames: ["S", "P", "A", "T", "K", "P", "Š"],
+
+ /* Month Name Strings */
+ monthNames: ["sausis", "vasaris", "kovas", "balandis", "gegužė", "birželis", "liepa", "rugpjūtis", "rugsėjis", "spalis", "lapkritis", "gruodis"],
+ abbreviatedMonthNames: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rgp", "Rgs", "Spl", "Lap", "Grd"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy.MM.dd",
+ longDate: "yyyy 'm.' MMMM d 'd.'",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "yyyy 'm.' MMMM d 'd.' HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM d 'd.'",
+ yearMonth: "yyyy 'm.' MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^sau(sis)?/i,
+ feb: /^vas(aris)?/i,
+ mar: /^kov(as)?/i,
+ apr: /^bal(andis)?/i,
+ may: /^geg(užė)?/i,
+ jun: /^bir(želis)?/i,
+ jul: /^lie(pa)?/i,
+ aug: /^rugpjūtis/i,
+ sep: /^rugsėjis/i,
+ oct: /^spalis/i,
+ nov: /^lap(kritis)?/i,
+ dec: /^gruodis/i,
+
+ sun: /^s(k(kmadienis)?)?/i,
+ mon: /^p(r(rmadienis)?)?/i,
+ tue: /^a(n(tradienis)?)?/i,
+ wed: /^t(r(ečiadienis)?)?/i,
+ thu: /^k(t(tvirtadienis)?)?/i,
+ fri: /^penktadienis/i,
+ sat: /^š(t(štadienis)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/lv-LV.js b/addons/web/static/lib/datejs/globalization/lv-LV.js
new file mode 100644
index 00000000000..09ac7772654
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/lv-LV.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "lv-LV",
+ englishName: "Latvian (Latvia)",
+ nativeName: "latviešu (Latvija)",
+
+ /* Day Name Strings */
+ dayNames: ["svētdiena", "pirmdiena", "otrdiena", "trešdiena", "ceturtdiena", "piektdiena", "sestdiena"],
+ abbreviatedDayNames: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"],
+ shortestDayNames: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"],
+ firstLetterDayNames: ["S", "P", "O", "T", "C", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["janvāris", "februāris", "marts", "aprīlis", "maijs", "jūnijs", "jūlijs", "augusts", "septembris", "oktobris", "novembris", "decembris"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy.MM.dd.",
+ longDate: "dddd, yyyy'. gada 'd. MMMM",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, yyyy'. gada 'd. MMMM H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "yyyy. MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(vāris)?/i,
+ feb: /^feb(ruāris)?/i,
+ mar: /^mar(ts)?/i,
+ apr: /^apr(īlis)?/i,
+ may: /^mai(js)?/i,
+ jun: /^jūn(ijs)?/i,
+ jul: /^jūl(ijs)?/i,
+ aug: /^aug(usts)?/i,
+ sep: /^sep(tembris)?/i,
+ oct: /^okt(obris)?/i,
+ nov: /^nov(embris)?/i,
+ dec: /^dec(embris)?/i,
+
+ sun: /^svētdiena/i,
+ mon: /^pirmdiena/i,
+ tue: /^otrdiena/i,
+ wed: /^trešdiena/i,
+ thu: /^ceturtdiena/i,
+ fri: /^piektdiena/i,
+ sat: /^sestdiena/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/mi-NZ.js b/addons/web/static/lib/datejs/globalization/mi-NZ.js
new file mode 100644
index 00000000000..e74f2b7b997
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/mi-NZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "mi-NZ",
+ englishName: "Maori (New Zealand)",
+ nativeName: "Reo Māori (Aotearoa)",
+
+ /* Day Name Strings */
+ dayNames: ["Rātapu", "Mane", "Tūrei", "Wenerei", "Tāite", "Paraire", "Hātarei"],
+ abbreviatedDayNames: ["Ta", "Ma", "Tū", "We", "Tāi", "Pa", "Hā"],
+ shortestDayNames: ["Ta", "Ma", "Tū", "We", "Tāi", "Pa", "Hā"],
+ firstLetterDayNames: ["T", "M", "T", "W", "T", "P", "H"],
+
+ /* Month Name Strings */
+ monthNames: ["Kohi-tātea", "Hui-tanguru", "Poutū-te-rangi", "Paenga-whāwhā", "Haratua", "Pipiri", "Hōngoingoi", "Here-turi-kōkā", "Mahuru", "Whiringa-ā-nuku", "Whiringa-ā-rangi", "Hakihea"],
+ abbreviatedMonthNames: ["Kohi", "Hui", "Pou", "Pae", "Hara", "Pipi", "Hōngoi", "Here", "Mahu", "Whi-nu", "Whi-ra", "Haki"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/MM/yyyy",
+ longDate: "dddd, d MMMM yyyy",
+ shortTime: "h:mm:ss tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^kohi(-tātea)?/i,
+ feb: /^hui(-tanguru)?/i,
+ mar: /^pou(tū-te-rangi)?/i,
+ apr: /^pae(nga-whāwhā)?/i,
+ may: /^hara(tua)?/i,
+ jun: /^pipi(ri)?/i,
+ jul: /^hōngoi(ngoi)?/i,
+ aug: /^here(-turi-kōkā)?/i,
+ sep: /^mahu(ru)?/i,
+ oct: /^whiringa-ā-nuku/i,
+ nov: /^whiringa-ā-rangi/i,
+ dec: /^haki(hea)?/i,
+
+ sun: /^rātapu/i,
+ mon: /^mane/i,
+ tue: /^tūrei/i,
+ wed: /^wenerei/i,
+ thu: /^tāite/i,
+ fri: /^paraire/i,
+ sat: /^hātarei/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/mk-MK.js b/addons/web/static/lib/datejs/globalization/mk-MK.js
new file mode 100644
index 00000000000..17a1fa0c9b8
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/mk-MK.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "mk-MK",
+ englishName: "Macedonian (Former Yugoslav Republic of Macedonia)",
+ nativeName: "македонски јазик (Македонија)",
+
+ /* Day Name Strings */
+ dayNames: ["недела", "понеделник", "вторник", "среда", "четврток", "петок", "сабота"],
+ abbreviatedDayNames: ["нед", "пон", "втр", "срд", "чет", "пет", "саб"],
+ shortestDayNames: ["не", "по", "вт", "ср", "че", "пе", "са"],
+ firstLetterDayNames: ["н", "п", "в", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["јануари", "февруари", "март", "април", "мај", "јуни", "јули", "август", "септември", "октомври", "ноември", "декември"],
+ abbreviatedMonthNames: ["јан", "фев", "мар", "апр", "мај", "јун", "јул", "авг", "сеп", "окт", "ное", "дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^јан(уари)?/i,
+ feb: /^фев(руари)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ил)?/i,
+ may: /^мај/i,
+ jun: /^јун(и)?/i,
+ jul: /^јул(и)?/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сеп(тември)?/i,
+ oct: /^окт(омври)?/i,
+ nov: /^ное(мври)?/i,
+ dec: /^дек(ември)?/i,
+
+ sun: /^не(д(ела)?)?/i,
+ mon: /^по(н(еделник)?)?/i,
+ tue: /^вт(р(рник)?)?/i,
+ wed: /^ср(д(да)?)?/i,
+ thu: /^че(т(врток)?)?/i,
+ fri: /^пе(т(ок)?)?/i,
+ sat: /^са(б(ота)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/mn-MN.js b/addons/web/static/lib/datejs/globalization/mn-MN.js
new file mode 100644
index 00000000000..d9eba61a0b5
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/mn-MN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "mn-MN",
+ englishName: "Mongolian (Cyrillic, Mongolia)",
+ nativeName: "Монгол хэл (Монгол улс)",
+
+ /* Day Name Strings */
+ dayNames: ["Ням", "Даваа", "Мягмар", "Лхагва", "Пүрэв", "Баасан", "Бямба"],
+ abbreviatedDayNames: ["Ня", "Да", "Мя", "Лх", "Пү", "Ба", "Бя"],
+ shortestDayNames: ["Ня", "Да", "Мя", "Лх", "Пү", "Ба", "Бя"],
+ firstLetterDayNames: ["Н", "Д", "М", "Л", "П", "Б", "Б"],
+
+ /* Month Name Strings */
+ monthNames: ["1 дүгээр сар", "2 дугаар сар", "3 дугаар сар", "4 дүгээр сар", "5 дугаар сар", "6 дугаар сар", "7 дугаар сар", "8 дугаар сар", "9 дүгээр сар", "10 дугаар сар", "11 дүгээр сар", "12 дугаар сар"],
+ abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VШ", "IX", "X", "XI", "XII"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yy.MM.dd",
+ longDate: "yyyy 'оны' MMMM d",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy 'оны' MMMM d H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "yyyy 'он' MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^1 дүгээр сар/i,
+ feb: /^2 дугаар сар/i,
+ mar: /^3 дугаар сар/i,
+ apr: /^4 дүгээр сар/i,
+ may: /^5 дугаар сар/i,
+ jun: /^6 дугаар сар/i,
+ jul: /^7 дугаар сар/i,
+ aug: /^8 дугаар сар/i,
+ sep: /^9 дүгээр сар/i,
+ oct: /^10 дугаар сар/i,
+ nov: /^11 дүгээр сар/i,
+ dec: /^12 дугаар сар/i,
+
+ sun: /^ням/i,
+ mon: /^даваа/i,
+ tue: /^мягмар/i,
+ wed: /^лхагва/i,
+ thu: /^пүрэв/i,
+ fri: /^баасан/i,
+ sat: /^бямба/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/mr-IN.js b/addons/web/static/lib/datejs/globalization/mr-IN.js
new file mode 100644
index 00000000000..f9a75c42004
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/mr-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "mr-IN",
+ englishName: "Marathi (India)",
+ nativeName: "मराठी (भारत)",
+
+ /* Day Name Strings */
+ dayNames: ["रविवार", "सोमवार", "मंगळवार", "बुधवार", "गुरुवार", "शुक्रवार", "शनिवार"],
+ abbreviatedDayNames: ["रवि.", "सोम.", "मंगळ.", "बुध.", "गुरु.", "शुक्र.", "शनि."],
+ shortestDayNames: ["र", "स", "म", "ब", "ग", "श", "श"],
+ firstLetterDayNames: ["र", "स", "म", "ब", "ग", "श", "श"],
+
+ /* Month Name Strings */
+ monthNames: ["जानेवारी", "फेब्रुवारी", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टेंबर", "ऑक्टोबर", "नोव्हेंबर", "डिसेंबर"],
+ abbreviatedMonthNames: ["जाने.", "फेब्रु.", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टें.", "ऑक्टो.", "नोव्हें.", "डिसें."],
+
+ /* AM/PM Designators */
+ amDesignator: "म.पू.",
+ pmDesignator: "म.नं.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^जाने(.(वारी)?)?/i,
+ feb: /^फेब्रु(.(वारी)?)?/i,
+ mar: /^मार्च/i,
+ apr: /^एप्रिल/i,
+ may: /^मे/i,
+ jun: /^जून/i,
+ jul: /^जुलै/i,
+ aug: /^ऑगस्ट/i,
+ sep: /^सप्टें(.(बर)?)?/i,
+ oct: /^ऑक्टो(.(बर)?)?/i,
+ nov: /^नोव्हें(.(बर)?)?/i,
+ dec: /^डिसें(.(बर)?)?/i,
+
+ sun: /^र(वि(.(वार)?)?)?/i,
+ mon: /^स(ोम(.(वार)?)?)?/i,
+ tue: /^म(ंगळ(.(वार)?)?)?/i,
+ wed: /^ब(ुध(.(वार)?)?)?/i,
+ thu: /^ग(ुरु(.(वार)?)?)?/i,
+ fri: /^श(ुक्र(.(वार)?)?)?/i,
+ sat: /^श(नि(.(वार)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ms-BN.js b/addons/web/static/lib/datejs/globalization/ms-BN.js
new file mode 100644
index 00000000000..ab5e4b710ed
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ms-BN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ms-BN",
+ englishName: "Malay (Brunei Darussalam)",
+ nativeName: "Bahasa Malaysia (Brunei Darussalam)",
+
+ /* Day Name Strings */
+ dayNames: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu"],
+ abbreviatedDayNames: ["Ahad", "Isnin", "Sel", "Rabu", "Khamis", "Jumaat", "Sabtu"],
+ shortestDayNames: ["A", "I", "S", "R", "K", "J", "S"],
+ firstLetterDayNames: ["A", "I", "S", "R", "K", "J", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ogos", "Sept", "Okt", "Nov", "Dis"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mac/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun/i,
+ jul: /^jul(ai)?/i,
+ aug: /^ogos/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dis(ember)?/i,
+
+ sun: /^a(1)?/i,
+ mon: /^i(1)?/i,
+ tue: /^s(el(asa)?)?/i,
+ wed: /^r(1)?/i,
+ thu: /^k(1)?/i,
+ fri: /^j(1)?/i,
+ sat: /^s(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ms-MY.js b/addons/web/static/lib/datejs/globalization/ms-MY.js
new file mode 100644
index 00000000000..7deb311246f
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ms-MY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ms-MY",
+ englishName: "Malay (Malaysia)",
+ nativeName: "Bahasa Malaysia (Malaysia)",
+
+ /* Day Name Strings */
+ dayNames: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu"],
+ abbreviatedDayNames: ["Ahad", "Isnin", "Sel", "Rabu", "Khamis", "Jumaat", "Sabtu"],
+ shortestDayNames: ["A", "I", "S", "R", "K", "J", "S"],
+ firstLetterDayNames: ["A", "I", "S", "R", "K", "J", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ogos", "Sept", "Okt", "Nov", "Dis"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mac/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun/i,
+ jul: /^jul(ai)?/i,
+ aug: /^ogos/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dis(ember)?/i,
+
+ sun: /^a(1)?/i,
+ mon: /^i(1)?/i,
+ tue: /^s(el(asa)?)?/i,
+ wed: /^r(1)?/i,
+ thu: /^k(1)?/i,
+ fri: /^j(1)?/i,
+ sat: /^s(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/mt-MT.js b/addons/web/static/lib/datejs/globalization/mt-MT.js
new file mode 100644
index 00000000000..0ee270f7456
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/mt-MT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "mt-MT",
+ englishName: "Maltese (Malta)",
+ nativeName: "Malti (Malta)",
+
+ /* Day Name Strings */
+ dayNames: ["Il-Ħadd", "It-Tnejn", "It-Tlieta", "L-Erbgħa", "Il-Ħamis", "Il-Ġimgħa", "Is-Sibt"],
+ abbreviatedDayNames: ["Ħad", "Tne", "Tli", "Erb", "Ħam", "Ġim", "Sib"],
+ shortestDayNames: ["Ħad", "Tne", "Tli", "Erb", "Ħam", "Ġim", "Sib"],
+ firstLetterDayNames: ["Ħ", "T", "T", "E", "Ħ", "Ġ", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Jannar", "Frar", "Marzu", "April", "Mejju", "Ġunju", "Lulju", "Awissu", "Settembru", "Ottubru", "Novembru", "Diċembru"],
+ abbreviatedMonthNames: ["Jan", "Fra", "Mar", "Apr", "Mej", "Ġun", "Lul", "Awi", "Set", "Ott", "Nov", "Diċ"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, d' ta\' 'MMMM yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d' ta\' 'MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(nar)?/i,
+ feb: /^fra(r)?/i,
+ mar: /^mar(zu)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mej(ju)?/i,
+ jun: /^ġun(ju)?/i,
+ jul: /^lul(ju)?/i,
+ aug: /^awi(ssu)?/i,
+ sep: /^set(tembru)?/i,
+ oct: /^ott(ubru)?/i,
+ nov: /^nov(embru)?/i,
+ dec: /^diċ(embru)?/i,
+
+ sun: /^il-ħadd/i,
+ mon: /^it-tnejn/i,
+ tue: /^it-tlieta/i,
+ wed: /^l-erbgħa/i,
+ thu: /^il-ħamis/i,
+ fri: /^il-ġimgħa/i,
+ sat: /^is-sibt/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/nb-NO.js b/addons/web/static/lib/datejs/globalization/nb-NO.js
new file mode 100644
index 00000000000..9da1b01e6e7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/nb-NO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nb-NO",
+ englishName: "Norwegian, Bokmål (Norway)",
+ nativeName: "norsk, bokmål (Norge)",
+
+ /* Day Name Strings */
+ dayNames: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
+ abbreviatedDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ shortestDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mars", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^søndag/i,
+ mon: /^mandag/i,
+ tue: /^tirsdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lørdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/nl-BE.js b/addons/web/static/lib/datejs/globalization/nl-BE.js
new file mode 100644
index 00000000000..69f9e3a5486
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/nl-BE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nl-BE",
+ englishName: "Dutch (Belgium)",
+ nativeName: "Nederlands (België)",
+
+ /* Day Name Strings */
+ dayNames: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
+ abbreviatedDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
+ shortestDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
+ firstLetterDayNames: ["z", "m", "d", "w", "d", "v", "z"],
+
+ /* Month Name Strings */
+ monthNames: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^maart/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ustus)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^zondag/i,
+ mon: /^maandag/i,
+ tue: /^dinsdag/i,
+ wed: /^woensdag/i,
+ thu: /^donderdag/i,
+ fri: /^vrijdag/i,
+ sat: /^zaterdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/nl-NL.js b/addons/web/static/lib/datejs/globalization/nl-NL.js
new file mode 100644
index 00000000000..ece102bb5f1
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/nl-NL.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nl-NL",
+ englishName: "Dutch (Netherlands)",
+ nativeName: "Nederlands (Nederland)",
+
+ /* Day Name Strings */
+ dayNames: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
+ abbreviatedDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
+ shortestDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
+ firstLetterDayNames: ["z", "m", "d", "w", "d", "v", "z"],
+
+ /* Month Name Strings */
+ monthNames: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d-M-yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^maart/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ustus)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^zondag/i,
+ mon: /^maandag/i,
+ tue: /^dinsdag/i,
+ wed: /^woensdag/i,
+ thu: /^donderdag/i,
+ fri: /^vrijdag/i,
+ sat: /^zaterdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/nn-NO.js b/addons/web/static/lib/datejs/globalization/nn-NO.js
new file mode 100644
index 00000000000..a01a3a0f65a
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/nn-NO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nn-NO",
+ englishName: "Norwegian, Nynorsk (Norway)",
+ nativeName: "norsk, nynorsk (Noreg)",
+
+ /* Day Name Strings */
+ dayNames: ["søndag", "måndag", "tysdag", "onsdag", "torsdag", "fredag", "laurdag"],
+ abbreviatedDayNames: ["sø", "må", "ty", "on", "to", "fr", "la"],
+ shortestDayNames: ["sø", "må", "ty", "on", "to", "fr", "la"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mars", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^søndag/i,
+ mon: /^måndag/i,
+ tue: /^tysdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^laurdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ns-ZA.js b/addons/web/static/lib/datejs/globalization/ns-ZA.js
new file mode 100644
index 00000000000..ee157ddf09f
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ns-ZA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ns-ZA",
+ englishName: "Northern Sotho (South Africa)",
+ nativeName: "Sesotho sa Leboa (Afrika Borwa)",
+
+ /* Day Name Strings */
+ dayNames: ["Lamorena", "Mošupologo", "Labobedi", "Laboraro", "Labone", "Labohlano", "Mokibelo"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Pherekgong", "Hlakola", "Mopitlo", "Moranang", "Mosegamanye", "Ngoatobošego", "Phuphu", "Phato", "Lewedi", "Diphalana", "Dibatsela", "Manthole"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dd MMMM yyyy",
+ shortTime: "hh:mm:ss tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^pherekgong/i,
+ feb: /^hlakola/i,
+ mar: /^mopitlo/i,
+ apr: /^moranang/i,
+ may: /^mosegamanye/i,
+ jun: /^ngoatobošego/i,
+ jul: /^phuphu/i,
+ aug: /^phato/i,
+ sep: /^lewedi/i,
+ oct: /^diphalana/i,
+ nov: /^dibatsela/i,
+ dec: /^manthole/i,
+
+ sun: /^lamorena/i,
+ mon: /^mošupologo/i,
+ tue: /^labobedi/i,
+ wed: /^laboraro/i,
+ thu: /^labone/i,
+ fri: /^labohlano/i,
+ sat: /^mokibelo/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/pa-IN.js b/addons/web/static/lib/datejs/globalization/pa-IN.js
new file mode 100644
index 00000000000..3f3fe7bf695
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/pa-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pa-IN",
+ englishName: "Punjabi (India)",
+ nativeName: "ਪੰਜਾਬੀ (ਭਾਰਤ)",
+
+ /* Day Name Strings */
+ dayNames: ["ਐਤਵਾਰ", "ਸੋਮਵਾਰ", "ਮੰਗਲਵਾਰ", "ਬੁਧਵਾਰ", "ਵੀਰਵਾਰ", "ਸ਼ੁੱਕਰਵਾਰ", "ਸ਼ਨੀਚਰਵਾਰ"],
+ abbreviatedDayNames: ["ਐਤ.", "ਸੋਮ.", "ਮੰਗਲ.", "ਬੁਧ.", "ਵੀਰ.", "ਸ਼ੁਕਰ.", "ਸ਼ਨੀ."],
+ shortestDayNames: ["ਐ", "ਸ", "ਮ", "ਬ", "ਵ", "ਸ਼", "ਸ਼"],
+ firstLetterDayNames: ["ਐ", "ਸ", "ਮ", "ਬ", "ਵ", "ਸ਼", "ਸ਼"],
+
+ /* Month Name Strings */
+ monthNames: ["ਜਨਵਰੀ", "ਫ਼ਰਵਰੀ", "ਮਾਰਚ", "ਅਪ੍ਰੈਲ", "ਮਈ", "ਜੂਨ", "ਜੁਲਾਈ", "ਅਗਸਤ", "ਸਤੰਬਰ", "ਅਕਤੂਬਰ", "ਨਵੰਬਰ", "ਦਸੰਬਰ"],
+ abbreviatedMonthNames: ["ਜਨਵਰੀ", "ਫ਼ਰਵਰੀ", "ਮਾਰਚ", "ਅਪ੍ਰੈਲ", "ਮਈ", "ਜੂਨ", "ਜੁਲਾਈ", "ਅਗਸਤ", "ਸਤੰਬਰ", "ਅਕਤੂਬਰ", "ਨਵੰਬਰ", "ਦਸੰਬਰ"],
+
+ /* AM/PM Designators */
+ amDesignator: "ਸਵੇਰੇ",
+ pmDesignator: "ਸ਼ਾਮ",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yy",
+ longDate: "dd MMMM yyyy dddd",
+ shortTime: "tt hh:mm",
+ longTime: "tt hh:mm:ss",
+ fullDateTime: "dd MMMM yyyy dddd tt hh:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ਜਨਵਰੀ/i,
+ feb: /^ਫ਼ਰਵਰੀ/i,
+ mar: /^ਮਾਰਚ/i,
+ apr: /^ਅਪ੍ਰੈਲ/i,
+ may: /^ਮਈ/i,
+ jun: /^ਜੂਨ/i,
+ jul: /^ਜੁਲਾਈ/i,
+ aug: /^ਅਗਸਤ/i,
+ sep: /^ਸਤੰਬਰ/i,
+ oct: /^ਅਕਤੂਬਰ/i,
+ nov: /^ਨਵੰਬਰ/i,
+ dec: /^ਦਸੰਬਰ/i,
+
+ sun: /^ਐ(ਤ(.(ਵਾਰ)?)?)?/i,
+ mon: /^ਸ(ੋਮ(.(ਵਾਰ)?)?)?/i,
+ tue: /^ਮ(ੰਗਲ(.(ਵਾਰ)?)?)?/i,
+ wed: /^ਬ(ੁਧ(.(ਵਾਰ)?)?)?/i,
+ thu: /^ਵ(ੀਰ(.(ਵਾਰ)?)?)?/i,
+ fri: /^ਸ਼(ੁਕਰ(.(ਰਵਾਰ)?)?)?/i,
+ sat: /^ਸ਼(ਨੀ(.(ਚਰਵਾਰ)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/pl-PL.js b/addons/web/static/lib/datejs/globalization/pl-PL.js
new file mode 100644
index 00000000000..c44d002ffe4
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/pl-PL.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pl-PL",
+ englishName: "Polish (Poland)",
+ nativeName: "polski (Polska)",
+
+ /* Day Name Strings */
+ dayNames: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"],
+ abbreviatedDayNames: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
+ shortestDayNames: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
+ firstLetterDayNames: ["N", "P", "W", "Ś", "C", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień"],
+ abbreviatedMonthNames: ["sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^sty(czeń)?/i,
+ feb: /^lut(y)?/i,
+ mar: /^mar(zec)?/i,
+ apr: /^kwi(ecień)?/i,
+ may: /^maj/i,
+ jun: /^cze(rwiec)?/i,
+ jul: /^lip(iec)?/i,
+ aug: /^sie(rpień)?/i,
+ sep: /^wrz(esień)?/i,
+ oct: /^paź(dziernik)?/i,
+ nov: /^lis(topad)?/i,
+ dec: /^gru(dzień)?/i,
+
+ sun: /^niedziela/i,
+ mon: /^poniedziałek/i,
+ tue: /^wtorek/i,
+ wed: /^środa/i,
+ thu: /^czwartek/i,
+ fri: /^piątek/i,
+ sat: /^sobota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/pt-BR.js b/addons/web/static/lib/datejs/globalization/pt-BR.js
new file mode 100644
index 00000000000..6313c581d8d
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/pt-BR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pt-BR",
+ englishName: "Portuguese (Brazil)",
+ nativeName: "Português (Brasil)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"],
+ abbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ shortestDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ firstLetterDayNames: ["d", "s", "t", "q", "q", "s", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"],
+ abbreviatedMonthNames: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd' de 'MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(eiro)?/i,
+ feb: /^fev(ereiro)?/i,
+ mar: /^mar(ço)?/i,
+ apr: /^abr(il)?/i,
+ may: /^mai(o)?/i,
+ jun: /^jun(ho)?/i,
+ jul: /^jul(ho)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(embro)?/i,
+ oct: /^out(ubro)?/i,
+ nov: /^nov(embro)?/i,
+ dec: /^dez(embro)?/i,
+
+ sun: /^domingo/i,
+ mon: /^segunda-feira/i,
+ tue: /^terça-feira/i,
+ wed: /^quarta-feira/i,
+ thu: /^quinta-feira/i,
+ fri: /^sexta-feira/i,
+ sat: /^sábado/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/pt-PT.js b/addons/web/static/lib/datejs/globalization/pt-PT.js
new file mode 100644
index 00000000000..6c19c28f5bf
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/pt-PT.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pt-PT",
+ englishName: "Portuguese (Portugal)",
+ nativeName: "português (Portugal)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"],
+ abbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ shortestDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ firstLetterDayNames: ["d", "s", "t", "q", "q", "s", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"],
+ abbreviatedMonthNames: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dddd, d' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d/M",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(eiro)?/i,
+ feb: /^fev(ereiro)?/i,
+ mar: /^mar(ço)?/i,
+ apr: /^abr(il)?/i,
+ may: /^mai(o)?/i,
+ jun: /^jun(ho)?/i,
+ jul: /^jul(ho)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(embro)?/i,
+ oct: /^out(ubro)?/i,
+ nov: /^nov(embro)?/i,
+ dec: /^dez(embro)?/i,
+
+ sun: /^domingo/i,
+ mon: /^segunda-feira/i,
+ tue: /^terça-feira/i,
+ wed: /^quarta-feira/i,
+ thu: /^quinta-feira/i,
+ fri: /^sexta-feira/i,
+ sat: /^sábado/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/quz-BO.js b/addons/web/static/lib/datejs/globalization/quz-BO.js
new file mode 100644
index 00000000000..86f0a4f74d9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/quz-BO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "quz-BO",
+ englishName: "Quechua (Bolivia)",
+ nativeName: "runasimi (Bolivia Suyu)",
+
+ /* Day Name Strings */
+ dayNames: ["intichaw", "killachaw", "atipachaw", "quyllurchaw", "Ch' askachaw", "Illapachaw", "k'uychichaw"],
+ abbreviatedDayNames: ["int", "kil", "ati", "quy", "Ch’", "Ill", "k'u"],
+ shortestDayNames: ["int", "kil", "ati", "quy", "Ch’", "Ill", "k'u"],
+ firstLetterDayNames: ["i", "k", "a", "q", "C", "I", "k"],
+
+ /* Month Name Strings */
+ monthNames: ["Qulla puquy", "Hatun puquy", "Pauqar waray", "ayriwa", "Aymuray", "Inti raymi", "Anta Sitwa", "Qhapaq Sitwa", "Uma raymi", "Kantaray", "Ayamarq'a", "Kapaq Raymi"],
+ abbreviatedMonthNames: ["Qul", "Hat", "Pau", "ayr", "Aym", "Int", "Ant", "Qha", "Uma", "Kan", "Aya", "Kap"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm:ss tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^qul(la puquy)?/i,
+ feb: /^hat(un puquy)?/i,
+ mar: /^pau(qar waray)?/i,
+ apr: /^ayr(iwa)?/i,
+ may: /^aym(uray)?/i,
+ jun: /^int(i raymi)?/i,
+ jul: /^ant(a sitwa)?/i,
+ aug: /^qha(paq sitwa)?/i,
+ sep: /^uma( raymi)?/i,
+ oct: /^kan(taray)?/i,
+ nov: /^aya(marq'a)?/i,
+ dec: /^kap(aq raymi)?/i,
+
+ sun: /^intichaw/i,
+ mon: /^killachaw/i,
+ tue: /^atipachaw/i,
+ wed: /^quyllurchaw/i,
+ thu: /^ch' askachaw/i,
+ fri: /^illapachaw/i,
+ sat: /^k'uychichaw/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/quz-EC.js b/addons/web/static/lib/datejs/globalization/quz-EC.js
new file mode 100644
index 00000000000..e72514dd09f
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/quz-EC.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "quz-EC",
+ englishName: "Quechua (Ecuador)",
+ nativeName: "runasimi (Ecuador Suyu)",
+
+ /* Day Name Strings */
+ dayNames: ["intichaw", "killachaw", "atipachaw", "quyllurchaw", "Ch' askachaw", "Illapachaw", "k'uychichaw"],
+ abbreviatedDayNames: ["int", "kil", "ati", "quy", "Ch’", "Ill", "k'u"],
+ shortestDayNames: ["int", "kil", "ati", "quy", "Ch’", "Ill", "k'u"],
+ firstLetterDayNames: ["i", "k", "a", "q", "C", "I", "k"],
+
+ /* Month Name Strings */
+ monthNames: ["Qulla puquy", "Hatun puquy", "Pauqar waray", "ayriwa", "Aymuray", "Inti raymi", "Anta Sitwa", "Qhapaq Sitwa", "Uma raymi", "Kantaray", "Ayamarq'a", "Kapaq Raymi"],
+ abbreviatedMonthNames: ["Qul", "Hat", "Pau", "ayr", "Aym", "Int", "Ant", "Qha", "Uma", "Kan", "Aya", "Kap"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^qul(la puquy)?/i,
+ feb: /^hat(un puquy)?/i,
+ mar: /^pau(qar waray)?/i,
+ apr: /^ayr(iwa)?/i,
+ may: /^aym(uray)?/i,
+ jun: /^int(i raymi)?/i,
+ jul: /^ant(a sitwa)?/i,
+ aug: /^qha(paq sitwa)?/i,
+ sep: /^uma( raymi)?/i,
+ oct: /^kan(taray)?/i,
+ nov: /^aya(marq'a)?/i,
+ dec: /^kap(aq raymi)?/i,
+
+ sun: /^intichaw/i,
+ mon: /^killachaw/i,
+ tue: /^atipachaw/i,
+ wed: /^quyllurchaw/i,
+ thu: /^ch' askachaw/i,
+ fri: /^illapachaw/i,
+ sat: /^k'uychichaw/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/quz-PE.js b/addons/web/static/lib/datejs/globalization/quz-PE.js
new file mode 100644
index 00000000000..42c1e5c0c83
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/quz-PE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "quz-PE",
+ englishName: "Quechua (Peru)",
+ nativeName: "runasimi (Peru Suyu)",
+
+ /* Day Name Strings */
+ dayNames: ["intichaw", "killachaw", "atipachaw", "quyllurchaw", "Ch' askachaw", "Illapachaw", "k'uychichaw"],
+ abbreviatedDayNames: ["int", "kil", "ati", "quy", "Ch’", "Ill", "k'u"],
+ shortestDayNames: ["int", "kil", "ati", "quy", "Ch’", "Ill", "k'u"],
+ firstLetterDayNames: ["i", "k", "a", "q", "C", "I", "k"],
+
+ /* Month Name Strings */
+ monthNames: ["Qulla puquy", "Hatun puquy", "Pauqar waray", "ayriwa", "Aymuray", "Inti raymi", "Anta Sitwa", "Qhapaq Sitwa", "Uma raymi", "Kantaray", "Ayamarq'a", "Kapaq Raymi"],
+ abbreviatedMonthNames: ["Qul", "Hat", "Pau", "ayr", "Aym", "Int", "Ant", "Qha", "Uma", "Kan", "Aya", "Kap"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "hh:mm:ss tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^qul(la puquy)?/i,
+ feb: /^hat(un puquy)?/i,
+ mar: /^pau(qar waray)?/i,
+ apr: /^ayr(iwa)?/i,
+ may: /^aym(uray)?/i,
+ jun: /^int(i raymi)?/i,
+ jul: /^ant(a sitwa)?/i,
+ aug: /^qha(paq sitwa)?/i,
+ sep: /^uma( raymi)?/i,
+ oct: /^kan(taray)?/i,
+ nov: /^aya(marq'a)?/i,
+ dec: /^kap(aq raymi)?/i,
+
+ sun: /^intichaw/i,
+ mon: /^killachaw/i,
+ tue: /^atipachaw/i,
+ wed: /^quyllurchaw/i,
+ thu: /^ch' askachaw/i,
+ fri: /^illapachaw/i,
+ sat: /^k'uychichaw/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ro-RO.js b/addons/web/static/lib/datejs/globalization/ro-RO.js
new file mode 100644
index 00000000000..b35d3e5efbb
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ro-RO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ro-RO",
+ englishName: "Romanian (Romania)",
+ nativeName: "română (România)",
+
+ /* Day Name Strings */
+ dayNames: ["duminică", "luni", "marţi", "miercuri", "joi", "vineri", "sâmbătă"],
+ abbreviatedDayNames: ["D", "L", "Ma", "Mi", "J", "V", "S"],
+ shortestDayNames: ["D", "L", "Ma", "Mi", "J", "V", "S"],
+ firstLetterDayNames: ["D", "L", "M", "M", "J", "V", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["ianuarie", "februarie", "martie", "aprilie", "mai", "iunie", "iulie", "august", "septembrie", "octombrie", "noiembrie", "decembrie"],
+ abbreviatedMonthNames: ["ian.", "feb.", "mar.", "apr.", "mai.", "iun.", "iul.", "aug.", "sep.", "oct.", "nov.", "dec."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ian(.(uarie)?)?/i,
+ feb: /^feb(.(ruarie)?)?/i,
+ mar: /^mar(.(tie)?)?/i,
+ apr: /^apr(.(ilie)?)?/i,
+ may: /^mai(.()?)?/i,
+ jun: /^iun(.(ie)?)?/i,
+ jul: /^iul(.(ie)?)?/i,
+ aug: /^aug(.(ust)?)?/i,
+ sep: /^sep(.(tembrie)?)?/i,
+ oct: /^oct(.(ombrie)?)?/i,
+ nov: /^noiembrie/i,
+ dec: /^dec(.(embrie)?)?/i,
+
+ sun: /^duminică/i,
+ mon: /^luni/i,
+ tue: /^marţi/i,
+ wed: /^miercuri/i,
+ thu: /^joi/i,
+ fri: /^vineri/i,
+ sat: /^sâmbătă/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ru-RU.js b/addons/web/static/lib/datejs/globalization/ru-RU.js
new file mode 100644
index 00000000000..3b741984c01
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ru-RU.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ru-RU",
+ englishName: "Russian (Russia)",
+ nativeName: "русский (Россия)",
+
+ /* Day Name Strings */
+ dayNames: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
+ abbreviatedDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ shortestDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ firstLetterDayNames: ["В", "П", "В", "С", "Ч", "П", "С"],
+
+ /* Month Name Strings */
+ monthNames: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
+ abbreviatedMonthNames: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy 'г.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy 'г.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy 'г.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^янв(арь)?/i,
+ feb: /^фев(раль)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ель)?/i,
+ may: /^май/i,
+ jun: /^июн(ь)?/i,
+ jul: /^июл(ь)?/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сен(тябрь)?/i,
+ oct: /^окт(ябрь)?/i,
+ nov: /^ноя(брь)?/i,
+ dec: /^дек(абрь)?/i,
+
+ sun: /^воскресенье/i,
+ mon: /^понедельник/i,
+ tue: /^вторник/i,
+ wed: /^среда/i,
+ thu: /^четверг/i,
+ fri: /^пятница/i,
+ sat: /^суббота/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sa-IN.js b/addons/web/static/lib/datejs/globalization/sa-IN.js
new file mode 100644
index 00000000000..571cf0b451b
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sa-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sa-IN",
+ englishName: "Sanskrit (India)",
+ nativeName: "संस्कृत (भारतम्)",
+
+ /* Day Name Strings */
+ dayNames: ["रविवासरः", "सोमवासरः", "मङ्गलवासरः", "बुधवासरः", "गुरुवासरः", "शुक्रवासरः", "शनिवासरः"],
+ abbreviatedDayNames: ["रविवासरः", "सोमवासरः", "मङ्गलवासरः", "बुधवासरः", "गुरुवासरः", "शुक्रवासरः", "शनिवासरः"],
+ shortestDayNames: ["र", "स", "म", "ब", "ग", "श", "श"],
+ firstLetterDayNames: ["र", "स", "म", "ब", "ग", "श", "श"],
+
+ /* Month Name Strings */
+ monthNames: ["जनवरी", "फरवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितम्बर", "अक्तूबर", "नवम्बर", "दिसम्बर"],
+ abbreviatedMonthNames: ["जनवरी", "फरवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितम्बर", "अक्तूबर", "नवम्बर", "दिसम्बर"],
+
+ /* AM/PM Designators */
+ amDesignator: "पूर्वाह्न",
+ pmDesignator: "अपराह्न",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM yyyy dddd",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy dddd HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^जनवरी/i,
+ feb: /^फरवरी/i,
+ mar: /^मार्च/i,
+ apr: /^अप्रैल/i,
+ may: /^मई/i,
+ jun: /^जून/i,
+ jul: /^जुलाई/i,
+ aug: /^अगस्त/i,
+ sep: /^सितम्बर/i,
+ oct: /^अक्तूबर/i,
+ nov: /^नवम्बर/i,
+ dec: /^दिसम्बर/i,
+
+ sun: /^र(1)?/i,
+ mon: /^स(1)?/i,
+ tue: /^म(1)?/i,
+ wed: /^ब(1)?/i,
+ thu: /^ग(1)?/i,
+ fri: /^श(1)?/i,
+ sat: /^श(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/se-FI.js b/addons/web/static/lib/datejs/globalization/se-FI.js
new file mode 100644
index 00000000000..e1324b05778
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/se-FI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "se-FI",
+ englishName: "Sami (Northern) (Finland)",
+ nativeName: "davvisámegiella (Suopma)",
+
+ /* Day Name Strings */
+ dayNames: ["sotnabeaivi", "vuossárga", "maŋŋebárga", "gaskavahkku", "duorastat", "bearjadat", "lávvardat"],
+ abbreviatedDayNames: ["sotn", "vuos", "maŋ", "gask", "duor", "bear", "láv"],
+ shortestDayNames: ["sotn", "vuos", "maŋ", "gask", "duor", "bear", "láv"],
+ firstLetterDayNames: ["s", "v", "m", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["ođđajagemánnu", "guovvamánnu", "njukčamánnu", "cuoŋománnu", "miessemánnu", "geassemánnu", "suoidnemánnu", "borgemánnu", "čakčamánnu", "golggotmánnu", "skábmamánnu", "juovlamánnu"],
+ abbreviatedMonthNames: ["ođđj", "guov", "njuk", "cuo", "mies", "geas", "suoi", "borg", "čakč", "golg", "skáb", "juov"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ođđajagemánnu/i,
+ feb: /^guov(vamánnu)?/i,
+ mar: /^njuk(čamánnu)?/i,
+ apr: /^cuo(ŋománnu)?/i,
+ may: /^mies(semánnu)?/i,
+ jun: /^geas(semánnu)?/i,
+ jul: /^suoi(dnemánnu)?/i,
+ aug: /^borg(emánnu)?/i,
+ sep: /^čakč(amánnu)?/i,
+ oct: /^golg(gotmánnu)?/i,
+ nov: /^skáb(mamánnu)?/i,
+ dec: /^juov(lamánnu)?/i,
+
+ sun: /^sotnabeaivi/i,
+ mon: /^vuossárga/i,
+ tue: /^maŋŋebárga/i,
+ wed: /^gaskavahkku/i,
+ thu: /^duorastat/i,
+ fri: /^bearjadat/i,
+ sat: /^lávvardat/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/se-NO.js b/addons/web/static/lib/datejs/globalization/se-NO.js
new file mode 100644
index 00000000000..356be9bea89
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/se-NO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "se-NO",
+ englishName: "Sami (Northern) (Norway)",
+ nativeName: "davvisámegiella (Norga)",
+
+ /* Day Name Strings */
+ dayNames: ["sotnabeaivi", "vuossárga", "maŋŋebárga", "gaskavahkku", "duorastat", "bearjadat", "lávvardat"],
+ abbreviatedDayNames: ["sotn", "vuos", "maŋ", "gask", "duor", "bear", "láv"],
+ shortestDayNames: ["sotn", "vuos", "maŋ", "gask", "duor", "bear", "láv"],
+ firstLetterDayNames: ["s", "v", "m", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["ođđajagemánnu", "guovvamánnu", "njukčamánnu", "cuoŋománnu", "miessemánnu", "geassemánnu", "suoidnemánnu", "borgemánnu", "čakčamánnu", "golggotmánnu", "skábmamánnu", "juovlamánnu"],
+ abbreviatedMonthNames: ["ođđj", "guov", "njuk", "cuo", "mies", "geas", "suoi", "borg", "čakč", "golg", "skáb", "juov"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ođđajagemánnu/i,
+ feb: /^guov(vamánnu)?/i,
+ mar: /^njuk(čamánnu)?/i,
+ apr: /^cuo(ŋománnu)?/i,
+ may: /^mies(semánnu)?/i,
+ jun: /^geas(semánnu)?/i,
+ jul: /^suoi(dnemánnu)?/i,
+ aug: /^borg(emánnu)?/i,
+ sep: /^čakč(amánnu)?/i,
+ oct: /^golg(gotmánnu)?/i,
+ nov: /^skáb(mamánnu)?/i,
+ dec: /^juov(lamánnu)?/i,
+
+ sun: /^sotnabeaivi/i,
+ mon: /^vuossárga/i,
+ tue: /^maŋŋebárga/i,
+ wed: /^gaskavahkku/i,
+ thu: /^duorastat/i,
+ fri: /^bearjadat/i,
+ sat: /^lávvardat/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/se-SE.js b/addons/web/static/lib/datejs/globalization/se-SE.js
new file mode 100644
index 00000000000..400cb34cc20
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/se-SE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "se-SE",
+ englishName: "Sami (Northern) (Sweden)",
+ nativeName: "davvisámegiella (Ruoŧŧa)",
+
+ /* Day Name Strings */
+ dayNames: ["sotnabeaivi", "mánnodat", "disdat", "gaskavahkku", "duorastat", "bearjadat", "lávvardat"],
+ abbreviatedDayNames: ["sotn", "mán", "dis", "gask", "duor", "bear", "láv"],
+ shortestDayNames: ["sotn", "mán", "dis", "gask", "duor", "bear", "láv"],
+ firstLetterDayNames: ["s", "m", "d", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["ođđajagemánnu", "guovvamánnu", "njukčamánnu", "cuoŋománnu", "miessemánnu", "geassemánnu", "suoidnemánnu", "borgemánnu", "čakčamánnu", "golggotmánnu", "skábmamánnu", "juovlamánnu"],
+ abbreviatedMonthNames: ["ođđj", "guov", "njuk", "cuo", "mies", "geas", "suoi", "borg", "čakč", "golg", "skáb", "juov"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ođđajagemánnu/i,
+ feb: /^guov(vamánnu)?/i,
+ mar: /^njuk(čamánnu)?/i,
+ apr: /^cuo(ŋománnu)?/i,
+ may: /^mies(semánnu)?/i,
+ jun: /^geas(semánnu)?/i,
+ jul: /^suoi(dnemánnu)?/i,
+ aug: /^borg(emánnu)?/i,
+ sep: /^čakč(amánnu)?/i,
+ oct: /^golg(gotmánnu)?/i,
+ nov: /^skáb(mamánnu)?/i,
+ dec: /^juov(lamánnu)?/i,
+
+ sun: /^sotnabeaivi/i,
+ mon: /^mánnodat/i,
+ tue: /^disdat/i,
+ wed: /^gaskavahkku/i,
+ thu: /^duorastat/i,
+ fri: /^bearjadat/i,
+ sat: /^lávvardat/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sk-SK.js b/addons/web/static/lib/datejs/globalization/sk-SK.js
new file mode 100644
index 00000000000..8d6359c6e32
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sk-SK.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sk-SK",
+ englishName: "Slovak (Slovakia)",
+ nativeName: "slovenčina (Slovenská republika)",
+
+ /* Day Name Strings */
+ dayNames: ["nedeľa", "pondelok", "utorok", "streda", "štvrtok", "piatok", "sobota"],
+ abbreviatedDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"],
+ shortestDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"],
+ firstLetterDayNames: ["n", "p", "u", "s", "š", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["január", "február", "marec", "apríl", "máj", "jún", "júl", "august", "september", "október", "november", "december"],
+ abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d. M. yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^január/i,
+ feb: /^február/i,
+ mar: /^marec/i,
+ apr: /^apríl/i,
+ may: /^máj/i,
+ jun: /^jún/i,
+ jul: /^júl/i,
+ aug: /^august/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^október/i,
+ nov: /^november/i,
+ dec: /^december/i,
+
+ sun: /^nedeľa/i,
+ mon: /^pondelok/i,
+ tue: /^utorok/i,
+ wed: /^streda/i,
+ thu: /^štvrtok/i,
+ fri: /^piatok/i,
+ sat: /^sobota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sl-SI.js b/addons/web/static/lib/datejs/globalization/sl-SI.js
new file mode 100644
index 00000000000..901e00f2e54
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sl-SI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sl-SI",
+ englishName: "Slovenian (Slovenia)",
+ nativeName: "slovenski (Slovenija)",
+
+ /* Day Name Strings */
+ dayNames: ["nedelja", "ponedeljek", "torek", "sreda", "četrtek", "petek", "sobota"],
+ abbreviatedDayNames: ["ned", "pon", "tor", "sre", "čet", "pet", "sob"],
+ shortestDayNames: ["ne", "po", "to", "sr", "če", "pe", "so"],
+ firstLetterDayNames: ["n", "p", "t", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "marec", "april", "maj", "junij", "julij", "avgust", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(ec)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(ij)?/i,
+ jul: /^jul(ij)?/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^ne(d(elja)?)?/i,
+ mon: /^po(n(edeljek)?)?/i,
+ tue: /^to(r(ek)?)?/i,
+ wed: /^sr(e(da)?)?/i,
+ thu: /^če(t(rtek)?)?/i,
+ fri: /^pe(t(ek)?)?/i,
+ sat: /^so(b(ota)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sma-NO.js b/addons/web/static/lib/datejs/globalization/sma-NO.js
new file mode 100644
index 00000000000..610f40b1eb9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sma-NO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sma-NO",
+ englishName: "Sami (Southern) (Norway)",
+ nativeName: "åarjelsaemiengiele (Nöörje)",
+
+ /* Day Name Strings */
+ dayNames: ["aejlege", "måanta", "dæjsta", "gaskevåhkoe", "duarsta", "bearjadahke", "laavvardahke"],
+ abbreviatedDayNames: ["aej", "måa", "dæj", "gask", "duar", "bearj", "laav"],
+ shortestDayNames: ["aej", "måa", "dæj", "gask", "duar", "bearj", "laav"],
+ firstLetterDayNames: ["a", "m", "d", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["tsïengele", "goevte", "njoktje", "voerhtje", "suehpede", "ruffie", "snjaltje", "mïetske", "skïerede", "golke", "rahka", "goeve"],
+ abbreviatedMonthNames: ["tsïen", "goevt", "njok", "voer", "sueh", "ruff", "snja", "mïet", "skïer", "golk", "rahk", "goev"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^tsïen(gele)?/i,
+ feb: /^goevt(e)?/i,
+ mar: /^njok(tje)?/i,
+ apr: /^voer(htje)?/i,
+ may: /^sueh(pede)?/i,
+ jun: /^ruff(ie)?/i,
+ jul: /^snja(ltje)?/i,
+ aug: /^mïet(ske)?/i,
+ sep: /^skïer(ede)?/i,
+ oct: /^golk(e)?/i,
+ nov: /^rahk(a)?/i,
+ dec: /^goev(e)?/i,
+
+ sun: /^aejlege/i,
+ mon: /^måanta/i,
+ tue: /^dæjsta/i,
+ wed: /^gaskevåhkoe/i,
+ thu: /^duarsta/i,
+ fri: /^bearjadahke/i,
+ sat: /^laavvardahke/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sma-SE.js b/addons/web/static/lib/datejs/globalization/sma-SE.js
new file mode 100644
index 00000000000..9a5854e6a24
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sma-SE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sma-SE",
+ englishName: "Sami (Southern) (Sweden)",
+ nativeName: "åarjelsaemiengiele (Sveerje)",
+
+ /* Day Name Strings */
+ dayNames: ["aejlege", "måanta", "dæjsta", "gaskevåhkoe", "duarsta", "bearjadahke", "laavvardahke"],
+ abbreviatedDayNames: ["aej", "måa", "dæj", "gask", "duar", "bearj", "laav"],
+ shortestDayNames: ["aej", "måa", "dæj", "gask", "duar", "bearj", "laav"],
+ firstLetterDayNames: ["a", "m", "d", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["tsïengele", "goevte", "njoktje", "voerhtje", "suehpede", "ruffie", "snjaltje", "mïetske", "skïerede", "golke", "rahka", "goeve"],
+ abbreviatedMonthNames: ["tsïen", "goevt", "njok", "voer", "sueh", "ruff", "snja", "mïet", "skïer", "golk", "rahk", "goev"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^tsïen(gele)?/i,
+ feb: /^goevt(e)?/i,
+ mar: /^njok(tje)?/i,
+ apr: /^voer(htje)?/i,
+ may: /^sueh(pede)?/i,
+ jun: /^ruff(ie)?/i,
+ jul: /^snja(ltje)?/i,
+ aug: /^mïet(ske)?/i,
+ sep: /^skïer(ede)?/i,
+ oct: /^golk(e)?/i,
+ nov: /^rahk(a)?/i,
+ dec: /^goev(e)?/i,
+
+ sun: /^aejlege/i,
+ mon: /^måanta/i,
+ tue: /^dæjsta/i,
+ wed: /^gaskevåhkoe/i,
+ thu: /^duarsta/i,
+ fri: /^bearjadahke/i,
+ sat: /^laavvardahke/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/smj-NO.js b/addons/web/static/lib/datejs/globalization/smj-NO.js
new file mode 100644
index 00000000000..66e061deca9
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/smj-NO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "smj-NO",
+ englishName: "Sami (Lule) (Norway)",
+ nativeName: "julevusámegiella (Vuodna)",
+
+ /* Day Name Strings */
+ dayNames: ["sådnåbiejvve", "mánnodahka", "dijstahka", "gasskavahkko", "duorastahka", "bierjjedahka", "lávvodahka"],
+ abbreviatedDayNames: ["såd", "mán", "dis", "gas", "duor", "bier", "láv"],
+ shortestDayNames: ["såd", "mán", "dis", "gas", "duor", "bier", "láv"],
+ firstLetterDayNames: ["s", "m", "d", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["ådåjakmánno", "guovvamánno", "sjnjuktjamánno", "vuoratjismánno", "moarmesmánno", "biehtsemánno", "sjnjilltjamánno", "bårggemánno", "ragátmánno", "gålgådismánno", "basádismánno", "javllamánno"],
+ abbreviatedMonthNames: ["ådåj", "guov", "snju", "vuor", "moar", "bieh", "snji", "bårg", "ragá", "gålg", "basá", "javl"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ådåj(akmánno)?/i,
+ feb: /^guov(vamánno)?/i,
+ mar: /^sjnjuktjamánno/i,
+ apr: /^vuor(atjismánno)?/i,
+ may: /^moar(mesmánno)?/i,
+ jun: /^bieh(tsemánno)?/i,
+ jul: /^sjnjilltjamánno/i,
+ aug: /^bårg(gemánno)?/i,
+ sep: /^ragá(tmánno)?/i,
+ oct: /^gålg(ådismánno)?/i,
+ nov: /^basá(dismánno)?/i,
+ dec: /^javl(lamánno)?/i,
+
+ sun: /^sådnåbiejvve/i,
+ mon: /^mánnodahka/i,
+ tue: /^dijstahka/i,
+ wed: /^gasskavahkko/i,
+ thu: /^duorastahka/i,
+ fri: /^bierjjedahka/i,
+ sat: /^lávvodahka/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/smj-SE.js b/addons/web/static/lib/datejs/globalization/smj-SE.js
new file mode 100644
index 00000000000..9c6c628b1a7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/smj-SE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "smj-SE",
+ englishName: "Sami (Lule) (Sweden)",
+ nativeName: "julevusámegiella (Svierik)",
+
+ /* Day Name Strings */
+ dayNames: ["ájllek", "mánnodahka", "dijstahka", "gasskavahkko", "duorastahka", "bierjjedahka", "lávvodahka"],
+ abbreviatedDayNames: ["ájl", "mán", "dis", "gas", "duor", "bier", "láv"],
+ shortestDayNames: ["ájl", "mán", "dis", "gas", "duor", "bier", "láv"],
+ firstLetterDayNames: ["á", "m", "d", "g", "d", "b", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["ådåjakmánno", "guovvamánno", "sjnjuktjamánno", "vuoratjismánno", "moarmesmánno", "biehtsemánno", "sjnjilltjamánno", "bårggemánno", "ragátmánno", "gålgådismánno", "basádismánno", "javllamánno"],
+ abbreviatedMonthNames: ["ådåj", "guov", "snju", "vuor", "moar", "bieh", "snji", "bårg", "ragá", "gålg", "basá", "javl"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "MMMM d'. b. 'yyyy",
+ shortTime: "HH:mm:ss",
+ longTime: "HH:mm:ss",
+ fullDateTime: "MMMM d'. b. 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ådåj(akmánno)?/i,
+ feb: /^guov(vamánno)?/i,
+ mar: /^sjnjuktjamánno/i,
+ apr: /^vuor(atjismánno)?/i,
+ may: /^moar(mesmánno)?/i,
+ jun: /^bieh(tsemánno)?/i,
+ jul: /^sjnjilltjamánno/i,
+ aug: /^bårg(gemánno)?/i,
+ sep: /^ragá(tmánno)?/i,
+ oct: /^gålg(ådismánno)?/i,
+ nov: /^basá(dismánno)?/i,
+ dec: /^javl(lamánno)?/i,
+
+ sun: /^ájllek/i,
+ mon: /^mánnodahka/i,
+ tue: /^dijstahka/i,
+ wed: /^gasskavahkko/i,
+ thu: /^duorastahka/i,
+ fri: /^bierjjedahka/i,
+ sat: /^lávvodahka/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/smn-FI.js b/addons/web/static/lib/datejs/globalization/smn-FI.js
new file mode 100644
index 00000000000..45cf715ad7e
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/smn-FI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "smn-FI",
+ englishName: "Sami (Inari) (Finland)",
+ nativeName: "sämikielâ (Suomâ)",
+
+ /* Day Name Strings */
+ dayNames: ["pasepeivi", "vuossargâ", "majebargâ", "koskokko", "tuorâstâh", "vástuppeivi", "lávárdâh"],
+ abbreviatedDayNames: ["pa", "vu", "ma", "ko", "tu", "vá", "lá"],
+ shortestDayNames: ["pa", "vu", "ma", "ko", "tu", "vá", "lá"],
+ firstLetterDayNames: ["p", "v", "m", "k", "t", "v", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["uđđâivemáánu", "kuovâmáánu", "njuhčâmáánu", "cuáŋuimáánu", "vyesimáánu", "kesimáánu", "syeinimáánu", "porgemáánu", "čohčâmáánu", "roovvâdmáánu", "skammâmáánu", "juovlâmáánu"],
+ abbreviatedMonthNames: ["uđiv", "kuov", "njuh", "cuoŋ", "vyes", "kesi", "syei", "porg", "čoh", "roov", "ska", "juov"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "MMMM d'. p. 'yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "MMMM d'. p. 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^uđđâivemáánu/i,
+ feb: /^kuov(âmáánu)?/i,
+ mar: /^njuh(čâmáánu)?/i,
+ apr: /^cuáŋuimáánu/i,
+ may: /^vyes(imáánu)?/i,
+ jun: /^kesi(máánu)?/i,
+ jul: /^syei(nimáánu)?/i,
+ aug: /^porg(emáánu)?/i,
+ sep: /^čoh(čâmáánu)?/i,
+ oct: /^roov(vâdmáánu)?/i,
+ nov: /^ska(mmâmáánu)?/i,
+ dec: /^juov(lâmáánu)?/i,
+
+ sun: /^pasepeivi/i,
+ mon: /^vuossargâ/i,
+ tue: /^majebargâ/i,
+ wed: /^koskokko/i,
+ thu: /^tuorâstâh/i,
+ fri: /^vástuppeivi/i,
+ sat: /^lávárdâh/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sms-FI.js b/addons/web/static/lib/datejs/globalization/sms-FI.js
new file mode 100644
index 00000000000..4bffb33a13d
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sms-FI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sms-FI",
+ englishName: "Sami (Skolt) (Finland)",
+ nativeName: "sääm´ǩiõll (Lää´ddjânnam)",
+
+ /* Day Name Strings */
+ dayNames: ["pâ´sspei´vv", "vuõssargg", "mââibargg", "seärad", "nelljdpei´vv", "piâtnâc", "sue´vet"],
+ abbreviatedDayNames: ["pâ", "vu", "mâ", "se", "ne", "pi", "su"],
+ shortestDayNames: ["pâ", "vu", "mâ", "se", "ne", "pi", "su"],
+ firstLetterDayNames: ["p", "v", "m", "s", "n", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["ođđee´jjmään", "tä´lvvmään", "pâ´zzlâšttammään", "njuhččmään", "vue´ssmään", "ǩie´ssmään", "suei´nnmään", "på´rǧǧmään", "čõhččmään", "kålggmään", "skamm´mään", "rosttovmään"],
+ abbreviatedMonthNames: ["ođjm", "tä´lvv", "pâzl", "njuh", "vue", "ǩie", "suei", "på´r", "čõh", "kålg", "ska", "rost"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "MMMM d'. p. 'yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "MMMM d'. p. 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ođđee´jjmään/i,
+ feb: /^tä´lvv(mään)?/i,
+ mar: /^pâ´zzlâšttammään/i,
+ apr: /^njuh(ččmään)?/i,
+ may: /^vue(´ssmään)?/i,
+ jun: /^ǩie(´ssmään)?/i,
+ jul: /^suei(´nnmään)?/i,
+ aug: /^på´r(ǧǧmään)?/i,
+ sep: /^čõh(ččmään)?/i,
+ oct: /^kålg(gmään)?/i,
+ nov: /^ska(mm´mään)?/i,
+ dec: /^rost(tovmään)?/i,
+
+ sun: /^pâ´sspei´vv/i,
+ mon: /^vuõssargg/i,
+ tue: /^mââibargg/i,
+ wed: /^seärad/i,
+ thu: /^nelljdpei´vv/i,
+ fri: /^piâtnâc/i,
+ sat: /^sue´vet/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sq-AL.js b/addons/web/static/lib/datejs/globalization/sq-AL.js
new file mode 100644
index 00000000000..1690471ca18
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sq-AL.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sq-AL",
+ englishName: "Albanian (Albania)",
+ nativeName: "shqipe (Shqipëria)",
+
+ /* Day Name Strings */
+ dayNames: ["e diel", "e hënë", "e martë", "e mërkurë", "e enjte", "e premte", "e shtunë"],
+ abbreviatedDayNames: ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Sht"],
+ shortestDayNames: ["Di", "Hë", "Ma", "Më", "En", "Pr", "Sh"],
+ firstLetterDayNames: ["D", "H", "M", "M", "E", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["janar", "shkurt", "mars", "prill", "maj", "qershor", "korrik", "gusht", "shtator", "tetor", "nëntor", "dhjetor"],
+ abbreviatedMonthNames: ["Jan", "Shk", "Mar", "Pri", "Maj", "Qer", "Kor", "Gsh", "Sht", "Tet", "Nën", "Dhj"],
+
+ /* AM/PM Designators */
+ amDesignator: "PD",
+ pmDesignator: "MD",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "yyyy-MM-dd",
+ shortTime: "h:mm.tt",
+ longTime: "h:mm:ss.tt",
+ fullDateTime: "yyyy-MM-dd h:mm:ss.tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "yyyy-MM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(ar)?/i,
+ feb: /^shk(urt)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^pri(ll)?/i,
+ may: /^maj/i,
+ jun: /^qer(shor)?/i,
+ jul: /^kor(rik)?/i,
+ aug: /^gusht/i,
+ sep: /^sht(ator)?/i,
+ oct: /^tet(or)?/i,
+ nov: /^nën(tor)?/i,
+ dec: /^dhj(etor)?/i,
+
+ sun: /^di(e(iel)?)?/i,
+ mon: /^hë(n(ënë)?)?/i,
+ tue: /^ma(r(artë)?)?/i,
+ wed: /^më(r(ërkurë)?)?/i,
+ thu: /^en(j(njte)?)?/i,
+ fri: /^pr(e(remte)?)?/i,
+ sat: /^sh(t(htunë)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sr-Cyrl-BA.js b/addons/web/static/lib/datejs/globalization/sr-Cyrl-BA.js
new file mode 100644
index 00000000000..c22a8566ea2
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sr-Cyrl-BA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sr-Cyrl-BA",
+ englishName: "Serbian (Cyrillic) (Bosnia and Herzegovina)",
+ nativeName: "српски (Босна и Херцеговина)",
+
+ /* Day Name Strings */
+ dayNames: ["недеља", "понедељак", "уторак", "среда", "четвртак", "петак", "субота"],
+ abbreviatedDayNames: ["нед", "пон", "уто", "сре", "чет", "пет", "суб"],
+ shortestDayNames: ["нед", "пон", "уто", "сре", "чет", "пет", "суб"],
+ firstLetterDayNames: ["н", "п", "у", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["јануар", "фебруар", "март", "април", "мај", "јун", "јул", "август", "септембар", "октобар", "новембар", "децембар"],
+ abbreviatedMonthNames: ["јан", "феб", "мар", "апр", "мај", "јун", "јул", "авг", "сеп", "окт", "нов", "дец"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^јан(уар)?/i,
+ feb: /^феб(руар)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ил)?/i,
+ may: /^мај/i,
+ jun: /^јун/i,
+ jul: /^јул/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сеп(тембар)?/i,
+ oct: /^окт(обар)?/i,
+ nov: /^нов(ембар)?/i,
+ dec: /^дец(ембар)?/i,
+
+ sun: /^недеља/i,
+ mon: /^понедељак/i,
+ tue: /^уторак/i,
+ wed: /^среда/i,
+ thu: /^четвртак/i,
+ fri: /^петак/i,
+ sat: /^субота/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sr-Cyrl-CS.js b/addons/web/static/lib/datejs/globalization/sr-Cyrl-CS.js
new file mode 100644
index 00000000000..f0922068740
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sr-Cyrl-CS.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sr-Cyrl-CS",
+ englishName: "Serbian (Cyrillic, Serbia)",
+ nativeName: "српски (Србија)",
+
+ /* Day Name Strings */
+ dayNames: ["недеља", "понедељак", "уторак", "среда", "четвртак", "петак", "субота"],
+ abbreviatedDayNames: ["нед", "пон", "уто", "сре", "чет", "пет", "суб"],
+ shortestDayNames: ["не", "по", "ут", "ср", "че", "пе", "су"],
+ firstLetterDayNames: ["н", "п", "у", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["јануар", "фебруар", "март", "април", "мај", "јун", "јул", "август", "септембар", "октобар", "новембар", "децембар"],
+ abbreviatedMonthNames: ["јан", "феб", "мар", "апр", "мај", "јун", "јул", "авг", "сеп", "окт", "нов", "дец"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^јан(уар)?/i,
+ feb: /^феб(руар)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ил)?/i,
+ may: /^мај/i,
+ jun: /^јун/i,
+ jul: /^јул/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сеп(тембар)?/i,
+ oct: /^окт(обар)?/i,
+ nov: /^нов(ембар)?/i,
+ dec: /^дец(ембар)?/i,
+
+ sun: /^не(д(еља)?)?/i,
+ mon: /^по(н(едељак)?)?/i,
+ tue: /^ут(о(рак)?)?/i,
+ wed: /^ср(е(да)?)?/i,
+ thu: /^че(т(вртак)?)?/i,
+ fri: /^пе(т(ак)?)?/i,
+ sat: /^су(б(ота)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sr-Latn-BA.js b/addons/web/static/lib/datejs/globalization/sr-Latn-BA.js
new file mode 100644
index 00000000000..052b146530f
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sr-Latn-BA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sr-Latn-BA",
+ englishName: "Serbian (Latin) (Bosnia and Herzegovina)",
+ nativeName: "srpski (Bosna i Hercegovina)",
+
+ /* Day Name Strings */
+ dayNames: ["nedelja", "ponedeljak", "utorak", "sreda", "četvrtak", "petak", "subota"],
+ abbreviatedDayNames: ["ned", "pon", "uto", "sre", "čet", "pet", "sub"],
+ shortestDayNames: ["ned", "pon", "uto", "sre", "čet", "pet", "sub"],
+ firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun/i,
+ jul: /^jul/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sep(tembar)?/i,
+ oct: /^okt(obar)?/i,
+ nov: /^nov(embar)?/i,
+ dec: /^dec(embar)?/i,
+
+ sun: /^nedelja/i,
+ mon: /^ponedeljak/i,
+ tue: /^utorak/i,
+ wed: /^sreda/i,
+ thu: /^četvrtak/i,
+ fri: /^petak/i,
+ sat: /^subota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sr-Latn-CS.js b/addons/web/static/lib/datejs/globalization/sr-Latn-CS.js
new file mode 100644
index 00000000000..9baa010c021
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sr-Latn-CS.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sr-Latn-CS",
+ englishName: "Serbian (Latin, Serbia)",
+ nativeName: "srpski (Srbija)",
+
+ /* Day Name Strings */
+ dayNames: ["nedelja", "ponedeljak", "utorak", "sreda", "četvrtak", "petak", "subota"],
+ abbreviatedDayNames: ["ned", "pon", "uto", "sre", "čet", "pet", "sub"],
+ shortestDayNames: ["ne", "po", "ut", "sr", "če", "pe", "su"],
+ firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun/i,
+ jul: /^jul/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sep(tembar)?/i,
+ oct: /^okt(obar)?/i,
+ nov: /^nov(embar)?/i,
+ dec: /^dec(embar)?/i,
+
+ sun: /^ne(d(elja)?)?/i,
+ mon: /^po(n(edeljak)?)?/i,
+ tue: /^ut(o(rak)?)?/i,
+ wed: /^sr(e(da)?)?/i,
+ thu: /^če(t(vrtak)?)?/i,
+ fri: /^pe(t(ak)?)?/i,
+ sat: /^su(b(ota)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sv-FI.js b/addons/web/static/lib/datejs/globalization/sv-FI.js
new file mode 100644
index 00000000000..c3882a17d54
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sv-FI.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sv-FI",
+ englishName: "Swedish (Finland)",
+ nativeName: "svenska (Finland)",
+
+ /* Day Name Strings */
+ dayNames: ["söndag", "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag"],
+ abbreviatedDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
+ shortestDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "'den 'd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "'den 'd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "'den 'd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(usti)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^söndag/i,
+ mon: /^måndag/i,
+ tue: /^tisdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lördag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sv-SE.js b/addons/web/static/lib/datejs/globalization/sv-SE.js
new file mode 100644
index 00000000000..1de63182bf4
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sv-SE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sv-SE",
+ englishName: "Swedish (Sweden)",
+ nativeName: "svenska (Sverige)",
+
+ /* Day Name Strings */
+ dayNames: ["söndag", "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag"],
+ abbreviatedDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
+ shortestDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "'den 'd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "'den 'd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "'den 'd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(usti)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^söndag/i,
+ mon: /^måndag/i,
+ tue: /^tisdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lördag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/sw-KE.js b/addons/web/static/lib/datejs/globalization/sw-KE.js
new file mode 100644
index 00000000000..de73841a7f2
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/sw-KE.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sw-KE",
+ englishName: "Kiswahili (Kenya)",
+ nativeName: "Kiswahili (Kenya)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^s(un(day)?)?/i,
+ mon: /^m(on(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^w(ed(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^f(ri(day)?)?/i,
+ sat: /^s(at(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/syr-SY.js b/addons/web/static/lib/datejs/globalization/syr-SY.js
new file mode 100644
index 00000000000..1e662406e93
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/syr-SY.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "syr-SY",
+ englishName: "Syriac (Syria)",
+ nativeName: "ܣܘܪܝܝܐ (سوريا)",
+
+ /* Day Name Strings */
+ dayNames: ["ܚܕ ܒܫܒܐ", "ܬܪܝܢ ܒܫܒܐ", "ܬܠܬܐ ܒܫܒܐ", "ܐܪܒܥܐ ܒܫܒܐ", "ܚܡܫܐ ܒܫܒܐ", "ܥܪܘܒܬܐ", "ܫܒܬܐ"],
+ abbreviatedDayNames: ["܏ܐ ܏ܒܫ", "܏ܒ ܏ܒܫ", "܏ܓ ܏ܒܫ", "܏ܕ ܏ܒܫ", "܏ܗ ܏ܒܫ", "܏ܥܪܘܒ", "܏ܫܒ"],
+ shortestDayNames: ["܏", "܏", "܏", "܏", "܏", "܏", "܏"],
+ firstLetterDayNames: ["܏", "܏", "܏", "܏", "܏", "܏", "܏"],
+
+ /* Month Name Strings */
+ monthNames: ["ܟܢܘܢ ܐܚܪܝ", "ܫܒܛ", "ܐܕܪ", "ܢܝܣܢ", "ܐܝܪ", "ܚܙܝܪܢ", "ܬܡܘܙ", "ܐܒ", "ܐܝܠܘܠ", "ܬܫܪܝ ܩܕܝܡ", "ܬܫܪܝ ܐܚܪܝ", "ܟܢܘܢ ܩܕܝܡ"],
+ abbreviatedMonthNames: ["܏ܟܢ ܏ܒ", "ܫܒܛ", "ܐܕܪ", "ܢܝܣܢ", "ܐܝܪ", "ܚܙܝܪܢ", "ܬܡܘܙ", "ܐܒ", "ܐܝܠܘܠ", "܏ܬܫ ܏ܐ", "܏ܬܫ ܏ܒ", "܏ܟܢ ܏ܐ"],
+
+ /* AM/PM Designators */
+ amDesignator: "ܩ.ܛ",
+ pmDesignator: "ܒ.ܛ",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ܟܢܘܢ ܐܚܪܝ/i,
+ feb: /^ܫܒܛ/i,
+ mar: /^ܐܕܪ/i,
+ apr: /^ܢܝܣܢ/i,
+ may: /^ܐܝܪ/i,
+ jun: /^ܚܙܝܪܢ/i,
+ jul: /^ܬܡܘܙ/i,
+ aug: /^ܐܒ/i,
+ sep: /^ܐܝܠܘܠ/i,
+ oct: /^ܬܫܪܝ ܩܕܝܡ/i,
+ nov: /^ܬܫܪܝ ܐܚܪܝ/i,
+ dec: /^ܟܢܘܢ ܩܕܝܡ/i,
+
+ sun: /^܏(ܐ ܏ܒܫ(ܐ)?)?/i,
+ mon: /^܏(ܒ ܏ܒܫ(ܫܒܐ)?)?/i,
+ tue: /^܏(ܓ ܏ܒܫ(ܫܒܐ)?)?/i,
+ wed: /^܏(ܕ ܏ܒܫ(ܒܫܒܐ)?)?/i,
+ thu: /^܏(ܗ ܏ܒܫ(ܫܒܐ)?)?/i,
+ fri: /^܏(ܥܪܘܒ(ܐ)?)?/i,
+ sat: /^܏(ܫܒ(ܐ)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ta-IN.js b/addons/web/static/lib/datejs/globalization/ta-IN.js
new file mode 100644
index 00000000000..63349a92ce0
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ta-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ta-IN",
+ englishName: "Tamil (India)",
+ nativeName: "தமிழ் (இந்தியா)",
+
+ /* Day Name Strings */
+ dayNames: ["ஞாயிறு", "திங்கள்", "செவ்வாய்", "புதன்", "வியாழன்", "வெள்ளி", "சனி"],
+ abbreviatedDayNames: ["ஞா", "தி", "செ", "பு", "வி", "வெ", "ச"],
+ shortestDayNames: ["ஞ", "த", "ச", "ப", "வ", "வ", "ச"],
+ firstLetterDayNames: ["ஞ", "த", "ச", "ப", "வ", "வ", "ச"],
+
+ /* Month Name Strings */
+ monthNames: ["ஜனவரி", "பெப்ரவரி", "மார்ச்", "ஏப்ரல்", "மே", "ஜூன்", "ஜூலை", "ஆகஸ்ட்", "செப்டம்பர்", "அக்டோபர்", "நவம்பர்", "டிசம்பர்"],
+ abbreviatedMonthNames: ["ஜன.", "பெப்.", "மார்.", "ஏப்.", "மே", "ஜூன்", "ஜூலை", "ஆக.", "செப்.", "அக்.", "நவ.", "டிச."],
+
+ /* AM/PM Designators */
+ amDesignator: "காலை",
+ pmDesignator: "மாலை",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ஜன(.(வரி)?)?/i,
+ feb: /^பெப்(.(ரவரி)?)?/i,
+ mar: /^மார்(.(ச்)?)?/i,
+ apr: /^ஏப்(.(ரல்)?)?/i,
+ may: /^மே/i,
+ jun: /^ஜூன்/i,
+ jul: /^ஜூலை/i,
+ aug: /^ஆக(.(ஸ்ட்)?)?/i,
+ sep: /^செப்(.(டம்பர்)?)?/i,
+ oct: /^அக்(.(டோபர்)?)?/i,
+ nov: /^நவ(.(ம்பர்)?)?/i,
+ dec: /^டிச(.(ம்பர்)?)?/i,
+
+ sun: /^ஞ(ா(யிறு)?)?/i,
+ mon: /^த(ி(ங்கள்)?)?/i,
+ tue: /^ச(ெ(வ்வாய்)?)?/i,
+ wed: /^ப(ு(தன்)?)?/i,
+ thu: /^வ(ி(யாழன்)?)?/i,
+ fri: /^வ(ெ(ள்ளி)?)?/i,
+ sat: /^சனி/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/te-IN.js b/addons/web/static/lib/datejs/globalization/te-IN.js
new file mode 100644
index 00000000000..94736b7a24e
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/te-IN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "te-IN",
+ englishName: "Telugu (India)",
+ nativeName: "తెలుగు (భారత దేశం)",
+
+ /* Day Name Strings */
+ dayNames: ["ఆదివారం", "సోమవారం", "మంగళవారం", "బుధవారం", "గురువారం", "శుక్రవారం", "శనివారం"],
+ abbreviatedDayNames: ["ఆది.", "సోమ.", "మంగళ.", "బుధ.", "గురు.", "శుక్ర.", "శని."],
+ shortestDayNames: ["ఆ", "స", "మ", "బ", "గ", "శ", "శ"],
+ firstLetterDayNames: ["ఆ", "స", "మ", "బ", "గ", "శ", "శ"],
+
+ /* Month Name Strings */
+ monthNames: ["జనవరి", "ఫిబ్రవరి", "మార్చి", "ఏప్రిల్", "మే", "జూన్", "జూలై", "ఆగస్టు", "సెప్టెంబర్", "అక్టోబర్", "నవంబర్", "డిసెంబర్"],
+ abbreviatedMonthNames: ["జనవరి", "ఫిబ్రవరి", "మార్చి", "ఏప్రిల్", "మే", "జూన్", "జూలై", "ఆగస్టు", "సెప్టెంబర్", "అక్టోబర్", "నవంబర్", "డిసెంబర్"],
+
+ /* AM/PM Designators */
+ amDesignator: "పూర్వాహ్న",
+ pmDesignator: "అపరాహ్న",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^జనవరి/i,
+ feb: /^ఫిబ్రవరి/i,
+ mar: /^మార్చి/i,
+ apr: /^ఏప్రిల్/i,
+ may: /^మే/i,
+ jun: /^జూన్/i,
+ jul: /^జూలై/i,
+ aug: /^ఆగస్టు/i,
+ sep: /^సెప్టెంబర్/i,
+ oct: /^అక్టోబర్/i,
+ nov: /^నవంబర్/i,
+ dec: /^డిసెంబర్/i,
+
+ sun: /^ఆ(ది(.(వారం)?)?)?/i,
+ mon: /^స(ోమ(.(వారం)?)?)?/i,
+ tue: /^మ(ంగళ(.(వారం)?)?)?/i,
+ wed: /^బ(ుధ(.(వారం)?)?)?/i,
+ thu: /^గ(ురు(.(వారం)?)?)?/i,
+ fri: /^శ(ుక్ర(.(వారం)?)?)?/i,
+ sat: /^శ(ని(.(వారం)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/th-TH.js b/addons/web/static/lib/datejs/globalization/th-TH.js
new file mode 100644
index 00000000000..f792de21ebb
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/th-TH.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "th-TH",
+ englishName: "Thai (Thailand)",
+ nativeName: "ไทย (ไทย)",
+
+ /* Day Name Strings */
+ dayNames: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัสบดี", "ศุกร์", "เสาร์"],
+ abbreviatedDayNames: ["อา.", "จ.", "อ.", "พ.", "พฤ.", "ศ.", "ส."],
+ shortestDayNames: ["อ", "จ", "อ", "พ", "พ", "ศ", "ส"],
+ firstLetterDayNames: ["อ", "จ", "อ", "พ", "พ", "ศ", "ส"],
+
+ /* Month Name Strings */
+ monthNames: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"],
+ abbreviatedMonthNames: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2572,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ม(.(กราค)?)?/i,
+ feb: /^ก(.(ุมภาพันธ์)?)?/i,
+ mar: /^มี(.(นาคม)?)?/i,
+ apr: /^เม(.(ษายน)?)?/i,
+ may: /^พ(.(ฤษภาคม)?)?/i,
+ jun: /^มิ(.(ถุนายน)?)?/i,
+ jul: /^ก(.(รฎาคม)?)?/i,
+ aug: /^ส(.(ิงหาคม)?)?/i,
+ sep: /^ก(.(ันยายน)?)?/i,
+ oct: /^ต(.(ุลาคม)?)?/i,
+ nov: /^พ(.(ฤศจิกายน)?)?/i,
+ dec: /^ธ(.(ันวาคม)?)?/i,
+
+ sun: /^อ(า(.(ทิตย์)?)?)?/i,
+ mon: /^จ((.(ันทร์)?)?)?/i,
+ tue: /^อ((.(ังคาร)?)?)?/i,
+ wed: /^พ((.(ุธ)?)?)?/i,
+ thu: /^พ(ฤ(.(หัสบดี)?)?)?/i,
+ fri: /^ศ((.(ุกร์)?)?)?/i,
+ sat: /^ส((.(สาร์)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/tn-ZA.js b/addons/web/static/lib/datejs/globalization/tn-ZA.js
new file mode 100644
index 00000000000..9c243d7cca7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/tn-ZA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "tn-ZA",
+ englishName: "Tswana (South Africa)",
+ nativeName: "Setswana (Aforika Borwa)",
+
+ /* Day Name Strings */
+ dayNames: ["Latshipi", "Mosupologo", "Labobedi", "Laboraro", "Labone", "Labotlhano", "Lamatlhatso"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Ferikgong", "Tlhakole", "Mopitloe", "Moranang", "Motsheganong", "Seetebosigo", "Phukwi", "Phatwe", "Lwetse", "Diphalane", "Ngwanatsele", "Sedimothole"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dd MMMM yyyy",
+ shortTime: "hh:mm:ss tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ferikgong/i,
+ feb: /^tlhakole/i,
+ mar: /^mopitloe/i,
+ apr: /^moranang/i,
+ may: /^motsheganong/i,
+ jun: /^seetebosigo/i,
+ jul: /^phukwi/i,
+ aug: /^phatwe/i,
+ sep: /^lwetse/i,
+ oct: /^diphalane/i,
+ nov: /^ngwanatsele/i,
+ dec: /^sedimothole/i,
+
+ sun: /^latshipi/i,
+ mon: /^mosupologo/i,
+ tue: /^labobedi/i,
+ wed: /^laboraro/i,
+ thu: /^labone/i,
+ fri: /^labotlhano/i,
+ sat: /^lamatlhatso/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/tr-TR.js b/addons/web/static/lib/datejs/globalization/tr-TR.js
new file mode 100644
index 00000000000..4018c2f24bd
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/tr-TR.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "tr-TR",
+ englishName: "Turkish (Turkey)",
+ nativeName: "Türkçe (Türkiye)",
+
+ /* Day Name Strings */
+ dayNames: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"],
+ abbreviatedDayNames: ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"],
+ shortestDayNames: ["Pz", "Pt", "Sa", "Ça", "Pe", "Cu", "Ct"],
+ firstLetterDayNames: ["P", "P", "S", "Ç", "P", "C", "C"],
+
+ /* Month Name Strings */
+ monthNames: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"],
+ abbreviatedMonthNames: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dd MMMM yyyy dddd",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy dddd HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^oca(k)?/i,
+ feb: /^şub(at)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^nis(an)?/i,
+ may: /^may(ıs)?/i,
+ jun: /^haz(iran)?/i,
+ jul: /^tem(muz)?/i,
+ aug: /^ağu(stos)?/i,
+ sep: /^eyl(ül)?/i,
+ oct: /^eki(m)?/i,
+ nov: /^kas(ım)?/i,
+ dec: /^ara(lık)?/i,
+
+ sun: /^pz(z(ar)?)?/i,
+ mon: /^pt(t(artesi)?)?/i,
+ tue: /^sa(l(ı)?)?/i,
+ wed: /^ça(r(şamba)?)?/i,
+ thu: /^pe(r(şembe)?)?/i,
+ fri: /^cu(m(a)?)?/i,
+ sat: /^ct(t(artesi)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/tt-RU.js b/addons/web/static/lib/datejs/globalization/tt-RU.js
new file mode 100644
index 00000000000..271338a1827
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/tt-RU.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "tt-RU",
+ englishName: "Tatar (Russia)",
+ nativeName: "Татар (Россия)",
+
+ /* Day Name Strings */
+ dayNames: ["Якшәмбе", "Дүшәмбе", "Сишәмбе", "Чәршәмбе", "Пәнҗешәмбе", "Җомга", "Шимбә"],
+ abbreviatedDayNames: ["Якш", "Дүш", "Сиш", "Чәрш", "Пәнҗ", "Җом", "Шим"],
+ shortestDayNames: ["Якш", "Дүш", "Сиш", "Чәрш", "Пәнҗ", "Җом", "Шим"],
+ firstLetterDayNames: ["Я", "Д", "С", "Ч", "П", "Җ", "Ш"],
+
+ /* Month Name Strings */
+ monthNames: ["Гыйнварь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
+ abbreviatedMonthNames: ["Гыйнв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^гыйнв(арь)?/i,
+ feb: /^фев(раль)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ель)?/i,
+ may: /^май/i,
+ jun: /^июн(ь)?/i,
+ jul: /^июл(ь)?/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сен(тябрь)?/i,
+ oct: /^окт(ябрь)?/i,
+ nov: /^ноя(брь)?/i,
+ dec: /^дек(абрь)?/i,
+
+ sun: /^якшәмбе/i,
+ mon: /^дүшәмбе/i,
+ tue: /^сишәмбе/i,
+ wed: /^чәршәмбе/i,
+ thu: /^пәнҗешәмбе/i,
+ fri: /^җомга/i,
+ sat: /^шимбә/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/uk-UA.js b/addons/web/static/lib/datejs/globalization/uk-UA.js
new file mode 100644
index 00000000000..246c121dcd7
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/uk-UA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "uk-UA",
+ englishName: "Ukrainian (Ukraine)",
+ nativeName: "україньска (Україна)",
+
+ /* Day Name Strings */
+ dayNames: ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"],
+ abbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ shortestDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ firstLetterDayNames: ["Н", "П", "В", "С", "Ч", "П", "С"],
+
+ /* Month Name Strings */
+ monthNames: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"],
+ abbreviatedMonthNames: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy' р.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy' р.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy' р.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^січ(ень)?/i,
+ feb: /^лют(ий)?/i,
+ mar: /^бер(езень)?/i,
+ apr: /^кві(тень)?/i,
+ may: /^тра(вень)?/i,
+ jun: /^чер(вень)?/i,
+ jul: /^лип(ень)?/i,
+ aug: /^сер(пень)?/i,
+ sep: /^вер(есень)?/i,
+ oct: /^жов(тень)?/i,
+ nov: /^лис(топад)?/i,
+ dec: /^гру(день)?/i,
+
+ sun: /^неділя/i,
+ mon: /^понеділок/i,
+ tue: /^вівторок/i,
+ wed: /^середа/i,
+ thu: /^четвер/i,
+ fri: /^п'ятниця/i,
+ sat: /^субота/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/ur-PK.js b/addons/web/static/lib/datejs/globalization/ur-PK.js
new file mode 100644
index 00000000000..6aa4662ccbb
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/ur-PK.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ur-PK",
+ englishName: "Urdu (Islamic Republic of Pakistan)",
+ nativeName: "اُردو (پاکستان)",
+
+ /* Day Name Strings */
+ dayNames: ["اتوار", "پير", "منگل", "بدھ", "جمعرات", "جمعه", "هفته"],
+ abbreviatedDayNames: ["اتوار", "پير", "منگل", "بدھ", "جمعرات", "جمعه", "هفته"],
+ shortestDayNames: ["ا", "پ", "م", "ب", "ج", "ج", "ه"],
+ firstLetterDayNames: ["ا", "پ", "م", "ب", "ج", "ج", "ه"],
+
+ /* Month Name Strings */
+ monthNames: ["جنورى", "فرورى", "مارچ", "اپريل", "مئ", "جون", "جولاٸ", "اگست", "ستمبر", "اکتوبر", "نومبر", "دسمبر"],
+ abbreviatedMonthNames: ["جنورى", "فرورى", "مارچ", "اپريل", "مئ", "جون", "جولاٸ", "اگست", "ستمبر", "اکتوبر", "نومبر", "دسمبر"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^جنورى/i,
+ feb: /^فرورى/i,
+ mar: /^مارچ/i,
+ apr: /^اپريل/i,
+ may: /^مئ/i,
+ jun: /^جون/i,
+ jul: /^جولاٸ/i,
+ aug: /^اگست/i,
+ sep: /^ستمبر/i,
+ oct: /^اکتوبر/i,
+ nov: /^نومبر/i,
+ dec: /^دسمبر/i,
+
+ sun: /^ا(1)?/i,
+ mon: /^پ(1)?/i,
+ tue: /^م(1)?/i,
+ wed: /^ب(1)?/i,
+ thu: /^ج(1)?/i,
+ fri: /^ج(1)?/i,
+ sat: /^ه(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/uz-Cyrl-UZ.js b/addons/web/static/lib/datejs/globalization/uz-Cyrl-UZ.js
new file mode 100644
index 00000000000..a2eafa121cc
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/uz-Cyrl-UZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "uz-Cyrl-UZ",
+ englishName: "Uzbek (Cyrillic, Uzbekistan)",
+ nativeName: "Ўзбек (Ўзбекистон)",
+
+ /* Day Name Strings */
+ dayNames: ["якшанба", "душанба", "сешанба", "чоршанба", "пайшанба", "жума", "шанба"],
+ abbreviatedDayNames: ["якш", "дш", "сш", "чш", "пш", "ж", "ш"],
+ shortestDayNames: ["якш", "дш", "сш", "чш", "пш", "ж", "ш"],
+ firstLetterDayNames: ["я", "д", "с", "ч", "п", "ж", "ш"],
+
+ /* Month Name Strings */
+ monthNames: ["Январ", "Феврал", "Март", "Апрел", "Май", "Июн", "Июл", "Август", "Сентябр", "Октябр", "Ноябр", "Декабр"],
+ abbreviatedMonthNames: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "yyyy 'йил' d-MMMM",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "yyyy 'йил' d-MMMM HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d-MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^янв(ар)?/i,
+ feb: /^фев(рал)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ел)?/i,
+ may: /^май/i,
+ jun: /^июн/i,
+ jul: /^июл/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сен(тябр)?/i,
+ oct: /^окт(ябр)?/i,
+ nov: /^ноя(бр)?/i,
+ dec: /^дек(абр)?/i,
+
+ sun: /^якшанба/i,
+ mon: /^душанба/i,
+ tue: /^сешанба/i,
+ wed: /^чоршанба/i,
+ thu: /^пайшанба/i,
+ fri: /^жума/i,
+ sat: /^шанба/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/uz-Latn-UZ.js b/addons/web/static/lib/datejs/globalization/uz-Latn-UZ.js
new file mode 100644
index 00000000000..6a9a5af533c
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/uz-Latn-UZ.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "uz-Latn-UZ",
+ englishName: "Uzbek (Latin, Uzbekistan)",
+ nativeName: "U'zbek (U'zbekiston Respublikasi)",
+
+ /* Day Name Strings */
+ dayNames: ["yakshanba", "dushanba", "seshanba", "chorshanba", "payshanba", "juma", "shanba"],
+ abbreviatedDayNames: ["yak.", "dsh.", "sesh.", "chr.", "psh.", "jm.", "sh."],
+ shortestDayNames: ["yak", "dsh", "sesh", "chr", "psh", "jm", "sh"],
+ firstLetterDayNames: ["y", "d", "s", "c", "p", "j", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["yanvar", "fevral", "mart", "aprel", "may", "iyun", "iyul", "avgust", "sentyabr", "oktyabr", "noyabr", "dekabr"],
+ abbreviatedMonthNames: ["yanvar", "fevral", "mart", "aprel", "may", "iyun", "iyul", "avgust", "sentyabr", "oktyabr", "noyabr", "dekabr"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM yyyy",
+ longDate: "yyyy 'yil' d-MMMM",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "yyyy 'yil' d-MMMM HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d-MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^yanvar/i,
+ feb: /^fevral/i,
+ mar: /^mart/i,
+ apr: /^aprel/i,
+ may: /^may/i,
+ jun: /^iyun/i,
+ jul: /^iyul/i,
+ aug: /^avgust/i,
+ sep: /^sentyabr/i,
+ oct: /^oktyabr/i,
+ nov: /^noyabr/i,
+ dec: /^dekabr/i,
+
+ sun: /^yak((.(shanba)?)?)?/i,
+ mon: /^dsh((.(hanba)?)?)?/i,
+ tue: /^sesh((.(anba)?)?)?/i,
+ wed: /^chr((.(rshanba)?)?)?/i,
+ thu: /^psh((.(shanba)?)?)?/i,
+ fri: /^jm((.(ma)?)?)?/i,
+ sat: /^sh((.(anba)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/vi-VN.js b/addons/web/static/lib/datejs/globalization/vi-VN.js
new file mode 100644
index 00000000000..271480360ee
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/vi-VN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "vi-VN",
+ englishName: "Vietnamese (Vietnam)",
+ nativeName: "Tiếng Việt (Việt Nam)",
+
+ /* Day Name Strings */
+ dayNames: ["Chủ Nhật", "Thứ Hai", "Thứ Ba", "Thứ Tư", "Thứ Năm", "Thứ Sáu", "Thứ Bảy"],
+ abbreviatedDayNames: ["CN", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy"],
+ shortestDayNames: ["C", "H", "B", "T", "N", "S", "B"],
+ firstLetterDayNames: ["C", "H", "B", "T", "N", "S", "B"],
+
+ /* Month Name Strings */
+ monthNames: ["Tháng Giêng", "Tháng Hai", "Tháng Ba", "Tháng Tư", "Tháng Năm", "Tháng Sáu", "Tháng Bảy", "Tháng Tám", "Tháng Chín", "Tháng Mười", "Tháng Mười Một", "Tháng Mười Hai"],
+ abbreviatedMonthNames: ["Thg1", "Thg2", "Thg3", "Thg4", "Thg5", "Thg6", "Thg7", "Thg8", "Thg9", "Thg10", "Thg11", "Thg12"],
+
+ /* AM/PM Designators */
+ amDesignator: "SA",
+ pmDesignator: "CH",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^tháng giêng/i,
+ feb: /^tháng hai/i,
+ mar: /^tháng ba/i,
+ apr: /^tháng tư/i,
+ may: /^tháng năm/i,
+ jun: /^tháng sáu/i,
+ jul: /^tháng bảy/i,
+ aug: /^tháng tám/i,
+ sep: /^tháng chín/i,
+ oct: /^tháng mười/i,
+ nov: /^tháng mười một/i,
+ dec: /^tháng mười hai/i,
+
+ sun: /^c(n(ủ nhật)?)?/i,
+ mon: /^h(ai(́ hai)?)?/i,
+ tue: /^b(a(ứ ba)?)?/i,
+ wed: /^t(ư(ứ tư)?)?/i,
+ thu: /^n(ăm(́ năm)?)?/i,
+ fri: /^s(áu( sáu)?)?/i,
+ sat: /^b(ảy( bảy)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/xh-ZA.js b/addons/web/static/lib/datejs/globalization/xh-ZA.js
new file mode 100644
index 00000000000..dfcdb3b1338
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/xh-ZA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "xh-ZA",
+ englishName: "Xhosa (South Africa)",
+ nativeName: "isiXhosa (uMzantsi Afrika)",
+
+ /* Day Name Strings */
+ dayNames: ["iCawa", "uMvulo", "uLwesibini", "uLwesithathu", "uLwesine", "uLwesihlanu", "uMgqibelo"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["eyoMqungu", "eyoMdumba", "eyoKwindla", "Tshazimpuzi", "Canzibe", "eyeSilimela", "eyeKhala", "eyeThupha", "eyoMsintsi", "eyeDwara", "eyeNkanga", "eyoMnga"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dd MMMM yyyy",
+ shortTime: "hh:mm:ss tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^eyomqungu/i,
+ feb: /^eyomdumba/i,
+ mar: /^eyokwindla/i,
+ apr: /^tshazimpuzi/i,
+ may: /^canzibe/i,
+ jun: /^eyesilimela/i,
+ jul: /^eyekhala/i,
+ aug: /^eyethupha/i,
+ sep: /^eyomsintsi/i,
+ oct: /^eyedwara/i,
+ nov: /^eyenkanga/i,
+ dec: /^eyomnga/i,
+
+ sun: /^icawa/i,
+ mon: /^umvulo/i,
+ tue: /^ulwesibini/i,
+ wed: /^ulwesithathu/i,
+ thu: /^ulwesine/i,
+ fri: /^ulwesihlanu/i,
+ sat: /^umgqibelo/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/zh-CN.js b/addons/web/static/lib/datejs/globalization/zh-CN.js
new file mode 100644
index 00000000000..8dac6692b46
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/zh-CN.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-CN",
+ englishName: "Chinese (People's Republic of China)",
+ nativeName: "中文(中华人民共和国)",
+
+ /* Day Name Strings */
+ dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ abbreviatedDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+
+ /* Month Name Strings */
+ monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+
+ /* AM/PM Designators */
+ amDesignator: "上午",
+ pmDesignator: "下午",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/M/d",
+ longDate: "yyyy'年'M'月'd'日'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy'年'M'月'd'日' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'月'd'日'",
+ yearMonth: "yyyy'年'M'月'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^一月/i,
+ feb: /^二月/i,
+ mar: /^三月/i,
+ apr: /^四月/i,
+ may: /^五月/i,
+ jun: /^六月/i,
+ jul: /^七月/i,
+ aug: /^八月/i,
+ sep: /^九月/i,
+ oct: /^十月/i,
+ nov: /^十一月/i,
+ dec: /^十二月/i,
+
+ sun: /^星期日/i,
+ mon: /^星期一/i,
+ tue: /^星期二/i,
+ wed: /^星期三/i,
+ thu: /^星期四/i,
+ fri: /^星期五/i,
+ sat: /^星期六/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/zh-HK.js b/addons/web/static/lib/datejs/globalization/zh-HK.js
new file mode 100644
index 00000000000..989e988492b
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/zh-HK.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-HK",
+ englishName: "Chinese (Hong Kong S.A.R.)",
+ nativeName: "中文(香港特别行政區)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d MMMM, yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, d MMMM, yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/zh-MO.js b/addons/web/static/lib/datejs/globalization/zh-MO.js
new file mode 100644
index 00000000000..390d8340c79
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/zh-MO.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-MO",
+ englishName: "Chinese (Macao S.A.R.)",
+ nativeName: "中文(澳門特别行政區)",
+
+ /* Day Name Strings */
+ dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ abbreviatedDayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+
+ /* Month Name Strings */
+ monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d MMMM, yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, d MMMM, yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^一月/i,
+ feb: /^二月/i,
+ mar: /^三月/i,
+ apr: /^四月/i,
+ may: /^五月/i,
+ jun: /^六月/i,
+ jul: /^七月/i,
+ aug: /^八月/i,
+ sep: /^九月/i,
+ oct: /^十月/i,
+ nov: /^十一月/i,
+ dec: /^十二月/i,
+
+ sun: /^星期日/i,
+ mon: /^星期一/i,
+ tue: /^星期二/i,
+ wed: /^星期三/i,
+ thu: /^星期四/i,
+ fri: /^星期五/i,
+ sat: /^星期六/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/zh-SG.js b/addons/web/static/lib/datejs/globalization/zh-SG.js
new file mode 100644
index 00000000000..e6a3ff9c3fd
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/zh-SG.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-SG",
+ englishName: "Chinese (Singapore)",
+ nativeName: "中文(新加坡)",
+
+ /* Day Name Strings */
+ dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ abbreviatedDayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+
+ /* Month Name Strings */
+ monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d MMMM, yyyy",
+ shortTime: "tt h:mm",
+ longTime: "tt h:mm:ss",
+ fullDateTime: "dddd, d MMMM, yyyy tt h:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^一月/i,
+ feb: /^二月/i,
+ mar: /^三月/i,
+ apr: /^四月/i,
+ may: /^五月/i,
+ jun: /^六月/i,
+ jul: /^七月/i,
+ aug: /^八月/i,
+ sep: /^九月/i,
+ oct: /^十月/i,
+ nov: /^十一月/i,
+ dec: /^十二月/i,
+
+ sun: /^星期日/i,
+ mon: /^星期一/i,
+ tue: /^星期二/i,
+ wed: /^星期三/i,
+ thu: /^星期四/i,
+ fri: /^星期五/i,
+ sat: /^星期六/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/zh-TW.js b/addons/web/static/lib/datejs/globalization/zh-TW.js
new file mode 100644
index 00000000000..3e54de90cc0
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/zh-TW.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-TW",
+ englishName: "Chinese (Taiwan)",
+ nativeName: "中文(台灣)",
+
+ /* Day Name Strings */
+ dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ abbreviatedDayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+
+ /* Month Name Strings */
+ monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+
+ /* AM/PM Designators */
+ amDesignator: "上午",
+ pmDesignator: "下午",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/M/d",
+ longDate: "yyyy'年'M'月'd'日'",
+ shortTime: "tt hh:mm",
+ longTime: "tt hh:mm:ss",
+ fullDateTime: "yyyy'年'M'月'd'日' tt hh:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'月'd'日'",
+ yearMonth: "yyyy'年'M'月'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^一月/i,
+ feb: /^二月/i,
+ mar: /^三月/i,
+ apr: /^四月/i,
+ may: /^五月/i,
+ jun: /^六月/i,
+ jul: /^七月/i,
+ aug: /^八月/i,
+ sep: /^九月/i,
+ oct: /^十月/i,
+ nov: /^十一月/i,
+ dec: /^十二月/i,
+
+ sun: /^星期日/i,
+ mon: /^星期一/i,
+ tue: /^星期二/i,
+ wed: /^星期三/i,
+ thu: /^星期四/i,
+ fri: /^星期五/i,
+ sat: /^星期六/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/globalization/zu-ZA.js b/addons/web/static/lib/datejs/globalization/zu-ZA.js
new file mode 100644
index 00000000000..61c5ca0e09c
--- /dev/null
+++ b/addons/web/static/lib/datejs/globalization/zu-ZA.js
@@ -0,0 +1,195 @@
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zu-ZA",
+ englishName: "Zulu (South Africa)",
+ nativeName: "isiZulu (iNingizimu Afrika)",
+
+ /* Day Name Strings */
+ dayNames: ["iSonto", "uMsombuluko", "uLwesibili", "uLwesithathu", "uLwesine", "uLwesihlanu", "uMgqibelo"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["uJanuwari", "uFebuwari", "uMashi", "uAprhili", "uMeyi", "uJuni", "uJulayi", "uAgaste", "uSepthemba", "uOkthoba", "uNovemba", "uDisemba"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dd MMMM yyyy",
+ shortTime: "hh:mm:ss tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ujanuwari/i,
+ feb: /^ufebuwari/i,
+ mar: /^umashi/i,
+ apr: /^uaprhili/i,
+ may: /^umeyi/i,
+ jun: /^ujuni/i,
+ jul: /^ujulayi/i,
+ aug: /^uagaste/i,
+ sep: /^usepthemba/i,
+ oct: /^uokthoba/i,
+ nov: /^unovemba/i,
+ dec: /^udisemba/i,
+
+ sun: /^isonto/i,
+ mon: /^umsombuluko/i,
+ tue: /^ulwesibili/i,
+ wed: /^ulwesithathu/i,
+ thu: /^ulwesine/i,
+ fri: /^ulwesihlanu/i,
+ sat: /^umgqibelo/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */ \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/parser.js b/addons/web/static/lib/datejs/parser.js
new file mode 100644
index 00000000000..4a9f16da4e4
--- /dev/null
+++ b/addons/web/static/lib/datejs/parser.js
@@ -0,0 +1,1116 @@
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+(function () {
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function (s) { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s);
+ // Removed .strip()
+ // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip();
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ //
+ // Atomic Operators
+ //
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, r = null;
+ return function (s) {
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length == 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length == 1);
+
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i != j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ return function () {
+ var args = null, rx = [];
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ for (var i = 0, px = args.shift() ; i < px.length ; i++) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+
+(function () {
+ var $D = Date, $P = $D.prototype;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ $D.Grammar = {};
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length == 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < $D.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ x = (x instanceof Array) ? x : [ x ];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ var now = new Date();
+
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+
+ if (this.meridian && this.hour) {
+ if (this.meridian == "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian == "a" && this.hour == 12) {
+ this.hour = 0;
+ }
+ }
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second);
+
+ if (this.timezone) {
+ r.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ r.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return r;
+ },
+ finish: function (x) {
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] == "function") {
+ x[i].call(this);
+ }
+ }
+
+ var today = $D.today();
+
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else if (this.now) {
+ today = new Date();
+ }
+
+ var expression = !!(this.days && this.days !== null || this.orient || this.operator);
+
+ var gap, mod, orient;
+ orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1);
+
+ if(!this.now && "hour minute second".indexOf(this.unit) != -1) {
+ today.setTimeToNow();
+ }
+
+ if (this.month || this.month === 0) {
+ if ("year day hour minute second".indexOf(this.unit) != -1) {
+ this.value = this.month + 1;
+ this.month = null;
+ expression = true;
+ }
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ var temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (!this.month) {
+ this.month = temp.getMonth();
+ }
+ this.year = temp.getFullYear();
+ }
+
+ if (expression && this.weekday && this.unit != "month") {
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ mod = 7;
+ this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
+ }
+
+ if (this.month && this.unit == "day" && this.operator) {
+ this.value = (this.month + 1);
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit == "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit != "year") {
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ mod = 12;
+ this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
+ this.month = null;
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+
+ if (this.meridian && this.hour) {
+ if (this.meridian == "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian == "a" && this.hour == 12) {
+ this.hour = 0;
+ }
+ }
+
+ if (this.weekday && !this.day && !this.days) {
+ var temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ return (expression) ? today.add(this) : today.set(this);
+ }
+ };
+
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = $D.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken($D.CultureInfo.regexPatterns[key]);
+ };
+
+ // hour, minute, second, meridian, timezone
+ g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour));
+ g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour));
+ g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour));
+ g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour));
+ g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute));
+ g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute));
+ g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second));
+ g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second));
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ // _.min(1, _.set([ g.H, g.m, g.s ], g._t));
+ g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian));
+ g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian));
+ g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
+ g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
+
+ g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone));
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+
+ // days, months, years
+ g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),
+ _.optional(g.ctoken2("ordinalSuffix"))), t.day));
+ g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),
+ _.optional(g.ctoken2("ordinalSuffix"))), t.day));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+ g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month));
+ g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month));
+ g.MMM = g.MMMM = _.cache(_.process(
+ g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year));
+ g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year));
+ g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year));
+ g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year));
+
+ // rolling these up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ // pre-loaded rules for different date part order preferences
+ _fn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ g.mdy = _fn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _fn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _fn(g.ddd, g.day, g.month, g.year);
+ g.date = function (s) {
+ return ((g[$D.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(
+ _.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ var _F = {
+ //"M/d/yyyy": function (s) {
+ // var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/);
+ // if (m!=null) {
+ // var r = [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ];
+ // r = t.finishExact.call(this,r);
+ // return [ r, "" ];
+ // } else {
+ // throw new Date.Parsing.Exception(s);
+ // }
+ //}
+ //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; }
+ };
+ var _get = function (f) {
+ return _F[f] = (_F[f] || g.format(f)[0]);
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+
+ $D._parse = $D.parse;
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+ <pre><code>
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+ </code></pre>
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parse = function (s) {
+ var r = null;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s;
+ }
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+ return ((r[1].length === 0) ? r[0] : null);
+ };
+
+ $D.getParseFunction = function (fx) {
+ var fn = $D.Grammar.formats(fx);
+ return function (s) {
+ var r = null;
+ try {
+ r = fn.call({}, s);
+ } catch (e) {
+ return null;
+ }
+ return ((r[1].length === 0) ? r[0] : null);
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+ <pre><code>
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+ </code></pre>
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}()); \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/sugarpak.js b/addons/web/static/lib/datejs/sugarpak.js
new file mode 100644
index 00000000000..7438a49f35c
--- /dev/null
+++ b/addons/web/static/lib/datejs/sugarpak.js
@@ -0,0 +1,475 @@
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+/**
+ **************************************************************
+ ** SugarPak - Domain Specific Language - Syntactical Sugar **
+ **************************************************************
+ */
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "day";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+ <pre><code>
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+ <pre><code>
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+ </code></pre>
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+ <pre><code>
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+ <pre><code>
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+ <pre><code>
+ Date.today().is().weekday(); // true|false
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+ <pre><code>
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+ <pre><code>
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+ </code></pre>
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+ <pre><code>
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+ </code></pre>
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {};
+ c[this._dateElement] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files. See /trunk/src/globalization/.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+ <pre><code>
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+ </code></pre>
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+ <pre><code>
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+ </code></pre>
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() == n;
+ }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && $D.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+ for (var i = 0; i < dx.length; i++) {
+ // Create constant static Day Name variables. Example: Date.MONDAY or Date.MON
+ $D[dx[i].toUpperCase()] = $D[dx[i].toUpperCase().substring(0, 3)] = i;
+
+ // Create Day Name functions. Example: Date.monday() or Date.mon()
+ $D[dx[i]] = $D[dx[i].substring(0, 3)] = sdf(i);
+
+ // Create Day Name instance functions. Example: Date.today().next().monday()
+ $P[dx[i]] = $P[dx[i].substring(0, 3)] = df(i);
+ }
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var mf = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var smf = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ for (var j = 0; j < mx.length; j++) {
+ // Create constant static Month Name variables. Example: Date.MARCH or Date.MAR
+ $D[mx[j].toUpperCase()] = $D[mx[j].toUpperCase().substring(0, 3)] = j;
+
+ // Create Month Name functions. Example: Date.march() or Date.mar()
+ $D[mx[j]] = $D[mx[j].substring(0, 3)] = smf(j);
+
+ // Create Month Name instance functions. Example: Date.today().next().march()
+ $P[mx[j]] = $P[mx[j].substring(0, 3)] = mf(j);
+ }
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] != o2[v]) {
+ return false;
+ }
+ if (k == v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) != "s") {
+ j += "s";
+ }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de);
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}()); \ No newline at end of file
diff --git a/addons/web/static/lib/datejs/time.js b/addons/web/static/lib/datejs/time.js
new file mode 100644
index 00000000000..c3ac11f224d
--- /dev/null
+++ b/addons/web/static/lib/datejs/time.js
@@ -0,0 +1,269 @@
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+/*
+ * TimeSpan(milliseconds);
+ * TimeSpan(days, hours, minutes, seconds);
+ * TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ var attrs = "days hours minutes seconds milliseconds".split(/\s+/);
+
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ TimeSpan.prototype[$a] = 0;
+ TimeSpan.prototype["get" + $b] = gFn($a);
+ TimeSpan.prototype["set" + $b] = sFn($a);
+ }
+
+ if (arguments.length == 4) {
+ this.setDays(days);
+ this.setHours(hours);
+ this.setMinutes(minutes);
+ this.setSeconds(seconds);
+ } else if (arguments.length == 5) {
+ this.setDays(days);
+ this.setHours(hours);
+ this.setMinutes(minutes);
+ this.setSeconds(seconds);
+ this.setMilliseconds(milliseconds);
+ } else if (arguments.length == 1 && typeof days == "number") {
+ var orient = (days < 0) ? -1 : +1;
+ this.setMilliseconds(Math.abs(days));
+
+ this.setDays(Math.floor(this.getMilliseconds() / 86400000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 86400000);
+
+ this.setHours(Math.floor(this.getMilliseconds() / 3600000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 3600000);
+
+ this.setMinutes(Math.floor(this.getMilliseconds() / 60000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 60000);
+
+ this.setSeconds(Math.floor(this.getMilliseconds() / 1000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 1000);
+
+ this.setMilliseconds(this.getMilliseconds() * orient);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) + (this.getHours() * 3600000) + (this.getMinutes() * 60000) + (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+};
+
+/**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+};
+
+/*
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ var attrs = "years months days hours minutes seconds milliseconds".split(/\s+/);
+
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ TimePeriod.prototype[$a] = 0;
+ TimePeriod.prototype["get" + $b] = gFn($a);
+ TimePeriod.prototype["set" + $b] = sFn($a);
+ }
+
+ if (arguments.length == 7) {
+ this.years = years;
+ this.months = months;
+ this.setDays(days);
+ this.setHours(hours);
+ this.setMinutes(minutes);
+ this.setSeconds(seconds);
+ this.setMilliseconds(milliseconds);
+ } else if (arguments.length == 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ // startDate and endDate as arguments
+
+ var d1 = years.clone();
+ var d2 = months.clone();
+
+ var temp = d1.clone();
+ var orient = (d1 > d2) ? -1 : +1;
+
+ this.years = d2.getFullYear() - d1.getFullYear();
+ temp.addYears(this.years);
+
+ if (orient == +1) {
+ if (temp > d2) {
+ if (this.years !== 0) {
+ this.years--;
+ }
+ }
+ } else {
+ if (temp < d2) {
+ if (this.years !== 0) {
+ this.years++;
+ }
+ }
+ }
+
+ d1.addYears(this.years);
+
+ if (orient == +1) {
+ while (d1 < d2 && d1.clone().addDays(Date.getDaysInMonth(d1.getYear(), d1.getMonth()) ) < d2) {
+ d1.addMonths(1);
+ this.months++;
+ }
+ }
+ else {
+ while (d1 > d2 && d1.clone().addDays(-d1.getDaysInMonth()) > d2) {
+ d1.addMonths(-1);
+ this.months--;
+ }
+ }
+
+ var diff = d2 - d1;
+
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.setDays(ts.getDays());
+ this.setHours(ts.getHours());
+ this.setMinutes(ts.getMinutes());
+ this.setSeconds(ts.getSeconds());
+ this.setMilliseconds(ts.getMilliseconds());
+ }
+ }
+ return this;
+}; \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js b/addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js
new file mode 100644
index 00000000000..f251123acd7
--- /dev/null
+++ b/addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js
@@ -0,0 +1,1137 @@
+/*!
+ * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
+ * http://benalman.com/projects/jquery-bbq-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Script: jQuery BBQ: Back Button & Query Library
+//
+// *Version: 1.2.1, Last updated: 2/17/2010*
+//
+// Project Home - http://benalman.com/projects/jquery-bbq-plugin/
+// GitHub - http://github.com/cowboy/jquery-bbq/
+// Source - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js
+// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (4.0kb)
+//
+// About: License
+//
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+//
+// About: Examples
+//
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+//
+// Basic AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-basic/
+// Advanced AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/
+// jQuery UI Tabs - http://benalman.com/code/projects/jquery-bbq/examples/fragment-jquery-ui-tabs/
+// Deparam - http://benalman.com/code/projects/jquery-bbq/examples/deparam/
+//
+// About: Support and Testing
+//
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+//
+// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4,
+// Chrome 4-5, Opera 9.6-10.1.
+// Unit Tests - http://benalman.com/code/projects/jquery-bbq/unit/
+//
+// About: Release History
+//
+// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from
+// <jQuery hashchange event> in BBQ, which was the main reason for the
+// previous release!
+// 1.2 - (2/16/2010) Integrated <jQuery hashchange event> v1.2, which fixes a
+// Safari bug, the event can now be bound before DOM ready, and IE6/7
+// page should no longer scroll when the event is first bound. Also
+// added the <jQuery.param.fragment.noEscape> method, and reworked the
+// <hashchange event (BBQ)> internal "add" method to be compatible with
+// changes made to the jQuery 1.4.2 special events API.
+// 1.1.1 - (1/22/2010) Integrated <jQuery hashchange event> v1.1, which fixes an
+// obscure IE8 EmulateIE7 meta tag compatibility mode bug.
+// 1.1 - (1/9/2010) Broke out the jQuery BBQ event.special <hashchange event>
+// functionality into a separate plugin for users who want just the
+// basic event & back button support, without all the extra awesomeness
+// that BBQ provides. This plugin will be included as part of jQuery BBQ,
+// but also be available separately. See <jQuery hashchange event>
+// plugin for more information. Also added the <jQuery.bbq.removeState>
+// method and added additional <jQuery.deparam> examples.
+// 1.0.3 - (12/2/2009) Fixed an issue in IE 6 where location.search and
+// location.hash would report incorrectly if the hash contained the ?
+// character. Also <jQuery.param.querystring> and <jQuery.param.fragment>
+// will no longer parse params out of a URL that doesn't contain ? or #,
+// respectively.
+// 1.0.2 - (10/10/2009) Fixed an issue in IE 6/7 where the hidden IFRAME caused
+// a "This page contains both secure and nonsecure items." warning when
+// used on an https:// page.
+// 1.0.1 - (10/7/2009) Fixed an issue in IE 8. Since both "IE7" and "IE8
+// Compatibility View" modes erroneously report that the browser
+// supports the native window.onhashchange event, a slightly more
+// robust test needed to be added.
+// 1.0 - (10/2/2009) Initial release
+
+(function($,window){
+ '$:nomunge'; // Used by YUI compressor.
+
+ // Some convenient shortcuts.
+ var undefined,
+ aps = Array.prototype.slice,
+ decode = decodeURIComponent,
+
+ // Method / object references.
+ jq_param = $.param,
+ jq_param_fragment,
+ jq_deparam,
+ jq_deparam_fragment,
+ jq_bbq = $.bbq = $.bbq || {},
+ jq_bbq_pushState,
+ jq_bbq_getState,
+ jq_elemUrlAttr,
+ jq_event_special = $.event.special,
+
+ // Reused strings.
+ str_hashchange = 'hashchange',
+ str_querystring = 'querystring',
+ str_fragment = 'fragment',
+ str_elemUrlAttr = 'elemUrlAttr',
+ str_location = 'location',
+ str_href = 'href',
+ str_src = 'src',
+
+ // Reused RegExp.
+ re_trim_querystring = /^.*\?|#.*$/g,
+ re_trim_fragment = /^.*\#/,
+ re_no_escape,
+
+ // Used by jQuery.elemUrlAttr.
+ elemUrlAttr_cache = {};
+
+ // A few commonly used bits, broken out to help reduce minified file size.
+
+ function is_string( arg ) {
+ return typeof arg === 'string';
+ };
+
+ // Why write the same function twice? Let's curry! Mmmm, curry..
+
+ function curry( func ) {
+ var args = aps.call( arguments, 1 );
+
+ return function() {
+ return func.apply( this, args.concat( aps.call( arguments ) ) );
+ };
+ };
+
+ // Get location.hash (or what you'd expect location.hash to be) sans any
+ // leading #. Thanks for making this necessary, Firefox!
+ function get_fragment( url ) {
+ return url.replace( /^[^#]*#?(.*)$/, '$1' );
+ };
+
+ // Get location.search (or what you'd expect location.search to be) sans any
+ // leading #. Thanks for making this necessary, IE6!
+ function get_querystring( url ) {
+ return url.replace( /(?:^[^?#]*\?([^#]*).*$)?.*/, '$1' );
+ };
+
+ // Section: Param (to string)
+ //
+ // Method: jQuery.param.querystring
+ //
+ // Retrieve the query string from a URL or if no arguments are passed, the
+ // current window.location.
+ //
+ // Usage:
+ //
+ // > jQuery.param.querystring( [ url ] );
+ //
+ // Arguments:
+ //
+ // url - (String) A URL containing query string params to be parsed. If url
+ // is not passed, the current window.location is used.
+ //
+ // Returns:
+ //
+ // (String) The parsed query string, with any leading "?" removed.
+ //
+
+ // Method: jQuery.param.querystring (build url)
+ //
+ // Merge a URL, with or without pre-existing query string params, plus any
+ // object, params string or URL containing query string params into a new URL.
+ //
+ // Usage:
+ //
+ // > jQuery.param.querystring( url, params [, merge_mode ] );
+ //
+ // Arguments:
+ //
+ // url - (String) A valid URL for params to be merged into. This URL may
+ // contain a query string and/or fragment (hash).
+ // params - (String) A params string or URL containing query string params to
+ // be merged into url.
+ // params - (Object) A params object to be merged into url.
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
+ // specified, and is as-follows:
+ //
+ // * 0: params in the params argument will override any query string
+ // params in url.
+ // * 1: any query string params in url will override params in the params
+ // argument.
+ // * 2: params argument will completely replace any query string in url.
+ //
+ // Returns:
+ //
+ // (String) Either a params string with urlencoded data or a URL with a
+ // urlencoded query string in the format 'a=b&c=d&e=f'.
+
+ // Method: jQuery.param.fragment
+ //
+ // Retrieve the fragment (hash) from a URL or if no arguments are passed, the
+ // current window.location.
+ //
+ // Usage:
+ //
+ // > jQuery.param.fragment( [ url ] );
+ //
+ // Arguments:
+ //
+ // url - (String) A URL containing fragment (hash) params to be parsed. If
+ // url is not passed, the current window.location is used.
+ //
+ // Returns:
+ //
+ // (String) The parsed fragment (hash) string, with any leading "#" removed.
+
+ // Method: jQuery.param.fragment (build url)
+ //
+ // Merge a URL, with or without pre-existing fragment (hash) params, plus any
+ // object, params string or URL containing fragment (hash) params into a new
+ // URL.
+ //
+ // Usage:
+ //
+ // > jQuery.param.fragment( url, params [, merge_mode ] );
+ //
+ // Arguments:
+ //
+ // url - (String) A valid URL for params to be merged into. This URL may
+ // contain a query string and/or fragment (hash).
+ // params - (String) A params string or URL containing fragment (hash) params
+ // to be merged into url.
+ // params - (Object) A params object to be merged into url.
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
+ // specified, and is as-follows:
+ //
+ // * 0: params in the params argument will override any fragment (hash)
+ // params in url.
+ // * 1: any fragment (hash) params in url will override params in the
+ // params argument.
+ // * 2: params argument will completely replace any query string in url.
+ //
+ // Returns:
+ //
+ // (String) Either a params string with urlencoded data or a URL with a
+ // urlencoded fragment (hash) in the format 'a=b&c=d&e=f'.
+
+ function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) {
+ var result,
+ qs,
+ matches,
+ url_params,
+ hash;
+
+ if ( params !== undefined ) {
+ // Build URL by merging params into url string.
+
+ // matches[1] = url part that precedes params, not including trailing ?/#
+ // matches[2] = params, not including leading ?/#
+ // matches[3] = if in 'querystring' mode, hash including leading #, otherwise ''
+ matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ );
+
+ // Get the hash if in 'querystring' mode, and it exists.
+ hash = matches[3] || '';
+
+ if ( merge_mode === 2 && is_string( params ) ) {
+ // If merge_mode is 2 and params is a string, merge the fragment / query
+ // string into the URL wholesale, without converting it into an object.
+ qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' );
+
+ } else {
+ // Convert relevant params in url to object.
+ url_params = jq_deparam( matches[2] );
+
+ params = is_string( params )
+
+ // Convert passed params string into object.
+ ? jq_deparam[ is_fragment ? str_fragment : str_querystring ]( params )
+
+ // Passed params object.
+ : params;
+
+ qs = merge_mode === 2 ? params // passed params replace url params
+ : merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params
+ : $.extend( {}, url_params, params ); // passed params override url params
+
+ // Convert params object to a string.
+ qs = jq_param( qs );
+
+ // Unescape characters specified via $.param.noEscape. Since only hash-
+ // history users have requested this feature, it's only enabled for
+ // fragment-related params strings.
+ if ( is_fragment ) {
+ qs = qs.replace( re_no_escape, decode );
+ }
+ }
+
+ // Build URL from the base url, querystring and hash. In 'querystring'
+ // mode, ? is only added if a query string exists. In 'fragment' mode, #
+ // is always added.
+ result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash;
+
+ } else {
+ // If URL was passed in, parse params from URL string, otherwise parse
+ // params from window.location.
+ result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] );
+ }
+
+ return result;
+ };
+
+ jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring );
+ jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment );
+
+ // Method: jQuery.param.fragment.noEscape
+ //
+ // Specify characters that will be left unescaped when fragments are created
+ // or merged using <jQuery.param.fragment>, or when the fragment is modified
+ // using <jQuery.bbq.pushState>. This option only applies to serialized data
+ // object fragments, and not set-as-string fragments. Does not affect the
+ // query string. Defaults to ",/" (comma, forward slash).
+ //
+ // Note that this is considered a purely aesthetic option, and will help to
+ // create URLs that "look pretty" in the address bar or bookmarks, without
+ // affecting functionality in any way. That being said, be careful to not
+ // unescape characters that are used as delimiters or serve a special
+ // purpose, such as the "#?&=+" (octothorpe, question mark, ampersand,
+ // equals, plus) characters.
+ //
+ // Usage:
+ //
+ // > jQuery.param.fragment.noEscape( [ chars ] );
+ //
+ // Arguments:
+ //
+ // chars - (String) The characters to not escape in the fragment. If
+ // unspecified, defaults to empty string (escape all characters).
+ //
+ // Returns:
+ //
+ // Nothing.
+
+ jq_param_fragment.noEscape = function( chars ) {
+ chars = chars || '';
+ var arr = $.map( chars.split(''), encodeURIComponent );
+ re_no_escape = new RegExp( arr.join('|'), 'g' );
+ };
+
+ // A sensible default. These are the characters people seem to complain about
+ // "uglifying up the URL" the most.
+ jq_param_fragment.noEscape( ',/' );
+
+ // Section: Deparam (from string)
+ //
+ // Method: jQuery.deparam
+ //
+ // Deserialize a params string into an object, optionally coercing numbers,
+ // booleans, null and undefined values; this method is the counterpart to the
+ // internal jQuery.param method.
+ //
+ // Usage:
+ //
+ // > jQuery.deparam( params [, coerce ] );
+ //
+ // Arguments:
+ //
+ // params - (String) A params string to be parsed.
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
+ // undefined to their actual value. Defaults to false if omitted.
+ //
+ // Returns:
+ //
+ // (Object) An object representing the deserialized params string.
+
+ $.deparam = jq_deparam = function( params, coerce ) {
+ var obj = {},
+ coerce_types = { 'true': !0, 'false': !1, 'null': null };
+
+ // Iterate over all name=value pairs.
+ $.each( params.replace( /\+/g, ' ' ).split( '&' ), function(j,v){
+ var param = v.split( '=' ),
+ key = decode( param[0] ),
+ val,
+ cur = obj,
+ i = 0,
+
+ // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
+ // into its component parts.
+ keys = key.split( '][' ),
+ keys_last = keys.length - 1;
+
+ // If the first keys part contains [ and the last ends with ], then []
+ // are correctly balanced.
+ if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) {
+ // Remove the trailing ] from the last keys part.
+ keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' );
+
+ // Split first keys part into two parts on the [ and add them back onto
+ // the beginning of the keys array.
+ keys = keys.shift().split('[').concat( keys );
+
+ keys_last = keys.length - 1;
+ } else {
+ // Basic 'foo' style key.
+ keys_last = 0;
+ }
+
+ // Are we dealing with a name=value pair, or just a name?
+ if ( param.length === 2 ) {
+ val = decode( param[1] );
+
+ // Coerce values.
+ if ( coerce ) {
+ val = val && !isNaN(val) ? +val // number
+ : val === 'undefined' ? undefined // undefined
+ : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
+ : val; // string
+ }
+
+ if ( keys_last ) {
+ // Complex key, build deep object structure based on a few rules:
+ // * The 'cur' pointer starts at the object top-level.
+ // * [] = array push (n is set to array length), [n] = array if n is
+ // numeric, otherwise object.
+ // * If at the last keys part, set the value.
+ // * For each keys part, if the current level is undefined create an
+ // object or array based on the type of the next keys part.
+ // * Move the 'cur' pointer to the next level.
+ // * Rinse & repeat.
+ for ( ; i <= keys_last; i++ ) {
+ key = keys[i] === '' ? cur.length : keys[i];
+ cur = cur[key] = i < keys_last
+ ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
+ : val;
+ }
+
+ } else {
+ // Simple key, even simpler rules, since only scalars and shallow
+ // arrays are allowed.
+
+ if ( $.isArray( obj[key] ) ) {
+ // val is already an array, so push on the next value.
+ obj[key].push( val );
+
+ } else if ( obj[key] !== undefined ) {
+ // val isn't an array, but since a second value has been specified,
+ // convert val into an array.
+ obj[key] = [ obj[key], val ];
+
+ } else {
+ // val is a scalar.
+ obj[key] = val;
+ }
+ }
+
+ } else if ( key ) {
+ // No value was defined, so set something meaningful.
+ obj[key] = coerce
+ ? undefined
+ : '';
+ }
+ });
+
+ return obj;
+ };
+
+ // Method: jQuery.deparam.querystring
+ //
+ // Parse the query string from a URL or the current window.location,
+ // deserializing it into an object, optionally coercing numbers, booleans,
+ // null and undefined values.
+ //
+ // Usage:
+ //
+ // > jQuery.deparam.querystring( [ url ] [, coerce ] );
+ //
+ // Arguments:
+ //
+ // url - (String) An optional params string or URL containing query string
+ // params to be parsed. If url is omitted, the current window.location
+ // is used.
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
+ // undefined to their actual value. Defaults to false if omitted.
+ //
+ // Returns:
+ //
+ // (Object) An object representing the deserialized params string.
+
+ // Method: jQuery.deparam.fragment
+ //
+ // Parse the fragment (hash) from a URL or the current window.location,
+ // deserializing it into an object, optionally coercing numbers, booleans,
+ // null and undefined values.
+ //
+ // Usage:
+ //
+ // > jQuery.deparam.fragment( [ url ] [, coerce ] );
+ //
+ // Arguments:
+ //
+ // url - (String) An optional params string or URL containing fragment (hash)
+ // params to be parsed. If url is omitted, the current window.location
+ // is used.
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
+ // undefined to their actual value. Defaults to false if omitted.
+ //
+ // Returns:
+ //
+ // (Object) An object representing the deserialized params string.
+
+ function jq_deparam_sub( is_fragment, url_or_params, coerce ) {
+ if ( url_or_params === undefined || typeof url_or_params === 'boolean' ) {
+ // url_or_params not specified.
+ coerce = url_or_params;
+ url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ]();
+ } else {
+ url_or_params = is_string( url_or_params )
+ ? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' )
+ : url_or_params;
+ }
+
+ return jq_deparam( url_or_params, coerce );
+ };
+
+ jq_deparam[ str_querystring ] = curry( jq_deparam_sub, 0 );
+ jq_deparam[ str_fragment ] = jq_deparam_fragment = curry( jq_deparam_sub, 1 );
+
+ // Section: Element manipulation
+ //
+ // Method: jQuery.elemUrlAttr
+ //
+ // Get the internal "Default URL attribute per tag" list, or augment the list
+ // with additional tag-attribute pairs, in case the defaults are insufficient.
+ //
+ // In the <jQuery.fn.querystring> and <jQuery.fn.fragment> methods, this list
+ // is used to determine which attribute contains the URL to be modified, if
+ // an "attr" param is not specified.
+ //
+ // Default Tag-Attribute List:
+ //
+ // a - href
+ // base - href
+ // iframe - src
+ // img - src
+ // input - src
+ // form - action
+ // link - href
+ // script - src
+ //
+ // Usage:
+ //
+ // > jQuery.elemUrlAttr( [ tag_attr ] );
+ //
+ // Arguments:
+ //
+ // tag_attr - (Object) An object containing a list of tag names and their
+ // associated default attribute names in the format { tag: 'attr', ... } to
+ // be merged into the internal tag-attribute list.
+ //
+ // Returns:
+ //
+ // (Object) An object containing all stored tag-attribute values.
+
+ // Only define function and set defaults if function doesn't already exist, as
+ // the urlInternal plugin will provide this method as well.
+ $[ str_elemUrlAttr ] || ($[ str_elemUrlAttr ] = function( obj ) {
+ return $.extend( elemUrlAttr_cache, obj );
+ })({
+ a: str_href,
+ base: str_href,
+ iframe: str_src,
+ img: str_src,
+ input: str_src,
+ form: 'action',
+ link: str_href,
+ script: str_src
+ });
+
+ jq_elemUrlAttr = $[ str_elemUrlAttr ];
+
+ // Method: jQuery.fn.querystring
+ //
+ // Update URL attribute in one or more elements, merging the current URL (with
+ // or without pre-existing query string params) plus any params object or
+ // string into a new URL, which is then set into that attribute. Like
+ // <jQuery.param.querystring (build url)>, but for all elements in a jQuery
+ // collection.
+ //
+ // Usage:
+ //
+ // > jQuery('selector').querystring( [ attr, ] params [, merge_mode ] );
+ //
+ // Arguments:
+ //
+ // attr - (String) Optional name of an attribute that will contain a URL to
+ // merge params or url into. See <jQuery.elemUrlAttr> for a list of default
+ // attributes.
+ // params - (Object) A params object to be merged into the URL attribute.
+ // params - (String) A URL containing query string params, or params string
+ // to be merged into the URL attribute.
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
+ // specified, and is as-follows:
+ //
+ // * 0: params in the params argument will override any params in attr URL.
+ // * 1: any params in attr URL will override params in the params argument.
+ // * 2: params argument will completely replace any query string in attr
+ // URL.
+ //
+ // Returns:
+ //
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
+ // attribute values.
+
+ // Method: jQuery.fn.fragment
+ //
+ // Update URL attribute in one or more elements, merging the current URL (with
+ // or without pre-existing fragment/hash params) plus any params object or
+ // string into a new URL, which is then set into that attribute. Like
+ // <jQuery.param.fragment (build url)>, but for all elements in a jQuery
+ // collection.
+ //
+ // Usage:
+ //
+ // > jQuery('selector').fragment( [ attr, ] params [, merge_mode ] );
+ //
+ // Arguments:
+ //
+ // attr - (String) Optional name of an attribute that will contain a URL to
+ // merge params into. See <jQuery.elemUrlAttr> for a list of default
+ // attributes.
+ // params - (Object) A params object to be merged into the URL attribute.
+ // params - (String) A URL containing fragment (hash) params, or params
+ // string to be merged into the URL attribute.
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
+ // specified, and is as-follows:
+ //
+ // * 0: params in the params argument will override any params in attr URL.
+ // * 1: any params in attr URL will override params in the params argument.
+ // * 2: params argument will completely replace any fragment (hash) in attr
+ // URL.
+ //
+ // Returns:
+ //
+ // (jQuery) The initial jQuery collection of elements, but with modified URL
+ // attribute values.
+
+ function jq_fn_sub( mode, force_attr, params, merge_mode ) {
+ if ( !is_string( params ) && typeof params !== 'object' ) {
+ // force_attr not specified.
+ merge_mode = params;
+ params = force_attr;
+ force_attr = undefined;
+ }
+
+ return this.each(function(){
+ var that = $(this),
+
+ // Get attribute specified, or default specified via $.elemUrlAttr.
+ attr = force_attr || jq_elemUrlAttr()[ ( this.nodeName || '' ).toLowerCase() ] || '',
+
+ // Get URL value.
+ url = attr && that.attr( attr ) || '';
+
+ // Update attribute with new URL.
+ that.attr( attr, jq_param[ mode ]( url, params, merge_mode ) );
+ });
+
+ };
+
+ $.fn[ str_querystring ] = curry( jq_fn_sub, str_querystring );
+ $.fn[ str_fragment ] = curry( jq_fn_sub, str_fragment );
+
+ // Section: History, hashchange event
+ //
+ // Method: jQuery.bbq.pushState
+ //
+ // Adds a 'state' into the browser history at the current position, setting
+ // location.hash and triggering any bound <hashchange event> callbacks
+ // (provided the new state is different than the previous state).
+ //
+ // If no arguments are passed, an empty state is created, which is just a
+ // shortcut for jQuery.bbq.pushState( {}, 2 ).
+ //
+ // Usage:
+ //
+ // > jQuery.bbq.pushState( [ params [, merge_mode ] ] );
+ //
+ // Arguments:
+ //
+ // params - (String) A serialized params string or a hash string beginning
+ // with # to merge into location.hash.
+ // params - (Object) A params object to merge into location.hash.
+ // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
+ // specified (unless a hash string beginning with # is specified, in which
+ // case merge behavior defaults to 2), and is as-follows:
+ //
+ // * 0: params in the params argument will override any params in the
+ // current state.
+ // * 1: any params in the current state will override params in the params
+ // argument.
+ // * 2: params argument will completely replace current state.
+ //
+ // Returns:
+ //
+ // Nothing.
+ //
+ // Additional Notes:
+ //
+ // * Setting an empty state may cause the browser to scroll.
+ // * Unlike the fragment and querystring methods, if a hash string beginning
+ // with # is specified as the params agrument, merge_mode defaults to 2.
+
+ jq_bbq.pushState = jq_bbq_pushState = function( params, merge_mode ) {
+ if ( is_string( params ) && /^#/.test( params ) && merge_mode === undefined ) {
+ // Params string begins with # and merge_mode not specified, so completely
+ // overwrite window.location.hash.
+ merge_mode = 2;
+ }
+
+ var has_args = params !== undefined,
+ // Merge params into window.location using $.param.fragment.
+ url = jq_param_fragment( window[ str_location ][ str_href ],
+ has_args ? params : {}, has_args ? merge_mode : 2 );
+
+ // Set new window.location.href. If hash is empty, use just # to prevent
+ // browser from reloading the page. Note that Safari 3 & Chrome barf on
+ // location.hash = '#'.
+ window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' );
+ };
+
+ // Method: jQuery.bbq.getState
+ //
+ // Retrieves the current 'state' from the browser history, parsing
+ // location.hash for a specific key or returning an object containing the
+ // entire state, optionally coercing numbers, booleans, null and undefined
+ // values.
+ //
+ // Usage:
+ //
+ // > jQuery.bbq.getState( [ key ] [, coerce ] );
+ //
+ // Arguments:
+ //
+ // key - (String) An optional state key for which to return a value.
+ // coerce - (Boolean) If true, coerces any numbers or true, false, null, and
+ // undefined to their actual value. Defaults to false.
+ //
+ // Returns:
+ //
+ // (Anything) If key is passed, returns the value corresponding with that key
+ // in the location.hash 'state', or undefined. If not, an object
+ // representing the entire 'state' is returned.
+
+ jq_bbq.getState = jq_bbq_getState = function( key, coerce ) {
+ return key === undefined || typeof key === 'boolean'
+ ? jq_deparam_fragment( key ) // 'key' really means 'coerce' here
+ : jq_deparam_fragment( coerce )[ key ];
+ };
+
+ // Method: jQuery.bbq.removeState
+ //
+ // Remove one or more keys from the current browser history 'state', creating
+ // a new state, setting location.hash and triggering any bound
+ // <hashchange event> callbacks (provided the new state is different than
+ // the previous state).
+ //
+ // If no arguments are passed, an empty state is created, which is just a
+ // shortcut for jQuery.bbq.pushState( {}, 2 ).
+ //
+ // Usage:
+ //
+ // > jQuery.bbq.removeState( [ key [, key ... ] ] );
+ //
+ // Arguments:
+ //
+ // key - (String) One or more key values to remove from the current state,
+ // passed as individual arguments.
+ // key - (Array) A single array argument that contains a list of key values
+ // to remove from the current state.
+ //
+ // Returns:
+ //
+ // Nothing.
+ //
+ // Additional Notes:
+ //
+ // * Setting an empty state may cause the browser to scroll.
+
+ jq_bbq.removeState = function( arr ) {
+ var state = {};
+
+ // If one or more arguments is passed..
+ if ( arr !== undefined ) {
+
+ // Get the current state.
+ state = jq_bbq_getState();
+
+ // For each passed key, delete the corresponding property from the current
+ // state.
+ $.each( $.isArray( arr ) ? arr : arguments, function(i,v){
+ delete state[ v ];
+ });
+ }
+
+ // Set the state, completely overriding any existing state.
+ jq_bbq_pushState( state, 2 );
+ };
+
+ // Event: hashchange event (BBQ)
+ //
+ // Usage in jQuery 1.4 and newer:
+ //
+ // In jQuery 1.4 and newer, the event object passed into any hashchange event
+ // callback is augmented with a copy of the location.hash fragment at the time
+ // the event was triggered as its event.fragment property. In addition, the
+ // event.getState method operates on this property (instead of location.hash)
+ // which allows this fragment-as-a-state to be referenced later, even after
+ // window.location may have changed.
+ //
+ // Note that event.fragment and event.getState are not defined according to
+ // W3C (or any other) specification, but will still be available whether or
+ // not the hashchange event exists natively in the browser, because of the
+ // utility they provide.
+ //
+ // The event.fragment property contains the output of <jQuery.param.fragment>
+ // and the event.getState method is equivalent to the <jQuery.bbq.getState>
+ // method.
+ //
+ // > $(window).bind( 'hashchange', function( event ) {
+ // > var hash_str = event.fragment,
+ // > param_obj = event.getState(),
+ // > param_val = event.getState( 'param_name' ),
+ // > param_val_coerced = event.getState( 'param_name', true );
+ // > ...
+ // > });
+ //
+ // Usage in jQuery 1.3.2:
+ //
+ // In jQuery 1.3.2, the event object cannot to be augmented as in jQuery 1.4+,
+ // so the fragment state isn't bound to the event object and must instead be
+ // parsed using the <jQuery.param.fragment> and <jQuery.bbq.getState> methods.
+ //
+ // > $(window).bind( 'hashchange', function( event ) {
+ // > var hash_str = $.param.fragment(),
+ // > param_obj = $.bbq.getState(),
+ // > param_val = $.bbq.getState( 'param_name' ),
+ // > param_val_coerced = $.bbq.getState( 'param_name', true );
+ // > ...
+ // > });
+ //
+ // Additional Notes:
+ //
+ // * Due to changes in the special events API, jQuery BBQ v1.2 or newer is
+ // required to enable the augmented event object in jQuery 1.4.2 and newer.
+ // * See <jQuery hashchange event> for more detailed information.
+
+ jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
+
+ // Augmenting the event object with the .fragment property and .getState
+ // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will
+ // work, but the event won't be augmented)
+ add: function( handleObj ) {
+ var old_handler;
+
+ function new_handler(e) {
+ // e.fragment is set to the value of location.hash (with any leading #
+ // removed) at the time the event is triggered.
+ var hash = e[ str_fragment ] = jq_param_fragment();
+
+ // e.getState() works just like $.bbq.getState(), but uses the
+ // e.fragment property stored on the event object.
+ e.getState = function( key, coerce ) {
+ return key === undefined || typeof key === 'boolean'
+ ? jq_deparam( hash, key ) // 'key' really means 'coerce' here
+ : jq_deparam( hash, coerce )[ key ];
+ };
+
+ old_handler.apply( this, arguments );
+ };
+
+ // This may seem a little complicated, but it normalizes the special event
+ // .add method between jQuery 1.4/1.4.1 and 1.4.2+
+ if ( $.isFunction( handleObj ) ) {
+ // 1.4, 1.4.1
+ old_handler = handleObj;
+ return new_handler;
+ } else {
+ // 1.4.2+
+ old_handler = handleObj.handler;
+ handleObj.handler = new_handler;
+ }
+ }
+
+ });
+
+})(jQuery,this);
+
+/*!
+ * jQuery hashchange event - v1.2 - 2/11/2010
+ * http://benalman.com/projects/jquery-hashchange-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Script: jQuery hashchange event
+//
+// *Version: 1.2, Last updated: 2/11/2010*
+//
+// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
+// GitHub - http://github.com/cowboy/jquery-hashchange/
+// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
+// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb)
+//
+// About: License
+//
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+//
+// About: Examples
+//
+// This working example, complete with fully commented code, illustrate one way
+// in which this plugin can be used.
+//
+// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
+//
+// About: Support and Testing
+//
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+//
+// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1.
+// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
+//
+// About: Known issues
+//
+// While this jQuery hashchange event implementation is quite stable and robust,
+// there are a few unfortunate browser bugs surrounding expected hashchange
+// event-based behaviors, independent of any JavaScript window.onhashchange
+// abstraction. See the following examples for more information:
+//
+// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
+// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
+// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
+// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
+//
+// About: Release History
+//
+// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
+// from a page on another domain would cause an error in Safari 4. Also,
+// IE6/7 Iframe is now inserted after the body (this actually works),
+// which prevents the page from scrolling when the event is first bound.
+// Event can also now be bound before DOM ready, but it won't be usable
+// before then in IE6/7.
+// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
+// where browser version is incorrectly reported as 8.0, despite
+// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
+// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
+// window.onhashchange functionality into a separate plugin for users
+// who want just the basic event & back button support, without all the
+// extra awesomeness that BBQ provides. This plugin will be included as
+// part of jQuery BBQ, but also be available separately.
+
+(function($,window,undefined){
+ '$:nomunge'; // Used by YUI compressor.
+
+ // Method / object references.
+ var fake_onhashchange,
+ jq_event_special = $.event.special,
+
+ // Reused strings.
+ str_location = 'location',
+ str_hashchange = 'hashchange',
+ str_href = 'href',
+
+ // IE6/7 specifically need some special love when it comes to back-button
+ // support, so let's do a little browser sniffing..
+ browser = $.browser,
+ mode = document.documentMode,
+ is_old_ie = browser.msie && ( mode === undefined || mode < 8 ),
+
+ // Does the browser support window.onhashchange? Test for IE version, since
+ // IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"!
+ supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie;
+
+ // Get location.hash (or what you'd expect location.hash to be) sans any
+ // leading #. Thanks for making this necessary, Firefox!
+ function get_fragment( url ) {
+ url = url || window[ str_location ][ str_href ];
+ return url.replace( /^[^#]*#?(.*)$/, '$1' );
+ };
+
+ // Property: jQuery.hashchangeDelay
+ //
+ // The numeric interval (in milliseconds) at which the <hashchange event>
+ // polling loop executes. Defaults to 100.
+
+ $[ str_hashchange + 'Delay' ] = 100;
+
+ // Event: hashchange event
+ //
+ // Fired when location.hash changes. In browsers that support it, the native
+ // window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is
+ // initialized, running every <jQuery.hashchangeDelay> milliseconds to see if
+ // the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow
+ // the back button and hash-based history to work.
+ //
+ // Usage:
+ //
+ // > $(window).bind( 'hashchange', function(e) {
+ // > var hash = location.hash;
+ // > ...
+ // > });
+ //
+ // Additional Notes:
+ //
+ // * The polling loop and Iframe are not created until at least one callback
+ // is actually bound to 'hashchange'.
+ // * If you need the bound callback(s) to execute immediately, in cases where
+ // the page 'state' exists on page load (via bookmark or page refresh, for
+ // example) use $(window).trigger( 'hashchange' );
+ // * The event can be bound before DOM ready, but since it won't be usable
+ // before then in IE6/7 (due to the necessary Iframe), recommended usage is
+ // to bind it inside a $(document).ready() callback.
+
+ jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
+
+ // Called only when the first 'hashchange' event is bound to window.
+ setup: function() {
+ // If window.onhashchange is supported natively, there's nothing to do..
+ if ( supports_onhashchange ) { return false; }
+
+ // Otherwise, we need to create our own. And we don't want to call this
+ // until the user binds to the event, just in case they never do, since it
+ // will create a polling loop and possibly even a hidden Iframe.
+ $( fake_onhashchange.start );
+ },
+
+ // Called only when the last 'hashchange' event is unbound from window.
+ teardown: function() {
+ // If window.onhashchange is supported natively, there's nothing to do..
+ if ( supports_onhashchange ) { return false; }
+
+ // Otherwise, we need to stop ours (if possible).
+ $( fake_onhashchange.stop );
+ }
+
+ });
+
+ // fake_onhashchange does all the work of triggering the window.onhashchange
+ // event for browsers that don't natively support it, including creating a
+ // polling loop to watch for hash changes and in IE 6/7 creating a hidden
+ // Iframe to enable back and forward.
+ fake_onhashchange = (function(){
+ var self = {},
+ timeout_id,
+ iframe,
+ set_history,
+ get_history;
+
+ // Initialize. In IE 6/7, creates a hidden Iframe for history handling.
+ function init(){
+ // Most browsers don't need special methods here..
+ set_history = get_history = function(val){ return val; };
+
+ // But IE6/7 do!
+ if ( is_old_ie ) {
+
+ // Create hidden Iframe after the end of the body to prevent initial
+ // page load from scrolling unnecessarily.
+ iframe = $('<iframe src="javascript:0"/>').hide().insertAfter( 'body' )[0].contentWindow;
+
+ // Get history by looking at the hidden Iframe's location.hash.
+ get_history = function() {
+ return get_fragment( iframe.document[ str_location ][ str_href ] );
+ };
+
+ // Set a new history item by opening and then closing the Iframe
+ // document, *then* setting its location.hash.
+ set_history = function( hash, history_hash ) {
+ if ( hash !== history_hash ) {
+ var doc = iframe.document;
+ doc.open().close();
+ doc[ str_location ].hash = '#' + hash;
+ }
+ };
+
+ // Set initial history.
+ set_history( get_fragment() );
+ }
+ };
+
+ // Start the polling loop.
+ self.start = function() {
+ // Polling loop is already running!
+ if ( timeout_id ) { return; }
+
+ // Remember the initial hash so it doesn't get triggered immediately.
+ var last_hash = get_fragment();
+
+ // Initialize if not yet initialized.
+ set_history || init();
+
+ // This polling loop checks every $.hashchangeDelay milliseconds to see if
+ // location.hash has changed, and triggers the 'hashchange' event on
+ // window when necessary.
+ (function loopy(){
+ var hash = get_fragment(),
+ history_hash = get_history( last_hash );
+
+ if ( hash !== last_hash ) {
+ set_history( last_hash = hash, history_hash );
+
+ $(window).trigger( str_hashchange );
+
+ } else if ( history_hash !== last_hash ) {
+ window[ str_location ][ str_href ] = window[ str_location ][ str_href ].replace( /#.*/, '' ) + '#' + history_hash;
+ }
+
+ timeout_id = setTimeout( loopy, $[ str_hashchange + 'Delay' ] );
+ })();
+ };
+
+ // Stop the polling loop, but only if an IE6/7 Iframe wasn't created. In
+ // that case, even if there are no longer any bound event handlers, the
+ // polling loop is still necessary for back/next to work at all!
+ self.stop = function() {
+ if ( !iframe ) {
+ timeout_id && clearTimeout( timeout_id );
+ timeout_id = 0;
+ }
+ };
+
+ return self;
+ })();
+
+})(jQuery,this);
diff --git a/addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.min.js b/addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.min.js
new file mode 100644
index 00000000000..bcbf24834ac
--- /dev/null
+++ b/addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.min.js
@@ -0,0 +1,18 @@
+/*
+ * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
+ * http://benalman.com/projects/jquery-bbq-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+(function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M<N?O[P]||(R[M+1]&&isNaN(R[M+1])?{}:[]):J}}else{if($.isArray(H[P])){H[P].push(J)}else{if(H[P]!==i){H[P]=[H[P],J]}else{H[P]=J}}}}else{if(P){H[P]=F?i:""}}});return H};function z(H,F,G){if(F===i||typeof F==="boolean"){G=F;F=a[H?D:A]()}else{F=E(F)?F.replace(H?w:x,""):F}return l(F,G)}l[A]=B(z,0);l[D]=v=B(z,1);$[y]||($[y]=function(F){return $.extend(C,F)})({a:k,base:k,iframe:t,img:t,input:t,form:"action",link:k,script:t});j=$[y];function s(I,G,H,F){if(!E(H)&&typeof H!=="object"){F=H;H=G;G=i}return this.each(function(){var L=$(this),J=G||j()[(this.nodeName||"").toLowerCase()]||"",K=J&&L.attr(J)||"";L.attr(J,a[I](K,H,F))})}$.fn[A]=B(s,A);$.fn[D]=B(s,D);b.pushState=q=function(I,F){if(E(I)&&/^#/.test(I)&&F===i){F=2}var H=I!==i,G=c(p[g][k],H?I:{},H?F:2);p[g][k]=G+(/#/.test(G)?"":"#")};b.getState=u=function(F,G){return F===i||typeof F==="boolean"?v(F):v(G)[F]};b.removeState=function(F){var G={};if(F!==i){G=u();$.each($.isArray(F)?F:arguments,function(I,H){delete G[H]})}q(G,2)};e[d]=$.extend(e[d],{add:function(F){var H;function G(J){var I=J[D]=c();J.getState=function(K,L){return K===i||typeof K==="boolean"?l(I,K):l(I,L)[K]};H.apply(this,arguments)}if($.isFunction(F)){H=F;return G}else{H=F.handler;F.handler=G}}})})(jQuery,this);
+/*
+ * jQuery hashchange event - v1.2 - 2/11/2010
+ * http://benalman.com/projects/jquery-hashchange-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+(function($,i,b){var j,k=$.event.special,c="location",d="hashchange",l="href",f=$.browser,g=document.documentMode,h=f.msie&&(g===b||g<8),e="on"+d in i&&!h;function a(m){m=m||i[c][l];return m.replace(/^[^#]*#?(.*)$/,"$1")}$[d+"Delay"]=100;k[d]=$.extend(k[d],{setup:function(){if(e){return false}$(j.start)},teardown:function(){if(e){return false}$(j.stop)}});j=(function(){var m={},r,n,o,q;function p(){o=q=function(s){return s};if(h){n=$('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.blockUI/jquery.blockUI.js b/addons/web/static/lib/jquery.blockUI/jquery.blockUI.js
new file mode 100644
index 00000000000..04db883c76e
--- /dev/null
+++ b/addons/web/static/lib/jquery.blockUI/jquery.blockUI.js
@@ -0,0 +1,499 @@
+/*!
+ * jQuery blockUI plugin
+ * Version 2.39 (23-MAY-2011)
+ * @requires jQuery v1.2.3 or later
+ *
+ * Examples at: http://malsup.com/jquery/block/
+ * Copyright (c) 2007-2010 M. Alsup
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Thanks to Amir-Hossein Sobhi for some excellent contributions!
+ */
+
+;(function($) {
+
+if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
+ alert('blockUI requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery);
+ return;
+}
+
+$.fn._fadeIn = $.fn.fadeIn;
+
+var noOp = function() {};
+
+// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
+// retarded userAgent strings on Vista)
+var mode = document.documentMode || 0;
+var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
+var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;
+
+// global $ methods for blocking/unblocking the entire page
+$.blockUI = function(opts) { install(window, opts); };
+$.unblockUI = function(opts) { remove(window, opts); };
+
+// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
+$.growlUI = function(title, message, timeout, onClose) {
+ var $m = $('<div class="growlUI"></div>');
+ if (title) $m.append('<h1>'+title+'</h1>');
+ if (message) $m.append('<h2>'+message+'</h2>');
+ if (timeout == undefined) timeout = 3000;
+ $.blockUI({
+ message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
+ timeout: timeout, showOverlay: false,
+ onUnblock: onClose,
+ css: $.blockUI.defaults.growlCSS
+ });
+};
+
+// plugin method for blocking element content
+$.fn.block = function(opts) {
+ return this.unblock({ fadeOut: 0 }).each(function() {
+ if ($.css(this,'position') == 'static')
+ this.style.position = 'relative';
+ if ($.browser.msie)
+ this.style.zoom = 1; // force 'hasLayout'
+ install(this, opts);
+ });
+};
+
+// plugin method for unblocking element content
+$.fn.unblock = function(opts) {
+ return this.each(function() {
+ remove(this, opts);
+ });
+};
+
+$.blockUI.version = 2.39; // 2nd generation blocking at no extra cost!
+
+// override these in your code to change the default behavior and style
+$.blockUI.defaults = {
+ // message displayed when blocking (use null for no message)
+ message: '<h1>Please wait...</h1>',
+
+ title: null, // title string; only used when theme == true
+ draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
+
+ theme: false, // set to true to use with jQuery UI themes
+
+ // styles for the message when blocking; if you wish to disable
+ // these and use an external stylesheet then do this in your code:
+ // $.blockUI.defaults.css = {};
+ css: {
+ padding: 0,
+ margin: 0,
+ width: '30%',
+ top: '40%',
+ left: '35%',
+ textAlign: 'center',
+ color: '#000',
+ border: '3px solid #aaa',
+ backgroundColor:'#fff',
+ cursor: 'wait'
+ },
+
+ // minimal style set used when themes are used
+ themedCSS: {
+ width: '30%',
+ top: '40%',
+ left: '35%'
+ },
+
+ // styles for the overlay
+ overlayCSS: {
+ backgroundColor: '#000',
+ opacity: 0.6,
+ cursor: 'wait'
+ },
+
+ // styles applied when using $.growlUI
+ growlCSS: {
+ width: '350px',
+ top: '10px',
+ left: '',
+ right: '10px',
+ border: 'none',
+ padding: '5px',
+ opacity: 0.6,
+ cursor: 'default',
+ color: '#fff',
+ backgroundColor: '#000',
+ '-webkit-border-radius': '10px',
+ '-moz-border-radius': '10px',
+ 'border-radius': '10px'
+ },
+
+ // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
+ // (hat tip to Jorge H. N. de Vasconcelos)
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
+
+ // force usage of iframe in non-IE browsers (handy for blocking applets)
+ forceIframe: false,
+
+ // z-index for the blocking overlay
+ baseZ: 1000,
+
+ // set these to true to have the message automatically centered
+ centerX: true, // <-- only effects element blocking (page block controlled via css above)
+ centerY: true,
+
+ // allow body element to be stetched in ie6; this makes blocking look better
+ // on "short" pages. disable if you wish to prevent changes to the body height
+ allowBodyStretch: true,
+
+ // enable if you want key and mouse events to be disabled for content that is blocked
+ bindEvents: true,
+
+ // be default blockUI will supress tab navigation from leaving blocking content
+ // (if bindEvents is true)
+ constrainTabKey: true,
+
+ // fadeIn time in millis; set to 0 to disable fadeIn on block
+ fadeIn: 200,
+
+ // fadeOut time in millis; set to 0 to disable fadeOut on unblock
+ fadeOut: 400,
+
+ // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
+ timeout: 0,
+
+ // disable if you don't want to show the overlay
+ showOverlay: true,
+
+ // if true, focus will be placed in the first available input field when
+ // page blocking
+ focusInput: true,
+
+ // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
+ applyPlatformOpacityRules: true,
+
+ // callback method invoked when fadeIn has completed and blocking message is visible
+ onBlock: null,
+
+ // callback method invoked when unblocking has completed; the callback is
+ // passed the element that has been unblocked (which is the window object for page
+ // blocks) and the options that were passed to the unblock call:
+ // onUnblock(element, options)
+ onUnblock: null,
+
+ // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
+ quirksmodeOffsetHack: 4,
+
+ // class name of the message block
+ blockMsgClass: 'blockMsg'
+};
+
+// private data and functions follow...
+
+var pageBlock = null;
+var pageBlockEls = [];
+
+function install(el, opts) {
+ var full = (el == window);
+ var msg = opts && opts.message !== undefined ? opts.message : undefined;
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+ opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
+ var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
+ var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
+ msg = msg === undefined ? opts.message : msg;
+
+ // remove the current block (if there is one)
+ if (full && pageBlock)
+ remove(window, {fadeOut:0});
+
+ // if an existing element is being used as the blocking content then we capture
+ // its current place in the DOM (and current display style) so we can restore
+ // it when we unblock
+ if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
+ var node = msg.jquery ? msg[0] : msg;
+ var data = {};
+ $(el).data('blockUI.history', data);
+ data.el = node;
+ data.parent = node.parentNode;
+ data.display = node.style.display;
+ data.position = node.style.position;
+ if (data.parent)
+ data.parent.removeChild(node);
+ }
+
+ $(el).data('blockUI.onUnblock', opts.onUnblock);
+ var z = opts.baseZ;
+
+ // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
+ // layer1 is the iframe layer which is used to supress bleed through of underlying content
+ // layer2 is the overlay layer which has opacity and a wait cursor (by default)
+ // layer3 is the message content that is displayed while blocking
+
+ var lyr1 = ($.browser.msie || opts.forceIframe)
+ ? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
+ : $('<div class="blockUI" style="display:none"></div>');
+
+ var lyr2 = opts.theme
+ ? $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>')
+ : $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
+
+ var lyr3, s;
+ if (opts.theme && full) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">' +
+ '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
+ '<div class="ui-widget-content ui-dialog-content"></div>' +
+ '</div>';
+ }
+ else if (opts.theme) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">' +
+ '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
+ '<div class="ui-widget-content ui-dialog-content"></div>' +
+ '</div>';
+ }
+ else if (full) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
+ }
+ else {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
+ }
+ lyr3 = $(s);
+
+ // if we have a message, style it
+ if (msg) {
+ if (opts.theme) {
+ lyr3.css(themedCSS);
+ lyr3.addClass('ui-widget-content');
+ }
+ else
+ lyr3.css(css);
+ }
+
+ // style the overlay
+ if (!opts.theme && (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform))))
+ lyr2.css(opts.overlayCSS);
+ lyr2.css('position', full ? 'fixed' : 'absolute');
+
+ // make iframe layer transparent in IE
+ if ($.browser.msie || opts.forceIframe)
+ lyr1.css('opacity',0.0);
+
+ //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
+ var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
+ $.each(layers, function() {
+ this.appendTo($par);
+ });
+
+ if (opts.theme && opts.draggable && $.fn.draggable) {
+ lyr3.draggable({
+ handle: '.ui-dialog-titlebar',
+ cancel: 'li'
+ });
+ }
+
+ // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
+ var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
+ if (ie6 || expr) {
+ // give body 100% height
+ if (full && opts.allowBodyStretch && $.boxModel)
+ $('html,body').css('height','100%');
+
+ // fix ie6 issue when blocked element has a border width
+ if ((ie6 || !$.boxModel) && !full) {
+ var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
+ var fixT = t ? '(0 - '+t+')' : 0;
+ var fixL = l ? '(0 - '+l+')' : 0;
+ }
+
+ // simulate fixed position
+ $.each([lyr1,lyr2,lyr3], function(i,o) {
+ var s = o[0].style;
+ s.position = 'absolute';
+ if (i < 2) {
+ full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
+ : s.setExpression('height','this.parentNode.offsetHeight + "px"');
+ full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
+ : s.setExpression('width','this.parentNode.offsetWidth + "px"');
+ if (fixL) s.setExpression('left', fixL);
+ if (fixT) s.setExpression('top', fixT);
+ }
+ else if (opts.centerY) {
+ if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
+ s.marginTop = 0;
+ }
+ else if (!opts.centerY && full) {
+ var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
+ var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
+ s.setExpression('top',expression);
+ }
+ });
+ }
+
+ // show the message
+ if (msg) {
+ if (opts.theme)
+ lyr3.find('.ui-widget-content').append(msg);
+ else
+ lyr3.append(msg);
+ if (msg.jquery || msg.nodeType)
+ $(msg).show();
+ }
+
+ if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
+ lyr1.show(); // opacity is zero
+ if (opts.fadeIn) {
+ var cb = opts.onBlock ? opts.onBlock : noOp;
+ var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
+ var cb2 = msg ? cb : noOp;
+ if (opts.showOverlay)
+ lyr2._fadeIn(opts.fadeIn, cb1);
+ if (msg)
+ lyr3._fadeIn(opts.fadeIn, cb2);
+ }
+ else {
+ if (opts.showOverlay)
+ lyr2.show();
+ if (msg)
+ lyr3.show();
+ if (opts.onBlock)
+ opts.onBlock();
+ }
+
+ // bind key and mouse events
+ bind(1, el, opts);
+
+ if (full) {
+ pageBlock = lyr3[0];
+ pageBlockEls = $(':input:enabled:visible',pageBlock);
+ if (opts.focusInput)
+ setTimeout(focus, 20);
+ }
+ else
+ center(lyr3[0], opts.centerX, opts.centerY);
+
+ if (opts.timeout) {
+ // auto-unblock
+ var to = setTimeout(function() {
+ full ? $.unblockUI(opts) : $(el).unblock(opts);
+ }, opts.timeout);
+ $(el).data('blockUI.timeout', to);
+ }
+};
+
+// remove the block
+function remove(el, opts) {
+ var full = (el == window);
+ var $el = $(el);
+ var data = $el.data('blockUI.history');
+ var to = $el.data('blockUI.timeout');
+ if (to) {
+ clearTimeout(to);
+ $el.removeData('blockUI.timeout');
+ }
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+ bind(0, el, opts); // unbind events
+
+ if (opts.onUnblock === null) {
+ opts.onUnblock = $el.data('blockUI.onUnblock');
+ $el.removeData('blockUI.onUnblock');
+ }
+
+ var els;
+ if (full) // crazy selector to handle odd field errors in ie6/7
+ els = $('body').children().filter('.blockUI').add('body > .blockUI');
+ else
+ els = $('.blockUI', el);
+
+ if (full)
+ pageBlock = pageBlockEls = null;
+
+ if (opts.fadeOut) {
+ els.fadeOut(opts.fadeOut);
+ setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
+ }
+ else
+ reset(els, data, opts, el);
+};
+
+// move blocking element back into the DOM where it started
+function reset(els,data,opts,el) {
+ els.each(function(i,o) {
+ // remove via DOM calls so we don't lose event handlers
+ if (this.parentNode)
+ this.parentNode.removeChild(this);
+ });
+
+ if (data && data.el) {
+ data.el.style.display = data.display;
+ data.el.style.position = data.position;
+ if (data.parent)
+ data.parent.appendChild(data.el);
+ $(el).removeData('blockUI.history');
+ }
+
+ if (typeof opts.onUnblock == 'function')
+ opts.onUnblock(el,opts);
+};
+
+// bind/unbind the handler
+function bind(b, el, opts) {
+ var full = el == window, $el = $(el);
+
+ // don't bother unbinding if there is nothing to unbind
+ if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
+ return;
+ if (!full)
+ $el.data('blockUI.isBlocked', b);
+
+ // don't bind events when overlay is not in use or if bindEvents is false
+ if (!opts.bindEvents || (b && !opts.showOverlay))
+ return;
+
+ // bind anchors and inputs for mouse and key events
+ var events = 'mousedown mouseup keydown keypress';
+ b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
+
+// former impl...
+// var $e = $('a,:input');
+// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
+};
+
+// event handler to suppress keyboard/mouse events when blocking
+function handler(e) {
+ // allow tab navigation (conditionally)
+ if (e.keyCode && e.keyCode == 9) {
+ if (pageBlock && e.data.constrainTabKey) {
+ var els = pageBlockEls;
+ var fwd = !e.shiftKey && e.target === els[els.length-1];
+ var back = e.shiftKey && e.target === els[0];
+ if (fwd || back) {
+ setTimeout(function(){focus(back)},10);
+ return false;
+ }
+ }
+ }
+ var opts = e.data;
+ // allow events within the message content
+ if ($(e.target).parents('div.' + opts.blockMsgClass).length > 0)
+ return true;
+
+ // allow events for content that is not being blocked
+ return $(e.target).parents().children().filter('div.blockUI').length == 0;
+};
+
+function focus(back) {
+ if (!pageBlockEls)
+ return;
+ var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
+ if (e)
+ e.focus();
+};
+
+function center(el, x, y) {
+ var p = el.parentNode, s = el.style;
+ var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
+ var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
+ if (x) s.left = l > 0 ? (l+'px') : '0';
+ if (y) s.top = t > 0 ? (t+'px') : '0';
+};
+
+function sz(el, p) {
+ return parseInt($.css(el,p))||0;
+};
+
+})(jQuery);
diff --git a/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js b/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js
new file mode 100644
index 00000000000..2356f3b606b
--- /dev/null
+++ b/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js
@@ -0,0 +1,126 @@
+(function($) {
+ var menu,shadow,trigger,content,hash,currentTarget;
+ var defaults= {
+ menuStyle: {
+ listStyle:'none',
+ padding:'1px',
+ margin:'0px',
+ backgroundColor:'#fff',
+ border:'1px solid #999',
+ width:'100px'
+ },
+ itemStyle: {
+ margin:'0px',
+ color:'#000',
+ display:'block',
+ cursor:'default',
+ padding:'3px',
+ border:'1px solid #fff',
+ backgroundColor:'transparent'
+ },
+ itemHoverStyle: {
+ border:'1px solid #0a246a',
+ backgroundColor:'#b6bdd2'
+ },
+ eventPosX:'pageX',
+ eventPosY:'pageY',
+ shadow:true,
+ onContextMenu:null,
+ onShowMenu:null
+ };
+ $.fn.contextMenu= function(id,options) {
+ if(!menu) {
+ menu=$('<div id="jqContextMenu"></div>').hide().css({
+ position:'absolute',
+ zIndex:'2000'
+ }).appendTo('body').bind('click', function(e) {
+ e.stopPropagation()
+ })
+ }
+ if(!shadow) {
+ shadow=$('<div></div>').css({
+ backgroundColor:'#000',
+ position:'absolute',
+ opacity:0.2,
+ zIndex:499
+ }).appendTo('body').hide()
+ }
+ hash=hash||[];
+ hash.push({
+ id:id,
+ menuStyle:$.extend({},defaults.menuStyle,options.menuStyle|| {}),
+ itemStyle:$.extend({},defaults.itemStyle,options.itemStyle|| {}),
+ itemHoverStyle:$.extend({},defaults.itemHoverStyle,options.itemHoverStyle|| {}),
+ bindings:options.bindings|| {},
+ shadow:options.shadow||options.shadow===false?options.shadow:defaults.shadow,
+ onContextMenu:options.onContextMenu||defaults.onContextMenu,
+ onShowMenu:options.onShowMenu||defaults.onShowMenu,
+ eventPosX:options.eventPosX||defaults.eventPosX,
+ eventPosY:options.eventPosY||defaults.eventPosY
+ });
+ var index=hash.length-1;
+ var callback = function(e) {
+ var bShowContext=(!!hash[index].onContextMenu)?hash[index].onContextMenu(e):true;
+ if(bShowContext)
+ display(index,this,e,options);
+ return false;
+ };
+ $(this).bind('contextmenu', callback);
+ if(options.leftClickToo) {
+ $(this).click(callback);
+ }
+ return this
+ };
+ function display(index,trigger,e,options) {
+ var cur=hash[index];
+ content=$('#'+cur.id).find('ul:first').clone(true);
+ content.css(cur.menuStyle).find('li').css(cur.itemStyle).hover( function() {
+ $(this).css(cur.itemHoverStyle)
+ }, function() {
+ $(this).css(cur.itemStyle)
+ }).find('img').css({
+ verticalAlign:'middle',
+ paddingRight:'2px'
+ });
+ menu.html(content);
+ if(!!cur.onShowMenu)
+ menu=cur.onShowMenu(e,menu);
+ $.each(cur.bindings, function(id,func) {
+ $('#'+id,menu).bind('click', function(e) {
+ hide();
+ func(trigger,currentTarget)
+ })
+ });
+ menu.css({
+ 'left':e[cur.eventPosX],
+ 'top':e[cur.eventPosY]
+ }).show();
+ if(cur.shadow)
+ shadow.css({
+ width:menu.width(),
+ height:menu.height(),
+ left:e.pageX+2,
+ top:e.pageY+2
+ }).show();
+ $(document).one('click',hide)
+ }
+
+ function hide() {
+ menu.hide();
+ shadow.hide()
+ }
+
+ $.contextMenu= {
+ defaults: function(userDefaults) {
+ $.each(userDefaults, function(i,val) {
+ if(typeof val=='object'&&defaults[i]) {
+ $.extend(defaults[i],val)
+ } else
+ defaults[i]=val
+ })
+ }
+ }
+})(jQuery);
+$( function() {
+ $('div.contextMenu').hide()
+}); \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.form/jquery.form.js b/addons/web/static/lib/jquery.form/jquery.form.js
new file mode 100644
index 00000000000..66ac5142238
--- /dev/null
+++ b/addons/web/static/lib/jquery.form/jquery.form.js
@@ -0,0 +1,911 @@
+/*!
+ * jQuery Form Plugin
+ * version: 2.83 (11-JUL-2011)
+ * @requires jQuery v1.3.2 or later
+ *
+ * Examples and documentation at: http://malsup.com/jquery/form/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+;(function($) {
+
+/*
+ Usage Note:
+ -----------
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
+ functions are intended to be exclusive. Use ajaxSubmit if you want
+ to bind your own submit handler to the form. For example,
+
+ $(document).ready(function() {
+ $('#myForm').bind('submit', function(e) {
+ e.preventDefault(); // <-- important
+ $(this).ajaxSubmit({
+ target: '#output'
+ });
+ });
+ });
+
+ Use ajaxForm when you want the plugin to manage all the event binding
+ for you. For example,
+
+ $(document).ready(function() {
+ $('#myForm').ajaxForm({
+ target: '#output'
+ });
+ });
+
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
+ at the appropriate time.
+*/
+
+/**
+ * ajaxSubmit() provides a mechanism for immediately submitting
+ * an HTML form using AJAX.
+ */
+$.fn.ajaxSubmit = function(options) {
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
+ if (!this.length) {
+ log('ajaxSubmit: skipping submit process - no element selected');
+ return this;
+ }
+
+ var method, action, url, $form = this;
+
+ if (typeof options == 'function') {
+ options = { success: options };
+ }
+
+ method = this.attr('method');
+ action = this.attr('action');
+ url = (typeof action === 'string') ? $.trim(action) : '';
+ url = url || window.location.href || '';
+ if (url) {
+ // clean url (don't include hash vaue)
+ url = (url.match(/^([^#]+)/)||[])[1];
+ }
+
+ options = $.extend(true, {
+ url: url,
+ success: $.ajaxSettings.success,
+ type: method || 'GET',
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
+ }, options);
+
+ // hook for manipulating the form data before it is extracted;
+ // convenient for use with rich editors like tinyMCE or FCKEditor
+ var veto = {};
+ this.trigger('form-pre-serialize', [this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
+ return this;
+ }
+
+ // provide opportunity to alter form data before it is serialized
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
+ return this;
+ }
+
+ var n,v,a = this.formToArray(options.semantic);
+ if (options.data) {
+ options.extraData = options.data;
+ for (n in options.data) {
+ if(options.data[n] instanceof Array) {
+ for (var k in options.data[n]) {
+ a.push( { name: n, value: options.data[n][k] } );
+ }
+ }
+ else {
+ v = options.data[n];
+ v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
+ a.push( { name: n, value: v } );
+ }
+ }
+ }
+
+ // give pre-submit callback an opportunity to abort the submit
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
+ return this;
+ }
+
+ // fire vetoable 'validate' event
+ this.trigger('form-submit-validate', [a, this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
+ return this;
+ }
+
+ var q = $.param(a);
+
+ if (options.type.toUpperCase() == 'GET') {
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
+ options.data = null; // data is null for 'get'
+ }
+ else {
+ options.data = q; // data is the query string for 'post'
+ }
+
+ var callbacks = [];
+ if (options.resetForm) {
+ callbacks.push(function() { $form.resetForm(); });
+ }
+ if (options.clearForm) {
+ callbacks.push(function() { $form.clearForm(); });
+ }
+
+ // perform a load on the target only if dataType is not provided
+ if (!options.dataType && options.target) {
+ var oldSuccess = options.success || function(){};
+ callbacks.push(function(data) {
+ var fn = options.replaceTarget ? 'replaceWith' : 'html';
+ $(options.target)[fn](data).each(oldSuccess, arguments);
+ });
+ }
+ else if (options.success) {
+ callbacks.push(options.success);
+ }
+
+ options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
+ var context = options.context || options; // jQuery 1.4+ supports scope context
+ for (var i=0, max=callbacks.length; i < max; i++) {
+ callbacks[i].apply(context, [data, status, xhr || $form, $form]);
+ }
+ };
+
+ // are there files to upload?
+ var fileInputs = $('input:file', this).length > 0;
+ var mp = 'multipart/form-data';
+ var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
+
+ // options.iframe allows user to force iframe mode
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
+ if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
+ if (options.closeKeepAlive) {
+ $.get(options.closeKeepAlive, function() { fileUpload(a); });
+ }
+ else {
+ fileUpload(a);
+ }
+ }
+ else {
+ // IE7 massage (see issue 57)
+ if ($.browser.msie && method == 'get') {
+ var ieMeth = $form[0].getAttribute('method');
+ if (typeof ieMeth === 'string')
+ options.type = ieMeth;
+ }
+ $.ajax(options);
+ }
+
+ // fire 'notify' event
+ this.trigger('form-submit-notify', [this, options]);
+ return this;
+
+
+ // private function for handling file uploads (hat tip to YAHOO!)
+ function fileUpload(a) {
+ var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
+ var useProp = !!$.fn.prop;
+
+ if (a) {
+ // ensure that every serialized input is still enabled
+ for (i=0; i < a.length; i++) {
+ el = $(form[a[i].name]);
+ el[ useProp ? 'prop' : 'attr' ]('disabled', false);
+ }
+ }
+
+ if ($(':input[name=submit],:input[id=submit]', form).length) {
+ // if there is an input with a name or id of 'submit' then we won't be
+ // able to invoke the submit fn on the form (at least not x-browser)
+ alert('Error: Form elements must not have name or id of "submit".');
+ return;
+ }
+
+ s = $.extend(true, {}, $.ajaxSettings, options);
+ s.context = s.context || s;
+ id = 'jqFormIO' + (new Date().getTime());
+ if (s.iframeTarget) {
+ $io = $(s.iframeTarget);
+ n = $io.attr('name');
+ if (n == null)
+ $io.attr('name', id);
+ else
+ id = n;
+ }
+ else {
+ $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+ }
+ io = $io[0];
+
+
+ xhr = { // mock object
+ aborted: 0,
+ responseText: null,
+ responseXML: null,
+ status: 0,
+ statusText: 'n/a',
+ getAllResponseHeaders: function() {},
+ getResponseHeader: function() {},
+ setRequestHeader: function() {},
+ abort: function(status) {
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
+ log('aborting upload... ' + e);
+ this.aborted = 1;
+ $io.attr('src', s.iframeSrc); // abort op in progress
+ xhr.error = e;
+ s.error && s.error.call(s.context, xhr, e, status);
+ g && $.event.trigger("ajaxError", [xhr, s, e]);
+ s.complete && s.complete.call(s.context, xhr, e);
+ }
+ };
+
+ g = s.global;
+ // trigger ajax global events so that activity/block indicators work like normal
+ if (g && ! $.active++) {
+ $.event.trigger("ajaxStart");
+ }
+ if (g) {
+ $.event.trigger("ajaxSend", [xhr, s]);
+ }
+
+ if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+ if (s.global) {
+ $.active--;
+ }
+ return;
+ }
+ if (xhr.aborted) {
+ return;
+ }
+
+ // add submitting element to data if we know it
+ sub = form.clk;
+ if (sub) {
+ n = sub.name;
+ if (n && !sub.disabled) {
+ s.extraData = s.extraData || {};
+ s.extraData[n] = sub.value;
+ if (sub.type == "image") {
+ s.extraData[n+'.x'] = form.clk_x;
+ s.extraData[n+'.y'] = form.clk_y;
+ }
+ }
+ }
+
+ var CLIENT_TIMEOUT_ABORT = 1;
+ var SERVER_ABORT = 2;
+
+ function getDoc(frame) {
+ var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
+ return doc;
+ }
+
+ // take a breath so that pending repaints get some cpu time before the upload starts
+ function doSubmit() {
+ // make sure form attrs are set
+ var t = $form.attr('target'), a = $form.attr('action');
+
+ // update form attrs in IE friendly way
+ form.setAttribute('target',id);
+ if (!method) {
+ form.setAttribute('method', 'POST');
+ }
+ if (a != s.url) {
+ form.setAttribute('action', s.url);
+ }
+
+ // ie borks in some cases when setting encoding
+ if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
+ $form.attr({
+ encoding: 'multipart/form-data',
+ enctype: 'multipart/form-data'
+ });
+ }
+
+ // support timout
+ if (s.timeout) {
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
+ }
+
+ // look for server aborts
+ function checkState() {
+ try {
+ var state = getDoc(io).readyState;
+ log('state = ' + state);
+ if (state.toLowerCase() == 'uninitialized')
+ setTimeout(checkState,50);
+ }
+ catch(e) {
+ log('Server abort: ' , e, ' (', e.name, ')');
+ cb(SERVER_ABORT);
+ timeoutHandle && clearTimeout(timeoutHandle);
+ timeoutHandle = undefined;
+ }
+ }
+
+ // add "extra" data to form if provided in options
+ var extraInputs = [];
+ try {
+ if (s.extraData) {
+ for (var n in s.extraData) {
+ extraInputs.push(
+ $('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n])
+ .appendTo(form)[0]);
+ }
+ }
+
+ if (!s.iframeTarget) {
+ // add iframe to doc and submit the form
+ $io.appendTo('body');
+ io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
+ }
+ setTimeout(checkState,15);
+ form.submit();
+ }
+ finally {
+ // reset attrs and remove "extra" input elements
+ form.setAttribute('action',a);
+ if(t) {
+ form.setAttribute('target', t);
+ } else {
+ $form.removeAttr('target');
+ }
+ $(extraInputs).remove();
+ }
+ }
+
+ if (s.forceSync) {
+ doSubmit();
+ }
+ else {
+ setTimeout(doSubmit, 10); // this lets dom updates render
+ }
+
+ var data, doc, domCheckCount = 50, callbackProcessed;
+
+ function cb(e) {
+ if (xhr.aborted || callbackProcessed) {
+ return;
+ }
+ try {
+ doc = getDoc(io);
+ }
+ catch(ex) {
+ log('cannot access response document: ', ex);
+ e = SERVER_ABORT;
+ }
+ if (e === CLIENT_TIMEOUT_ABORT && xhr) {
+ xhr.abort('timeout');
+ return;
+ }
+ else if (e == SERVER_ABORT && xhr) {
+ xhr.abort('server abort');
+ return;
+ }
+
+ if (!doc || doc.location.href == s.iframeSrc) {
+ // response not received yet
+ if (!timedOut)
+ return;
+ }
+ io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
+
+ var status = 'success', errMsg;
+ try {
+ if (timedOut) {
+ throw 'timeout';
+ }
+
+ var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+ log('isXml='+isXml);
+ if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
+ if (--domCheckCount) {
+ // in some browsers (Opera) the iframe DOM is not always traversable when
+ // the onload callback fires, so we loop a bit to accommodate
+ log('requeing onLoad callback, DOM not available');
+ setTimeout(cb, 250);
+ return;
+ }
+ // let this fall through because server response could be an empty document
+ //log('Could not access iframe DOM after mutiple tries.');
+ //throw 'DOMException: not available';
+ }
+
+ //log('response detected');
+ var docRoot = doc.body ? doc.body : doc.documentElement;
+ xhr.responseText = docRoot ? docRoot.innerHTML : null;
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+ if (isXml)
+ s.dataType = 'xml';
+ xhr.getResponseHeader = function(header){
+ var headers = {'content-type': s.dataType};
+ return headers[header];
+ };
+ // support for XHR 'status' & 'statusText' emulation :
+ if (docRoot) {
+ xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
+ xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
+ }
+
+ var dt = s.dataType || '';
+ var scr = /(json|script|text)/.test(dt.toLowerCase());
+ if (scr || s.textarea) {
+ // see if user embedded response in textarea
+ var ta = doc.getElementsByTagName('textarea')[0];
+ if (ta) {
+ xhr.responseText = ta.value;
+ // support for XHR 'status' & 'statusText' emulation :
+ xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
+ xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
+ }
+ else if (scr) {
+ // account for browsers injecting pre around json response
+ var pre = doc.getElementsByTagName('pre')[0];
+ var b = doc.getElementsByTagName('body')[0];
+ if (pre) {
+ xhr.responseText = pre.textContent ? pre.textContent : pre.innerHTML;
+ }
+ else if (b) {
+ xhr.responseText = b.innerHTML;
+ }
+ }
+ }
+ else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
+ xhr.responseXML = toXml(xhr.responseText);
+ }
+
+ try {
+ data = httpData(xhr, s.dataType, s);
+ }
+ catch (e) {
+ status = 'parsererror';
+ xhr.error = errMsg = (e || status);
+ }
+ }
+ catch (e) {
+ log('error caught: ',e);
+ status = 'error';
+ xhr.error = errMsg = (e || status);
+ }
+
+ if (xhr.aborted) {
+ log('upload aborted');
+ status = null;
+ }
+
+ if (xhr.status) { // we've set xhr.status
+ status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
+ }
+
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+ if (status === 'success') {
+ s.success && s.success.call(s.context, data, 'success', xhr);
+ g && $.event.trigger("ajaxSuccess", [xhr, s]);
+ }
+ else if (status) {
+ if (errMsg == undefined)
+ errMsg = xhr.statusText;
+ s.error && s.error.call(s.context, xhr, status, errMsg);
+ g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
+ }
+
+ g && $.event.trigger("ajaxComplete", [xhr, s]);
+
+ if (g && ! --$.active) {
+ $.event.trigger("ajaxStop");
+ }
+
+ s.complete && s.complete.call(s.context, xhr, status);
+
+ callbackProcessed = true;
+ if (s.timeout)
+ clearTimeout(timeoutHandle);
+
+ // clean up
+ setTimeout(function() {
+ if (!s.iframeTarget)
+ $io.remove();
+ xhr.responseXML = null;
+ }, 100);
+ }
+
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+ if (window.ActiveXObject) {
+ doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML(s);
+ }
+ else {
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
+ }
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+ };
+ var parseJSON = $.parseJSON || function(s) {
+ return window['eval']('(' + s + ')');
+ };
+
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+
+ var ct = xhr.getResponseHeader('content-type') || '',
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if (xml && data.documentElement.nodeName === 'parsererror') {
+ $.error && $.error('parsererror');
+ }
+ if (s && s.dataFilter) {
+ data = s.dataFilter(data, type);
+ }
+ if (typeof data === 'string') {
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+ data = parseJSON(data);
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+ $.globalEval(data);
+ }
+ }
+ return data;
+ };
+ }
+};
+
+/**
+ * ajaxForm() provides a mechanism for fully automating form submission.
+ *
+ * The advantages of using this method instead of ajaxSubmit() are:
+ *
+ * 1: This method will include coordinates for <input type="image" /> elements (if the element
+ * is used to submit the form).
+ * 2. This method will include the submit element's name/value data (for the element that was
+ * used to submit the form).
+ * 3. This method binds the submit() method to the form for you.
+ *
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
+ * passes the options argument along after properly binding events for submit elements and
+ * the form itself.
+ */
+$.fn.ajaxForm = function(options) {
+ // in jQuery 1.3+ we can fix mistakes with the ready state
+ if (this.length === 0) {
+ var o = { s: this.selector, c: this.context };
+ if (!$.isReady && o.s) {
+ log('DOM not ready, queuing ajaxForm');
+ $(function() {
+ $(o.s,o.c).ajaxForm(options);
+ });
+ return this;
+ }
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+ return this;
+ }
+
+ return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
+ if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+ e.preventDefault();
+ $(this).ajaxSubmit(options);
+ }
+ }).bind('click.form-plugin', function(e) {
+ var target = e.target;
+ var $el = $(target);
+ if (!($el.is(":submit,input:image"))) {
+ // is this a child element of the submit el? (ex: a span within a button)
+ var t = $el.closest(':submit');
+ if (t.length == 0) {
+ return;
+ }
+ target = t[0];
+ }
+ var form = this;
+ form.clk = target;
+ if (target.type == 'image') {
+ if (e.offsetX != undefined) {
+ form.clk_x = e.offsetX;
+ form.clk_y = e.offsetY;
+ } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
+ var offset = $el.offset();
+ form.clk_x = e.pageX - offset.left;
+ form.clk_y = e.pageY - offset.top;
+ } else {
+ form.clk_x = e.pageX - target.offsetLeft;
+ form.clk_y = e.pageY - target.offsetTop;
+ }
+ }
+ // clear form vars
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+ });
+};
+
+// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
+$.fn.ajaxFormUnbind = function() {
+ return this.unbind('submit.form-plugin click.form-plugin');
+};
+
+/**
+ * formToArray() gathers form element data into an array of objects that can
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
+ * Each object in the array has both a 'name' and 'value' property. An example of
+ * an array for a simple login form might be:
+ *
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
+ *
+ * It is this array that is passed to pre-submit callback functions provided to the
+ * ajaxSubmit() and ajaxForm() methods.
+ */
+$.fn.formToArray = function(semantic) {
+ var a = [];
+ if (this.length === 0) {
+ return a;
+ }
+
+ var form = this[0];
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
+ if (!els) {
+ return a;
+ }
+
+ var i,j,n,v,el,max,jmax;
+ for(i=0, max=els.length; i < max; i++) {
+ el = els[i];
+ n = el.name;
+ if (!n) {
+ continue;
+ }
+
+ if (semantic && form.clk && el.type == "image") {
+ // handle image inputs on the fly when semantic == true
+ if(!el.disabled && form.clk == el) {
+ a.push({name: n, value: $(el).val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ continue;
+ }
+
+ v = $.fieldValue(el, true);
+ if (v && v.constructor == Array) {
+ for(j=0, jmax=v.length; j < jmax; j++) {
+ a.push({name: n, value: v[j]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: n, value: v});
+ }
+ }
+
+ if (!semantic && form.clk) {
+ // input type=='image' are not found in elements array! handle it here
+ var $input = $(form.clk), input = $input[0];
+ n = input.name;
+ if (n && !input.disabled && input.type == 'image') {
+ a.push({name: n, value: $input.val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ }
+ return a;
+};
+
+/**
+ * Serializes form data into a 'submittable' string. This method will return a string
+ * in the format: name1=value1&amp;name2=value2
+ */
+$.fn.formSerialize = function(semantic) {
+ //hand off to jQuery.param for proper encoding
+ return $.param(this.formToArray(semantic));
+};
+
+/**
+ * Serializes all field elements in the jQuery object into a query string.
+ * This method will return a string in the format: name1=value1&amp;name2=value2
+ */
+$.fn.fieldSerialize = function(successful) {
+ var a = [];
+ this.each(function() {
+ var n = this.name;
+ if (!n) {
+ return;
+ }
+ var v = $.fieldValue(this, successful);
+ if (v && v.constructor == Array) {
+ for (var i=0,max=v.length; i < max; i++) {
+ a.push({name: n, value: v[i]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: this.name, value: v});
+ }
+ });
+ //hand off to jQuery.param for proper encoding
+ return $.param(a);
+};
+
+/**
+ * Returns the value(s) of the element in the matched set. For example, consider the following form:
+ *
+ * <form><fieldset>
+ * <input name="A" type="text" />
+ * <input name="A" type="text" />
+ * <input name="B" type="checkbox" value="B1" />
+ * <input name="B" type="checkbox" value="B2"/>
+ * <input name="C" type="radio" value="C1" />
+ * <input name="C" type="radio" value="C2" />
+ * </fieldset></form>
+ *
+ * var v = $(':text').fieldValue();
+ * // if no values are entered into the text inputs
+ * v == ['','']
+ * // if values entered into the text inputs are 'foo' and 'bar'
+ * v == ['foo','bar']
+ *
+ * var v = $(':checkbox').fieldValue();
+ * // if neither checkbox is checked
+ * v === undefined
+ * // if both checkboxes are checked
+ * v == ['B1', 'B2']
+ *
+ * var v = $(':radio').fieldValue();
+ * // if neither radio is checked
+ * v === undefined
+ * // if first radio is checked
+ * v == ['C1']
+ *
+ * The successful argument controls whether or not the field element must be 'successful'
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
+ * The default value of the successful argument is true. If this value is false the value(s)
+ * for each element is returned.
+ *
+ * Note: This method *always* returns an array. If no valid value can be determined the
+ * array will be empty, otherwise it will contain one or more values.
+ */
+$.fn.fieldValue = function(successful) {
+ for (var val=[], i=0, max=this.length; i < max; i++) {
+ var el = this[i];
+ var v = $.fieldValue(el, successful);
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+ continue;
+ }
+ v.constructor == Array ? $.merge(val, v) : val.push(v);
+ }
+ return val;
+};
+
+/**
+ * Returns the value of the field element.
+ */
+$.fieldValue = function(el, successful) {
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+ if (successful === undefined) {
+ successful = true;
+ }
+
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+ tag == 'select' && el.selectedIndex == -1)) {
+ return null;
+ }
+
+ if (tag == 'select') {
+ var index = el.selectedIndex;
+ if (index < 0) {
+ return null;
+ }
+ var a = [], ops = el.options;
+ var one = (t == 'select-one');
+ var max = (one ? index+1 : ops.length);
+ for(var i=(one ? index : 0); i < max; i++) {
+ var op = ops[i];
+ if (op.selected) {
+ var v = op.value;
+ if (!v) { // extra pain for IE...
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
+ }
+ if (one) {
+ return v;
+ }
+ a.push(v);
+ }
+ }
+ return a;
+ }
+ return $(el).val();
+};
+
+/**
+ * Clears the form data. Takes the following actions on the form's input fields:
+ * - input text fields will have their 'value' property set to the empty string
+ * - select elements will have their 'selectedIndex' property set to -1
+ * - checkbox and radio inputs will have their 'checked' property set to false
+ * - inputs of type submit, button, reset, and hidden will *not* be effected
+ * - button elements will *not* be effected
+ */
+$.fn.clearForm = function() {
+ return this.each(function() {
+ $('input,select,textarea', this).clearFields();
+ });
+};
+
+/**
+ * Clears the selected form elements.
+ */
+$.fn.clearFields = $.fn.clearInputs = function() {
+ var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
+ return this.each(function() {
+ var t = this.type, tag = this.tagName.toLowerCase();
+ if (re.test(t) || tag == 'textarea') {
+ this.value = '';
+ }
+ else if (t == 'checkbox' || t == 'radio') {
+ this.checked = false;
+ }
+ else if (tag == 'select') {
+ this.selectedIndex = -1;
+ }
+ });
+};
+
+/**
+ * Resets the form data. Causes all form elements to be reset to their original value.
+ */
+$.fn.resetForm = function() {
+ return this.each(function() {
+ // guard against an input with the name of 'reset'
+ // note that IE reports the reset function as an 'object'
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+ this.reset();
+ }
+ });
+};
+
+/**
+ * Enables or disables any matching elements.
+ */
+$.fn.enable = function(b) {
+ if (b === undefined) {
+ b = true;
+ }
+ return this.each(function() {
+ this.disabled = !b;
+ });
+};
+
+/**
+ * Checks/unchecks any matching checkboxes or radio buttons and
+ * selects/deselects and matching option elements.
+ */
+$.fn.selected = function(select) {
+ if (select === undefined) {
+ select = true;
+ }
+ return this.each(function() {
+ var t = this.type;
+ if (t == 'checkbox' || t == 'radio') {
+ this.checked = select;
+ }
+ else if (this.tagName.toLowerCase() == 'option') {
+ var $sel = $(this).parent('select');
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
+ // deselect all other options
+ $sel.find('option').selected(false);
+ }
+ this.selected = select;
+ }
+ });
+};
+
+// helper fn for console logging
+function log() {
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ else if (window.opera && window.opera.postError) {
+ window.opera.postError(msg);
+ }
+};
+
+})(jQuery);
diff --git a/addons/web/static/lib/jquery.superfish/changelog.txt b/addons/web/static/lib/jquery.superfish/changelog.txt
new file mode 100644
index 00000000000..3399f057ec3
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/changelog.txt
@@ -0,0 +1,74 @@
+Changelog for Superfish - a jQuery menu plugin
+
+v1.2.1: altered 2nd July 07. added hide() before animate to make work for jQuery 1.1.3.
+
+v1.2.2: altered 2nd August 07. changed over function .find('ul') to .find('>ul') for smoother animations
+ Also deleted the iframe removal lines - not necessary it turns out
+
+v1.2.3: altered jquery 1.1.3.1 broke keyboard access - had to change quite a few things and set display:none on the
+ .superfish rule in CSS instead of top:-999em
+
+v1.3: Pretty much a complete overhaul to make all original features work in 1.1.3.1 and above.
+ .superfish rule reverted back to top:-999em (which is better).
+
+v1.3.1: altered 'li[ul]' to $('li:has(ul)') to work with jQuery 1.2
+
+v1.3.2: added onshow callback option as requested - 'this' keyword refers to revealed ul.
+ fixed bug whereby multiple menus on a page shared options. Now each menu can have separate options.
+ fixed IE6 and IE7 bug whereby under certain circumstances => 3rd tier menus appear instantly with text missing when revisited
+
+v1.3.3: altered event attachment selectors for performance increase on menu setup.
+
+v1.3.4: fixed pathClass bug as current path was not being restored. Still doesn't if using keyboard nav (will work on that).
+
+v1.4: store options objects in array $.superfish.o. Also provide public access to $.superfish.defaults
+ provided backward compat for jQuery versions less than 1.2 via oldJquery option - will use li[ul] or li:has(ul) as needed
+ added more callbacks, also added option to disable hoverIntent usage if that plugin is detected
+
+v1.4.1: fixed current path not being restored when using keyboard to tab away from the menu completely
+ optimised code further - now less code
+ removed addself() in favour of backward compatible add(this)
+ also remove new mouseenter/mouseleave events on window.unload (due to paranoia)
+
+v1.4.2: 3rd July 2008. added semi-colon at start of superfish.js file to avert script concatenation errors
+ added pathLevels option to limit the depth of submenus that get restored by pathClass
+ CSS of main example hugely simplified - other example CSS files less-so.
+ - top level menu items are not fixed width
+ - only need to set submenu widths in one place.
+ - various other improvements.
+ - class names used in all CSS files are changed to be less generic
+ released optional Supersubs plugin which dynamically adjusts submenu widths
+ attach everything to jQuery.fn.superfish to clean up jQuery namespace
+ removed the multi-tier-all-horizontal-example as it was never a great idea and doesn't seem to be in use
+ Update documentation text and remove certain caveats which were there to support users of much older versions of Superfish
+ Documentation now show how to apply bgIgrame 2.1 - it's much easier than before
+ Add all links and their focus and blur events to the onunload unbind - paranoid about memory leaks
+
+v1.4.3 5th July 2008. documentation completely redone using Mike Alsup's templates.
+ CSS revised so that all types of menu use superfish.css as a base. Include additional CSS files to acheive alternate styles.
+ class="sf-menu sf-vertical" creates vertical menu, class="sf-menu sf-navbar" creates nav-bar style menu
+
+v1.4.4 7th July 2008. arrows feature added. If option 'autoArrows' is true, auto-appends (spans) to anchors that have a ul submenu sibling,
+ and adds class 'sf-with-ul' to anchor.
+ CSS added to style new arrows, including an 8-bit alpha (NOT INDEXED!) transparent png of arrow - degrades to solid for IE6.
+ Manually add arrow mark-up to docs and disable autoArrows (via defaults option) to maintain decent performance (for docs page)
+ Update docs, including zip download, to suit.
+ Fix CSS bug that had the third tier of the navbar-style menu visible when JS not available.
+
+v1.4.5 9 July 2008. decreased code weight
+ added drop shadows for capable browsers - added css and 8-bit alpha transparent png image for shadow
+ remove support for jQuery v<1.2
+ remove unload clean-up which was there to solve garbage collection problems in early jQuery versions
+ remove toggling 'visibility' on hide and show which as a fix for an IE bug that is no longer exhibited
+ removed need for getOpts, rewrote getMenu
+ use [].join('') instead of string concatenation for performance increase - probably very slight in this case
+ change selector in 'over' function from '.'+o.hoverClass to 'li.'+o.hoverClass
+
+v1.4.6 added workaround for IE7 shadows. If animation alters opacity then shadow is hidden during the animation and appears after.
+ This required some JS and a line of CSS, so created shortcut references to lighten code further.
+
+v1.4.7 added back in the visibility toggle that was removed in 1.4.5 as the bug is indeed still exhibited by IE6 & 7
+ tweaked the look of the shadow slightly and use nicer 32bit png as I now find they behave the same as 8bit png with regard to fades in IE7
+
+v1.4.8 fix over-sight: using 32bit png meant that the shadow image did show in IE6. Rather than go back to 8bit, add code to exclude IE6 from getting shadow class.
+ use new folder structure recommended by Matt from TopicTrack, for easier updates. \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/css/superfish-navbar.css b/addons/web/static/lib/jquery.superfish/css/superfish-navbar.css
new file mode 100644
index 00000000000..68c713584aa
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/css/superfish-navbar.css
@@ -0,0 +1,93 @@
+
+/*** adding the class sf-navbar in addition to sf-menu creates an all-horizontal nav-bar menu ***/
+.sf-navbar {
+ background: #BDD2FF;
+ height: 2.5em;
+ padding-bottom: 2.5em;
+ position: relative;
+}
+.sf-navbar li {
+ background: #AABDE6;
+ position: static;
+}
+.sf-navbar a {
+ border-top: none;
+}
+.sf-navbar li ul {
+ width: 44em; /*IE6 soils itself without this*/
+}
+.sf-navbar li li {
+ background: #BDD2FF;
+ position: relative;
+}
+.sf-navbar li li ul {
+ width: 13em;
+}
+.sf-navbar li li li {
+ width: 100%;
+}
+.sf-navbar ul li {
+ width: auto;
+ float: left;
+}
+.sf-navbar a, .sf-navbar a:visited {
+ border: none;
+}
+.sf-navbar li.current {
+ background: #BDD2FF;
+}
+.sf-navbar li:hover,
+.sf-navbar li.sfHover,
+.sf-navbar li li.current,
+.sf-navbar a:focus, .sf-navbar a:hover, .sf-navbar a:active {
+ background: #BDD2FF;
+}
+.sf-navbar ul li:hover,
+.sf-navbar ul li.sfHover,
+ul.sf-navbar ul li:hover li,
+ul.sf-navbar ul li.sfHover li,
+.sf-navbar ul a:focus, .sf-navbar ul a:hover, .sf-navbar ul a:active {
+ background: #D1DFFF;
+}
+ul.sf-navbar li li li:hover,
+ul.sf-navbar li li li.sfHover,
+.sf-navbar li li.current li.current,
+.sf-navbar ul li li a:focus, .sf-navbar ul li li a:hover, .sf-navbar ul li li a:active {
+ background: #E6EEFF;
+}
+ul.sf-navbar .current ul,
+ul.sf-navbar ul li:hover ul,
+ul.sf-navbar ul li.sfHover ul {
+ left: 0;
+ top: 2.5em; /* match top ul list item height */
+}
+ul.sf-navbar .current ul ul {
+ top: -999em;
+}
+
+.sf-navbar li li.current > a {
+ font-weight: bold;
+}
+
+/*** point all arrows down ***/
+/* point right for anchors in subs */
+.sf-navbar ul .sf-sub-indicator { background-position: -10px -100px; }
+.sf-navbar ul a > .sf-sub-indicator { background-position: 0 -100px; }
+/* apply hovers to modern browsers */
+.sf-navbar ul a:focus > .sf-sub-indicator,
+.sf-navbar ul a:hover > .sf-sub-indicator,
+.sf-navbar ul a:active > .sf-sub-indicator,
+.sf-navbar ul li:hover > a > .sf-sub-indicator,
+.sf-navbar ul li.sfHover > a > .sf-sub-indicator {
+ background-position: -10px -100px; /* arrow hovers for modern browsers*/
+}
+
+/*** remove shadow on first submenu ***/
+.sf-navbar > li > ul {
+ background: transparent;
+ padding: 0;
+ -moz-border-radius-bottomleft: 0;
+ -moz-border-radius-topright: 0;
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-bottom-left-radius: 0;
+} \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/css/superfish-vertical.css b/addons/web/static/lib/jquery.superfish/css/superfish-vertical.css
new file mode 100644
index 00000000000..8025b7859f6
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/css/superfish-vertical.css
@@ -0,0 +1,23 @@
+/*** adding sf-vertical in addition to sf-menu creates a vertical menu ***/
+.sf-vertical, .sf-vertical li {
+ width: 10em;
+}
+/* this lacks ul at the start of the selector, so the styles from the main CSS file override it where needed */
+.sf-vertical li:hover ul,
+.sf-vertical li.sfHover ul {
+ left: 10em; /* match ul width */
+ top: 0;
+}
+
+/*** alter arrow directions ***/
+.sf-vertical .sf-sub-indicator { background-position: -10px 0; } /* IE6 gets solid image only */
+.sf-vertical a > .sf-sub-indicator { background-position: 0 0; } /* use translucent arrow for modern browsers*/
+
+/* hover arrow direction for modern browsers*/
+.sf-vertical a:focus > .sf-sub-indicator,
+.sf-vertical a:hover > .sf-sub-indicator,
+.sf-vertical a:active > .sf-sub-indicator,
+.sf-vertical li:hover > a > .sf-sub-indicator,
+.sf-vertical li.sfHover > a > .sf-sub-indicator {
+ background-position: -10px 0; /* arrow hovers for modern browsers*/
+} \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/css/superfish.css b/addons/web/static/lib/jquery.superfish/css/superfish.css
new file mode 100644
index 00000000000..cc33fdb4e7f
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/css/superfish.css
@@ -0,0 +1,136 @@
+
+/*** ESSENTIAL STYLES ***/
+.sf-menu, .sf-menu * {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+.sf-menu {
+ line-height: 1.0;
+}
+.sf-menu ul {
+ position: absolute;
+ top: -999em;
+ width: 10em; /* left offset of submenus need to match (see below) */
+}
+.sf-menu ul li {
+ width: 100%;
+}
+.sf-menu li:hover {
+ visibility: inherit; /* fixes IE7 'sticky bug' */
+}
+.sf-menu li {
+ float: left;
+ position: relative;
+}
+.sf-menu a {
+ display: block;
+ position: relative;
+}
+.sf-menu li:hover ul,
+.sf-menu li.sfHover ul {
+ left: 0;
+ top: 2.5em; /* match top ul list item height */
+ z-index: 99;
+}
+ul.sf-menu li:hover li ul,
+ul.sf-menu li.sfHover li ul {
+ top: -999em;
+}
+ul.sf-menu li li:hover ul,
+ul.sf-menu li li.sfHover ul {
+ left: 10em; /* match ul width */
+ top: 0;
+}
+ul.sf-menu li li:hover li ul,
+ul.sf-menu li li.sfHover li ul {
+ top: -999em;
+}
+ul.sf-menu li li li:hover ul,
+ul.sf-menu li li li.sfHover ul {
+ left: 10em; /* match ul width */
+ top: 0;
+}
+
+/*** DEMO SKIN ***/
+.sf-menu {
+ float: left;
+ margin-bottom: 1em;
+}
+.sf-menu a {
+ border-left: 1px solid #fff;
+ border-top: 1px solid #CFDEFF;
+ padding: .75em 1em;
+ text-decoration:none;
+}
+.sf-menu a, .sf-menu a:visited { /* visited pseudo selector so IE6 applies text colour*/
+ color: #13a;
+}
+.sf-menu li {
+ background: #BDD2FF;
+}
+.sf-menu li li {
+ background: #AABDE6;
+}
+.sf-menu li li li {
+ background: #9AAEDB;
+}
+.sf-menu li:hover, .sf-menu li.sfHover,
+.sf-menu a:focus, .sf-menu a:hover, .sf-menu a:active {
+ background: #CFDEFF;
+ outline: 0;
+}
+
+/*** arrows **/
+.sf-menu a.sf-with-ul {
+ padding-right: 2.25em;
+ min-width: 1px; /* trigger IE7 hasLayout so spans position accurately */
+}
+.sf-sub-indicator {
+ position: absolute;
+ display: block;
+ right: .75em;
+ top: 1.05em; /* IE6 only */
+ width: 10px;
+ height: 10px;
+ text-indent: -999em;
+ overflow: hidden;
+ background: url('../images/arrows-ffffff.png') no-repeat -10px -100px; /* 8-bit indexed alpha png. IE6 gets solid image only */
+}
+a > .sf-sub-indicator { /* give all except IE6 the correct values */
+ top: .8em;
+ background-position: 0 -100px; /* use translucent arrow for modern browsers*/
+}
+/* apply hovers to modern browsers */
+a:focus > .sf-sub-indicator,
+a:hover > .sf-sub-indicator,
+a:active > .sf-sub-indicator,
+li:hover > a > .sf-sub-indicator,
+li.sfHover > a > .sf-sub-indicator {
+ background-position: -10px -100px; /* arrow hovers for modern browsers*/
+}
+
+/* point right for anchors in subs */
+.sf-menu ul .sf-sub-indicator { background-position: -10px 0; }
+.sf-menu ul a > .sf-sub-indicator { background-position: 0 0; }
+/* apply hovers to modern browsers */
+.sf-menu ul a:focus > .sf-sub-indicator,
+.sf-menu ul a:hover > .sf-sub-indicator,
+.sf-menu ul a:active > .sf-sub-indicator,
+.sf-menu ul li:hover > a > .sf-sub-indicator,
+.sf-menu ul li.sfHover > a > .sf-sub-indicator {
+ background-position: -10px 0; /* arrow hovers for modern browsers*/
+}
+
+/*** shadows for all but IE6 ***/
+.sf-shadow ul {
+ background: url('../images/shadow.png') no-repeat bottom right;
+ padding: 0 8px 9px 0;
+ -moz-border-radius-bottomleft: 17px;
+ -moz-border-radius-topright: 17px;
+ -webkit-border-top-right-radius: 17px;
+ -webkit-border-bottom-left-radius: 17px;
+}
+.sf-shadow ul.sf-shadow-off {
+ background: transparent;
+}
diff --git a/addons/web/static/lib/jquery.superfish/example.html b/addons/web/static/lib/jquery.superfish/example.html
new file mode 100644
index 00000000000..58205271719
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/example.html
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+ <head>
+ <title>A very basic Superfish menu example</title>
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
+ <link rel="stylesheet" type="text/css" href="css/superfish.css" media="screen">
+ <script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
+ <script type="text/javascript" src="js/hoverIntent.js"></script>
+ <script type="text/javascript" src="js/superfish.js"></script>
+ <script type="text/javascript">
+
+ // initialise plugins
+ jQuery(function(){
+ jQuery('ul.sf-menu').superfish();
+ });
+
+ </script>
+ </head>
+ <body>
+ <ul class="sf-menu">
+ <li class="current">
+ <a href="#a">menu item</a>
+ <ul>
+ <li>
+ <a href="#aa">menu item that is quite long</a>
+ </li>
+ <li class="current">
+ <a href="#ab">menu item</a>
+ <ul>
+ <li class="current"><a href="#">menu item</a></li>
+ <li><a href="#aba">menu item</a></li>
+ <li><a href="#abb">menu item</a></li>
+ <li><a href="#abc">menu item</a></li>
+ <li><a href="#abd">menu item</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">short</a></li>
+ <li><a href="#">short</a></li>
+ <li><a href="#">short</a></li>
+ <li><a href="#">short</a></li>
+ <li><a href="#">short</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ <ul>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ <li><a href="#">menu item</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">menu item</a>
+ </li>
+ </ul>
+ </body>
+</html> \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/images/arrows-ffffff.png b/addons/web/static/lib/jquery.superfish/images/arrows-ffffff.png
new file mode 100644
index 00000000000..995df52065b
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/images/arrows-ffffff.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.superfish/images/shadow.png b/addons/web/static/lib/jquery.superfish/images/shadow.png
new file mode 100644
index 00000000000..c04d21b76ec
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/images/shadow.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.superfish/js/hoverIntent.js b/addons/web/static/lib/jquery.superfish/js/hoverIntent.js
new file mode 100644
index 00000000000..91da57b2448
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/js/hoverIntent.js
@@ -0,0 +1,84 @@
+(function($){
+ /* hoverIntent by Brian Cherne */
+ $.fn.hoverIntent = function(f,g) {
+ // default configuration options
+ var cfg = {
+ sensitivity: 7,
+ interval: 100,
+ timeout: 0
+ };
+ // override configuration options with user supplied object
+ cfg = $.extend(cfg, g ? { over: f, out: g } : f );
+
+ // instantiate variables
+ // cX, cY = current X and Y position of mouse, updated by mousemove event
+ // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
+ var cX, cY, pX, pY;
+
+ // A private function for getting mouse position
+ var track = function(ev) {
+ cX = ev.pageX;
+ cY = ev.pageY;
+ };
+
+ // A private function for comparing current and previous mouse position
+ var compare = function(ev,ob) {
+ ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+ // compare mouse positions to see if they've crossed the threshold
+ if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
+ $(ob).unbind("mousemove",track);
+ // set hoverIntent state to true (so mouseOut can be called)
+ ob.hoverIntent_s = 1;
+ return cfg.over.apply(ob,[ev]);
+ } else {
+ // set previous coordinates for next time
+ pX = cX; pY = cY;
+ // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
+ ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
+ }
+ };
+
+ // A private function for delaying the mouseOut function
+ var delay = function(ev,ob) {
+ ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+ ob.hoverIntent_s = 0;
+ return cfg.out.apply(ob,[ev]);
+ };
+
+ // A private function for handling mouse 'hovering'
+ var handleHover = function(e) {
+ // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
+ var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
+ while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
+ if ( p == this ) { return false; }
+
+ // copy objects to be passed into t (required for event object to be passed in IE)
+ var ev = jQuery.extend({},e);
+ var ob = this;
+
+ // cancel hoverIntent timer if it exists
+ if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
+
+ // else e.type == "onmouseover"
+ if (e.type == "mouseover") {
+ // set "previous" X and Y position based on initial entry point
+ pX = ev.pageX; pY = ev.pageY;
+ // update "current" X and Y position based on mousemove
+ $(ob).bind("mousemove",track);
+ // start polling interval (self-calling timeout) to compare mouse coordinates over time
+ if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
+
+ // else e.type == "onmouseout"
+ } else {
+ // unbind expensive mousemove event
+ $(ob).unbind("mousemove",track);
+ // if hoverIntent state is true, then call the mouseOut function after the specified delay
+ if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
+ }
+ };
+
+ // bind the function to the two event listeners
+ return this.mouseover(handleHover).mouseout(handleHover);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/js/jquery-1.2.6.min.js b/addons/web/static/lib/jquery.superfish/js/jquery-1.2.6.min.js
new file mode 100644
index 00000000000..82b98e1d766
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/js/jquery-1.2.6.min.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})(); \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/js/jquery.bgiframe.min.js b/addons/web/static/lib/jquery.superfish/js/jquery.bgiframe.min.js
new file mode 100644
index 00000000000..b5af5204322
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/js/jquery.bgiframe.min.js
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-06-19 20:25:28 -0500 (Tue, 19 Jun 2007) $
+ * $Rev: 2111 $
+ *
+ * Version 2.1
+ */
+(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&parseInt($.browser.version)<=6){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};if(!$.browser.version)$.browser.version=navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1];})(jQuery); \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.superfish/js/superfish.js b/addons/web/static/lib/jquery.superfish/js/superfish.js
new file mode 100644
index 00000000000..c6a9c7de045
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/js/superfish.js
@@ -0,0 +1,121 @@
+
+/*
+ * Superfish v1.4.8 - jQuery menu widget
+ * Copyright (c) 2008 Joel Birch
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
+ */
+
+;(function($){
+ $.fn.superfish = function(op){
+
+ var sf = $.fn.superfish,
+ c = sf.c,
+ $arrow = $(['<span class="',c.arrowClass,'"> &#187;</span>'].join('')),
+ over = function(){
+ var $$ = $(this), menu = getMenu($$);
+ clearTimeout(menu.sfTimer);
+ $$.showSuperfishUl().siblings().hideSuperfishUl();
+ },
+ out = function(){
+ var $$ = $(this), menu = getMenu($$), o = sf.op;
+ clearTimeout(menu.sfTimer);
+ menu.sfTimer=setTimeout(function(){
+ o.retainPath=($.inArray($$[0],o.$path)>-1);
+ $$.hideSuperfishUl();
+ if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}
+ },o.delay);
+ },
+ getMenu = function($menu){
+ var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
+ sf.op = sf.o[menu.serial];
+ return menu;
+ },
+ addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };
+
+ return this.each(function() {
+ var s = this.serial = sf.o.length;
+ var o = $.extend({},sf.defaults,op);
+ o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
+ $(this).addClass([o.hoverClass,c.bcClass].join(' '))
+ .filter('li:has(ul)').removeClass(o.pathClass);
+ });
+ sf.o[s] = sf.op = o;
+
+ $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {
+ if (o.autoArrows) addArrow( $('>a:first-child',this) );
+ })
+ .not('.'+c.bcClass)
+ .hideSuperfishUl();
+
+ var $a = $('a',this);
+ $a.each(function(i){
+ var $li = $a.eq(i).parents('li');
+ $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
+ });
+ o.onInit.call(this);
+
+ }).each(function() {
+ var menuClasses = [c.menuClass];
+ if (sf.op.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);
+ $(this).addClass(menuClasses.join(' '));
+ });
+ };
+
+ var sf = $.fn.superfish;
+ sf.o = [];
+ sf.op = {};
+ sf.IE7fix = function(){
+ var o = sf.op;
+ if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)
+ this.toggleClass(sf.c.shadowClass+'-off');
+ };
+ sf.c = {
+ bcClass : 'sf-breadcrumb',
+ menuClass : 'sf-js-enabled',
+ anchorClass : 'sf-with-ul',
+ arrowClass : 'sf-sub-indicator',
+ shadowClass : 'sf-shadow'
+ };
+ sf.defaults = {
+ hoverClass : 'sfHover',
+ pathClass : 'overideThisToUse',
+ pathLevels : 1,
+ delay : 800,
+ animation : {opacity:'show'},
+ speed : 'normal',
+ autoArrows : true,
+ dropShadows : true,
+ disableHI : false, // true disables hoverIntent detection
+ onInit : function(){}, // callback functions
+ onBeforeShow: function(){},
+ onShow : function(){},
+ onHide : function(){}
+ };
+ $.fn.extend({
+ hideSuperfishUl : function(){
+ var o = sf.op,
+ not = (o.retainPath===true) ? o.$path : '';
+ o.retainPath = false;
+ var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)
+ .find('>ul').hide().css('visibility','hidden');
+ o.onHide.call($ul);
+ return this;
+ },
+ showSuperfishUl : function(){
+ var o = sf.op,
+ sh = sf.c.shadowClass+'-off',
+ $ul = this.addClass(o.hoverClass)
+ .find('>ul:hidden').css('visibility','visible');
+ sf.IE7fix.call($ul);
+ o.onBeforeShow.call($ul);
+ $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });
+ return this;
+ }
+ });
+
+})(jQuery);
diff --git a/addons/web/static/lib/jquery.superfish/js/supersubs.js b/addons/web/static/lib/jquery.superfish/js/supersubs.js
new file mode 100644
index 00000000000..45221510fc9
--- /dev/null
+++ b/addons/web/static/lib/jquery.superfish/js/supersubs.js
@@ -0,0 +1,90 @@
+
+/*
+ * Supersubs v0.2b - jQuery plugin
+ * Copyright (c) 2008 Joel Birch
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ *
+ * This plugin automatically adjusts submenu widths of suckerfish-style menus to that of
+ * their longest list item children. If you use this, please expect bugs and report them
+ * to the jQuery Google Group with the word 'Superfish' in the subject line.
+ *
+ */
+
+;(function($){ // $ will refer to jQuery within this closure
+
+ $.fn.supersubs = function(options){
+ var opts = $.extend({}, $.fn.supersubs.defaults, options);
+ // return original object to support chaining
+ return this.each(function() {
+ // cache selections
+ var $$ = $(this);
+ // support metadata
+ var o = $.meta ? $.extend({}, opts, $$.data()) : opts;
+ // get the font size of menu.
+ // .css('fontSize') returns various results cross-browser, so measure an em dash instead
+ var fontsize = $('<li id="menu-fontsize">&#8212;</li>').css({
+ 'padding' : 0,
+ 'position' : 'absolute',
+ 'top' : '-999em',
+ 'width' : 'auto'
+ }).appendTo($$).width(); //clientWidth is faster, but was incorrect here
+ // remove em dash
+ $('#menu-fontsize').remove();
+ // cache all ul elements
+ $ULs = $$.find('ul');
+ // loop through each ul in menu
+ $ULs.each(function(i) {
+ // cache this ul
+ var $ul = $ULs.eq(i);
+ // get all (li) children of this ul
+ var $LIs = $ul.children();
+ // get all anchor grand-children
+ var $As = $LIs.children('a');
+ // force content to one line and save current float property
+ var liFloat = $LIs.css('white-space','nowrap').css('float');
+ // remove width restrictions and floats so elements remain vertically stacked
+ var emWidth = $ul.add($LIs).add($As).css({
+ 'float' : 'none',
+ 'width' : 'auto'
+ })
+ // this ul will now be shrink-wrapped to longest li due to position:absolute
+ // so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer
+ .end().end()[0].clientWidth / fontsize;
+ // add more width to ensure lines don't turn over at certain sizes in various browsers
+ emWidth += o.extraWidth;
+ // restrict to at least minWidth and at most maxWidth
+ if (emWidth > o.maxWidth) { emWidth = o.maxWidth; }
+ else if (emWidth < o.minWidth) { emWidth = o.minWidth; }
+ emWidth += 'em';
+ // set ul to width in ems
+ $ul.css('width',emWidth);
+ // restore li floats to avoid IE bugs
+ // set li width to full width of this ul
+ // revert white-space to normal
+ $LIs.css({
+ 'float' : liFloat,
+ 'width' : '100%',
+ 'white-space' : 'normal'
+ })
+ // update offset position of descendant ul to reflect new width of parent
+ .each(function(){
+ var $childUl = $('>ul',this);
+ var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
+ $childUl.css(offsetDirection,emWidth);
+ });
+ });
+
+ });
+ };
+ // expose defaults
+ $.fn.supersubs.defaults = {
+ minWidth : 9, // requires em unit.
+ maxWidth : 25, // requires em unit.
+ extraWidth : 0 // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values
+ };
+
+})(jQuery); // plugin code ends
diff --git a/addons/web/static/lib/jquery.ui.notify/css/ui.notify.css b/addons/web/static/lib/jquery.ui.notify/css/ui.notify.css
new file mode 100644
index 00000000000..dcd2823b9d1
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui.notify/css/ui.notify.css
@@ -0,0 +1,13 @@
+.ui-notify { width:350px; position:fixed; top:10px; right:10px; }
+.ui-notify-message { padding:10px; margin-bottom:15px; -moz-border-radius:8px; -webkit-border-radius:8px; border-radius:8px }
+.ui-notify-message h1 { font-size:14px; margin:0; padding:0 }
+.ui-notify-message p { margin:3px 0; padding:0; line-height:18px }
+.ui-notify-message:last-child { margin-bottom:0 }
+.ui-notify-message-style { background:#000; background:rgba(0,0,0,0.8); -moz-box-shadow: 0 0 6px #000; -webkit-box-shadow: 0 0 6px #000; box-shadow: 0 0 6px #000; }
+.ui-notify-message-style h1 { color:#fff; font-weight:bold }
+.ui-notify-message-style p { color:#fff }
+.ui-notify-close { color:#fff; text-decoration:underline }
+.ui-notify-click { cursor:pointer }
+.ui-notify-cross { margin-top:-4px; float:right; cursor:pointer; text-decoration:none; font-size:12px; font-weight:bold; text-shadow:0 1px 1px #fff; padding:2px }
+.ui-notify-cross:hover { color:#ffffab }
+.ui-notify-cross:active { position:relative; top:1px }
diff --git a/addons/web/static/lib/jquery.ui.notify/js/jquery.notify.js b/addons/web/static/lib/jquery.ui.notify/js/jquery.notify.js
new file mode 100644
index 00000000000..c2c4657f4c2
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui.notify/js/jquery.notify.js
@@ -0,0 +1,140 @@
+/*
+ * jQuery Notify UI Widget 1.4
+ * Copyright (c) 2010 Eric Hynds
+ *
+ * http://www.erichynds.com/jquery/a-jquery-ui-growl-ubuntu-notification-widget/
+ *
+ * Depends:
+ * - jQuery 1.4
+ * - jQuery UI 1.8 widget factory
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+*/
+(function($){
+
+$.widget("ech.notify", {
+ options: {
+ speed: 500,
+ expires: 5000,
+ stack: 'below',
+ custom: false
+ },
+ _create: function(){
+ var self = this;
+ this.templates = {};
+ this.keys = [];
+
+ // build and save templates
+ this.element.addClass("ui-notify").children().addClass("ui-notify-message ui-notify-message-style").each(function(i){
+ var key = this.id || i;
+ self.keys.push(key);
+ self.templates[key] = $(this).removeAttr("id").wrap("<div></div>").parent().html(); // because $(this).andSelf().html() no workie
+ }).end().empty().show();
+ },
+ create: function(template, msg, opts){
+ if(typeof template === "object"){
+ opts = msg;
+ msg = template;
+ template = null;
+ }
+
+ var tpl = this.templates[ template || this.keys[0]];
+
+ // remove default styling class if rolling w/ custom classes
+ if(opts && opts.custom){
+ tpl = $(tpl).removeClass("ui-notify-message-style").wrap("<div></div>").parent().html();
+ }
+
+ // return a new notification instance
+ return new $.ech.notify.instance(this)._create(msg, $.extend({}, this.options, opts), tpl);
+ }
+});
+
+// instance constructor
+$.extend($.ech.notify, {
+ instance: function(widget){
+ this.parent = widget;
+ this.isOpen = false;
+ }
+});
+
+// instance methods
+$.extend($.ech.notify.instance.prototype, {
+ _create: function(params, options, template){
+ this.options = options;
+
+ var self = this,
+
+ // build html template
+ html = template.replace(/#(?:\{|%7B)(.*?)(?:\}|%7D)/g, function($1, $2){
+ return ($2 in params) ? params[$2] : '';
+ }),
+
+ // the actual message
+ m = (this.element = $(html)),
+
+ // close link
+ closelink = m.find(".ui-notify-close");
+
+ // clickable?
+ if(typeof this.options.click === "function"){
+ m.addClass("ui-notify-click").bind("click", function(e){
+ self._trigger("click", e, self);
+ });
+ }
+
+ // show close link?
+ if(closelink.length){
+ closelink.bind("click", function(){
+ self.close();
+ return false;
+ });
+ }
+
+ this.open();
+
+ // auto expire?
+ if(typeof options.expires === "number"){
+ window.setTimeout(function(){
+ self.close();
+ }, options.expires);
+ }
+
+ return this;
+ },
+ close: function(){
+ var self = this, speed = this.options.speed;
+
+ this.element.fadeTo(speed, 0).slideUp(speed, function(){
+ self._trigger("close");
+ self.isOpen = false;
+ });
+
+ return this;
+ },
+ open: function(){
+ if(this.isOpen || this._trigger("beforeopen") === false){
+ return this;
+ }
+
+ var self = this;
+
+ this.element[this.options.stack === 'above' ? 'prependTo' : 'appendTo'](this.parent.element).css({ display:"none", opacity:"" }).fadeIn(this.options.speed, function(){
+ self._trigger("open");
+ self.isOpen = true;
+ });
+
+ return this;
+ },
+ widget: function(){
+ return this.element;
+ },
+ _trigger: function(type, e, instance){
+ return this.parent._trigger.call( this, type, e, instance );
+ }
+});
+
+})(jQuery);
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644
index 00000000000..5b5dab2ab7b
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 00000000000..ac8b229af95
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 00000000000..ad3d6346e00
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 00000000000..42ccba269b6
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 00000000000..5a46b47cb16
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 00000000000..86c2baa655e
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 00000000000..4443fdc1a15
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 00000000000..7c9fa6c6edc
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_222222_256x240.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_222222_256x240.png
new file mode 100644
index 00000000000..b273ff111d2
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_2e83ff_256x240.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 00000000000..09d1cdc856c
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_454545_256x240.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_454545_256x240.png
new file mode 100644
index 00000000000..59bd45b907c
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_888888_256x240.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_888888_256x240.png
new file mode 100644
index 00000000000..6d02426c114
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_cd0a0a_256x240.png b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 00000000000..2ab019b73ec
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/addons/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css b/addons/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css
new file mode 100644
index 00000000000..fd5057b2f6d
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css
@@ -0,0 +1,573 @@
+/*
+ * jQuery UI CSS Framework 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*
+ * jQuery UI CSS Framework 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
+ * jQuery UI Resizable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
+ * jQuery UI Selectable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+/*
+ * jQuery UI Accordion 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion { width: 100%; }
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
+.ui-accordion .ui-accordion-content-active { display: block; }
+/*
+ * jQuery UI Autocomplete 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete { position: absolute; cursor: default; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.9
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+ float: left;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
+/*
+ * jQuery UI Button 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+/*
+ * jQuery UI Dialog 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/*
+ * jQuery UI Slider 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
+ * jQuery UI Tabs 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
+/*
+ * jQuery UI Datepicker 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}/*
+ * jQuery UI Progressbar 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js b/addons/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js
new file mode 100644
index 00000000000..45cc2744f16
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js
@@ -0,0 +1,781 @@
+/*!
+ * jQuery UI 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.9",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,
+NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,
+"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
+if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
+"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,
+d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
+c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&
+b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
+;/*!
+ * jQuery UI Widget 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
+a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;
+e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,
+this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},
+widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},
+enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
+;/*!
+ * jQuery UI Mouse 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ */
+(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(true===c.data(b.target,a.widgetName+".preventClickEvent")){c.removeData(b.target,a.widgetName+".preventClickEvent");b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=
+a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=
+this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);
+return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+".preventClickEvent",
+true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
+;/*
+ * jQuery UI Position 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
+left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
+m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
+d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
+a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
+g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
+;/*
+ * jQuery UI Draggable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
+"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
+this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-
+this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();
+d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||
+this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&
+this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==
+a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
+0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
+this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-
+(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==
+"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[(a.containment=="document"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment=="document"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?
+0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),
+10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==
+Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():
+f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;
+if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/
+b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-
+this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=
+this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.9"});
+d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=
+0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=
+c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,
+true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=
+0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=
+a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},
+stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=
+document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-
+c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-
+(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable",
+"snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=
+c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",
+{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,
+left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,
+a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,
+b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
+;/*
+ * jQuery UI Droppable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Droppables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ * jquery.ui.draggable.js
+ */
+(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
+a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
+this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
+this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
+d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
+a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.9"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
+switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
+i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
+"none";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e=="mousedown"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
+a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=
+d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);
+;/*
+ * jQuery UI Resizable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
+_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
+top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
+this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
+nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
+String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
+this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
+if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
+d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
+this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
+this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
+b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
+f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
+b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
+a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
+k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
+c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
+this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
+arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
+{version:"1.8.9"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
+function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
+(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
+false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
+a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
+b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
+"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
+f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
+a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
+e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
+height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
+d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
+;/*
+ * jQuery UI Selectable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),
+selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,
+c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",
+c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=
+this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
+a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&
+!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=
+e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.9"})})(jQuery);
+;/*
+ * jQuery UI Sortable 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Sortables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
+this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,
+arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
+c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
+{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
+if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
+a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
+if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+
+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+
+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+
+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
+c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
+document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-
+1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});
+this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&
+a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?
+"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?
+c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;
+return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=
+d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});
+return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=
+d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=
+this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=
+e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];
+if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);
+c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===
+1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=
+this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):
+b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==
+""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=
+this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),
+10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions=
+{width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||
+document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,
+b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=
+document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():
+e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-
+this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<
+this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&
+this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=
+this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();
+this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],
+this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",
+g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||
+this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,
+originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.9"})})(jQuery);
+;/*
+ * jQuery UI Accordion 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
+a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
+if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",
+function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+
+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");
+this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
+b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
+a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
+c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
+if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
+if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(),
+e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight||
+e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",
+tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.9",animations:{slide:function(a,b){a=
+c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);f[i]={value:j[1],
+unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide",
+paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
+;/*
+ * jQuery UI Autocomplete 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function(d){d.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,f;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){f=false;var e=d.ui.keyCode;
+switch(c.keyCode){case e.PAGE_UP:a._move("previousPage",c);break;case e.PAGE_DOWN:a._move("nextPage",c);break;case e.UP:a._move("previous",c);c.preventDefault();break;case e.DOWN:a._move("next",c);c.preventDefault();break;case e.ENTER:case e.NUMPAD_ENTER:if(a.menu.active){f=true;c.preventDefault()}case e.TAB:if(!a.menu.active)return;a.menu.select(c);break;case e.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem=
+null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(f){f=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||
+"body",b)[0]).mousedown(function(c){var e=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(g){g.target!==a.element[0]&&g.target!==e&&!d.ui.contains(e,g.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,e){e=e.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:e})&&/^key/.test(c.originalEvent.type)&&a.element.val(e.value)},selected:function(c,e){var g=e.item.data("item.autocomplete"),
+h=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=h;setTimeout(function(){a.previous=h;a.selectedItem=g},1)}false!==a._trigger("select",c,{item:g})&&a.element.val(g.value);a.term=a.element.val();a.close(c);a.selectedItem=g},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");
+this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,f;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,e){e(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source===
+"string"){f=this.options.source;this.source=function(c,e){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:f,data:c,dataType:"json",success:function(g,h,i){i===a.xhr&&e(g);a.xhr=null},error:function(g){g===a.xhr&&e([]);a.xhr=null}})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;
+this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==
+this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position))},
+_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var f=this;d.each(b,function(c,e){f._renderItem(a,e)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);
+else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(a,b){var f=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return f.test(c.label||c.value||c)})}})})(jQuery);
+(function(d){d.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(d(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
+-1).mouseenter(function(b){a.activate(b,d(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var f=b.offset().top-this.element.offset().top,c=this.element.attr("scrollTop"),e=this.element.height();if(f<0)this.element.attr("scrollTop",c+f);else f>=e&&this.element.attr("scrollTop",c+f-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})},
+deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,f){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);
+a.length?this.activate(f,a):this.activate(f,this.element.children(b))}else this.activate(f,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(".ui-menu-item:first"));else{var b=this.active.offset().top,f=this.element.height(),c=this.element.children(".ui-menu-item").filter(function(){var e=d(this).offset().top-b-f+d(this).height();return e<10&&e>-10});c.length||(c=this.element.children(".ui-menu-item:last"));this.activate(a,
+c)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(".ui-menu-item:last"));else{var b=this.active.offset().top,f=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-b+f-d(this).height();return c<10&&c>-10});result.length||(result=this.element.children(".ui-menu-item:first"));
+this.activate(a,result)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
+;/*
+ * jQuery UI Button 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",
+i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",
+function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");
+b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");
+g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",
+c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("label[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=
+this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||
+this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
+true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
+c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary");
+this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()},
+destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
+;/*
+ * jQuery UI Dialog 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.button.js
+ * jquery.ui.draggable.js
+ * jquery.ui.mouse.js
+ * jquery.ui.position.js
+ * jquery.ui.resizable.js
+ */
+(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&
+c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||"&#160;",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",
+-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role",
+"button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=
+b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&
+a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0]){e=c(this).css("z-index");
+isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);
+d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}});
+c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f,
+h){h=c.isFunction(h)?{click:h,text:f}:h;f=c('<button type="button"></button>').attr(h,true).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=
+d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,
+position:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f,
+h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===
+1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in
+l)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled");
+break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||"&#160;"));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e=
+this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(":data(resizable)")&&
+this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.9",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===
+0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),
+height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
+b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,
+function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
+;/*
+ * jQuery UI Slider 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");a.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
+this.range=d([]);if(a.range){if(a.range===true){this.range=d("<div></div>");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
+if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length<a.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();
+else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
+false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
+b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
+this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b,
+g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},
+_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;
+if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=
+this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c<e))c=e;if(c!==this.values(a)){e=this.values();e[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:e});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],
+value:c});b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value=
+this._trimAlignValue(b);this._refreshValue();this._change(null,0)}return this._value()},values:function(b,a){var c,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b):this.value();
+else return this._values()},_setOption:function(b,a){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
+this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b];
+return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},
+_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate);
+if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1,
+1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.9"})})(jQuery);
+;/*
+ * jQuery UI Tabs 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&&
+e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=
+d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
+(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
+this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
+this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
+if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
+this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+
+g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",
+function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};
+this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=
+-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";
+d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=
+d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,
+e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);
+j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();
+if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null,
+this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},
+load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,
+"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},
+url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.9"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&
+a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
+;/*
+ * jQuery UI Datepicker 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker
+ *
+ * Depends:
+ * jquery.ui.core.js
+ */
+(function(d,G){function K(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
+"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
+"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
+minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}function E(a,b){d.extend(a,b);for(var c in b)if(b[c]==
+null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.9"}});var y=(new Date).getTime();d.extend(K.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();
+f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},
+_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&
+b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==
+""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,
+c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),
+true);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});
+b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);
+this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",
+this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,
+function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:
+f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},
+e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);
+this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]?
+d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||
+a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,
+e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,
+"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},
+_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=
+d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,
+c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&
+d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a));var e=a.dpDiv.find("iframe.ui-datepicker-cover");e.length&&e.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",
+function(){d(this).removeClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=
+-1&&d(this).addClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,
+"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus();if(a.yearshtml){var f=a.yearshtml;setTimeout(function(){f===a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);f=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},
+_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-
+g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?
+b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},
+_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):
+0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=
+false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=
+d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);
+else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=
+a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,
+g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){var v=o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&v?4:p=="o"?3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,v,H){p=o(p)?H:v;for(v=0;v<p.length;v++)if(b.substr(s,p[v].length).toLowerCase()==p[v].toLowerCase()){s+=p[v].length;return v+1}throw"Unknown name at position "+
+s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(k)if(a.charAt(z)=="'"&&!o("'"))k=false;else r();else switch(a.charAt(z)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var w=new Date(m("@"));c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;case "!":w=new Date((m("!")-this._ticksTo1970)/1E4);c=w.getFullYear();j=w.getMonth()+
+1;l=w.getDate();break;case "'":if(o("'"))r();else k=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}w=this._daylightSavingAdjust(new Date(c,j-1,l));if(w.getFullYear()!=c||w.getMonth()+1!=j||w.getDate()!=l)throw"Invalid date";return w},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",
+RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&
+a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",
+b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+=
+"0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=
+f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=
+(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,
+l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=
+a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),
+b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=
+this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+
+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+
+(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>";j=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,
+"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=
+this._get(a,"monthNames"),w=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),v=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var L=this._getDefaultDate(a),I="",C=0;C<i[0];C++){for(var M="",D=0;D<i[1];D++){var N=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-
+1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,C>0||D>0,z,w)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=
+(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+="<tr>";var P=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=
+p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,J=B&&!H||!F[0]||k&&q<k||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==N.getTime()&&g==a.selectedMonth&&a._keyEvent||L.getTime()==q.getTime()&&L.getTime()==N.getTime()?" "+this._dayOverClass:"")+(J?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!v?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":
+""))+'"'+((!B||v)&&F[2]?' title="'+F[2]+'"':"")+(J?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!v?"&#xa0;":J?'<span class="ui-state-default">'+q.getDate()+"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==u.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=
+P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");M+=x}I+=M}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',
+o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&
+l)?"&#xa0;":""));a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+
+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";if(d.browser.mozilla)k+='<select class="ui-datepicker-year"><option value="'+c+'" selected="selected">'+c+"</option></select>";else{k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?"&#xa0;":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=
+a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,
+"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);
+c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,
+"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
+function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
+return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new K;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.9";window["DP_jQuery_"+y]=d})(jQuery);
+;/*
+ * jQuery UI Progressbar 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
+this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*
+this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.9"})})(jQuery);
+;/*
+ * jQuery UI Effects 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/
+ */
+jQuery.effects||function(f,j){function n(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
+16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return o.transparent;return o[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return n(b)}function p(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
+a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function q(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
+a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function m(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",
+"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=n(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var o={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,
+0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,
+211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},r=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,
+d){if(f.isFunction(b)){d=b;b=null}return this.queue("fx",function(){var e=f(this),g=e.attr("style")||" ",h=q(p.call(this)),l,v=e.attr("className");f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});l=q(p.call(this));e.attr("className",v);e.animate(u(h,l),a,b,function(){f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)});h=f.queue(this);l=h.splice(h.length-1,1)[0];
+h.splice(1,0,l);f.dequeue(this)})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,
+a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.9",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,
+a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",
+border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);
+return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments);
+else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),
+b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,
+a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,
+a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==
+e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=
+g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/
+h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,
+a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
+;/*
+ * jQuery UI Effects Blind 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Blind
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","bottom","left","right"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,
+g);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
+;/*
+ * jQuery UI Effects Bounce 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Bounce
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","bottom","left","right"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
+3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
+b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
+;/*
+ * jQuery UI Effects Clip 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Clip
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","bottom","left","right","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,
+c/2)}var h={};h[g.size]=f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Drop 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Drop
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e==
+"show"?1:0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Explode 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Explode
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
+0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
+e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
+;/*
+ * jQuery UI Effects Fade 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Fade
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Fold 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Fold
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],
+10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
+;/*
+ * jQuery UI Effects Highlight 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Highlight
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
+this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Pulsate 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Pulsate
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
+a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
+;/*
+ * jQuery UI Effects Scale 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Scale
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
+b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
+1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],g=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],
+p=c.effects.setMode(a,b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};
+if(m=="box"||m=="both"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);
+a.css("overflow","hidden").css(a.from);if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);
+child.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,
+n?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Shake 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Shake
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","bottom","left","right"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=
+(h=="pos"?"-=":"+=")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
+;/*
+ * jQuery UI Effects Slide 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Slide
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e);
+var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
+;/*
+ * jQuery UI Effects Transfer 1.8.9
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Transfer
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
+b.dequeue()})})}})(jQuery);
+; \ No newline at end of file
diff --git a/addons/web/static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js b/addons/web/static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js
new file mode 100644
index 00000000000..85c795c2e79
--- /dev/null
+++ b/addons/web/static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js
@@ -0,0 +1,911 @@
+/*
+* jQuery timepicker addon
+* By: Trent Richardson [http://trentrichardson.com]
+* Version 0.9.3
+* Last Modified: 02/05/2011
+*
+* Copyright 2010 Trent Richardson
+* Dual licensed under the MIT and GPL licenses.
+* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
+* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
+*
+* HERES THE CSS:
+* .ui-timepicker-div .ui-widget-header{ margin-bottom: 8px; }
+* .ui-timepicker-div dl{ text-align: left; }
+* .ui-timepicker-div dl dt{ height: 25px; }
+* .ui-timepicker-div dl dd{ margin: -25px 0 10px 65px; }
+* .ui-timepicker-div td { font-size: 90%; }
+*/
+
+(function($) {
+
+$.extend($.ui, { timepicker: { version: "0.9.3" } });
+
+/* Time picker manager.
+ Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+ Settings for (groups of) time pickers are maintained in an instance object,
+ allowing multiple different settings on the same page. */
+
+function Timepicker() {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ currentText: 'Now',
+ closeText: 'Done',
+ ampm: false,
+ timeFormat: 'hh:mm tt',
+ timeOnlyTitle: 'Choose Time',
+ timeText: 'Time',
+ hourText: 'Hour',
+ minuteText: 'Minute',
+ secondText: 'Second'
+ };
+ this._defaults = { // Global defaults for all the datetime picker instances
+ showButtonPanel: true,
+ timeOnly: false,
+ showHour: true,
+ showMinute: true,
+ showSecond: false,
+ showTime: true,
+ stepHour: 0.05,
+ stepMinute: 0.05,
+ stepSecond: 0.05,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ hourMin: 0,
+ minuteMin: 0,
+ secondMin: 0,
+ hourMax: 23,
+ minuteMax: 59,
+ secondMax: 59,
+ minDateTime: null,
+ maxDateTime: null,
+ hourGrid: 0,
+ minuteGrid: 0,
+ secondGrid: 0,
+ alwaysSetTime: true,
+ separator: ' ',
+ altFieldTimeOnly: true,
+ showTimepicker: true
+ };
+ $.extend(this._defaults, this.regional['']);
+}
+
+$.extend(Timepicker.prototype, {
+ $input: null,
+ $altInput: null,
+ $timeObj: null,
+ inst: null,
+ hour_slider: null,
+ minute_slider: null,
+ second_slider: null,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ hourMinOriginal: null,
+ minuteMinOriginal: null,
+ secondMinOriginal: null,
+ hourMaxOriginal: null,
+ minuteMaxOriginal: null,
+ secondMaxOriginal: null,
+ ampm: '',
+ formattedDate: '',
+ formattedTime: '',
+ formattedDateTime: '',
+
+ /* Override the default settings for all instances of the time picker.
+ @param settings object - the new settings to use as defaults (anonymous object)
+ @return the manager object */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ //########################################################################
+ // Create a new Timepicker instance
+ //########################################################################
+ _newInst: function($input, o) {
+ var tp_inst = new Timepicker(),
+ inlineSettings = {};
+
+ tp_inst.hour = tp_inst._defaults.hour;
+ tp_inst.minute = tp_inst._defaults.minute;
+ tp_inst.second = tp_inst._defaults.second;
+ tp_inst.ampm = '';
+ tp_inst.$input = $input;
+
+
+ for (var attrName in this._defaults) {
+ var attrValue = $input.attr('time:' + attrName);
+ if (attrValue) {
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, {
+ beforeShow: function(input, dp_inst) {
+ if ($.isFunction(o.beforeShow))
+ o.beforeShow(input, dp_inst, tp_inst);
+ },
+ onChangeMonthYear: function(year, month, dp_inst) {
+ // Update the time as well : this prevents the time from disappearing from the $input field.
+ tp_inst._updateDateTime(dp_inst);
+ if ($.isFunction(o.onChangeMonthYear))
+ o.onChangeMonthYear(year, month, dp_inst, tp_inst);
+ },
+ onClose: function(dateText, dp_inst) {
+ if (tp_inst.timeDefined === true && $input.val() != '')
+ tp_inst._updateDateTime(dp_inst);
+ if ($.isFunction(o.onClose))
+ o.onClose(dateText, dp_inst, tp_inst);
+ },
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+ });
+
+ if (o.altField)
+ tp_inst.$altInput = $(o.altField)
+ .css({ cursor: 'pointer' })
+ .focus(function(){ $input.trigger("focus"); });
+
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+ if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date)
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+ if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date)
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+ if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date)
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+ if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date)
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+
+ return tp_inst;
+ },
+
+ //########################################################################
+ // add our sliders to the calendar
+ //########################################################################
+ _addTimePicker: function(dp_inst) {
+ var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ?
+ this.$input.val() + ' ' + this.$altInput.val() :
+ this.$input.val();
+
+ this.timeDefined = this._parseTime(currDT);
+ this._limitMinMaxDateTime(dp_inst, false);
+ this._injectTimePicker();
+ },
+
+ //########################################################################
+ // parse the time string from input value or _setTime
+ //########################################################################
+ _parseTime: function(timeString, withDate) {
+ var regstr = this._defaults.timeFormat.toString()
+ .replace(/h{1,2}/ig, '(\\d?\\d)')
+ .replace(/m{1,2}/ig, '(\\d?\\d)')
+ .replace(/s{1,2}/ig, '(\\d?\\d)')
+ .replace(/t{1,2}/ig, '(am|pm|a|p)?')
+ .replace(/\s/g, '\\s?') + '$',
+ order = this._getFormatPositions(),
+ treg;
+
+ if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
+
+ if (withDate || !this._defaults.timeOnly) {
+ // the time should come after x number of characters and a space.
+ // x = at least the length of text specified by the date format
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+ regstr = '.{' + dp_dateFormat.length + ',}' + this._defaults.separator + regstr;
+ }
+
+ treg = timeString.match(new RegExp(regstr, 'i'));
+
+ if (treg) {
+ if (order.t !== -1)
+ this.ampm = ((treg[order.t] === undefined || treg[order.t].length === 0) ?
+ '' :
+ (treg[order.t].charAt(0).toUpperCase() == 'A') ? 'AM' : 'PM').toUpperCase();
+
+ if (order.h !== -1) {
+ if (this.ampm == 'AM' && treg[order.h] == '12')
+ this.hour = 0; // 12am = 0 hour
+ else if (this.ampm == 'PM' && treg[order.h] != '12')
+ this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12
+ else this.hour = Number(treg[order.h]);
+ }
+
+ if (order.m !== -1) this.minute = Number(treg[order.m]);
+ if (order.s !== -1) this.second = Number(treg[order.s]);
+
+ return true;
+
+ }
+ return false;
+ },
+
+ //########################################################################
+ // figure out position of time elements.. cause js cant do named captures
+ //########################################################################
+ _getFormatPositions: function() {
+ var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|t{1,2})/g),
+ orders = { h: -1, m: -1, s: -1, t: -1 };
+
+ if (finds)
+ for (var i = 0; i < finds.length; i++)
+ if (orders[finds[i].toString().charAt(0)] == -1)
+ orders[finds[i].toString().charAt(0)] = i + 1;
+
+ return orders;
+ },
+
+ //########################################################################
+ // generate and inject html for timepicker into ui datepicker
+ //########################################################################
+ _injectTimePicker: function() {
+ var $dp = this.inst.dpDiv,
+ o = this._defaults,
+ tp_inst = this,
+ // Added by Peter Medeiros:
+ // - Figure out what the hour/minute/second max should be based on the step values.
+ // - Example: if stepMinute is 15, then minMax is 45.
+ hourMax = (o.hourMax - (o.hourMax % o.stepHour)).toFixed(0),
+ minMax = (o.minuteMax - (o.minuteMax % o.stepMinute)).toFixed(0),
+ secMax = (o.secondMax - (o.secondMax % o.stepSecond)).toFixed(0),
+ dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, '');
+
+ // Prevent displaying twice
+ //if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) {
+ if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) {
+ var noDisplay = ' style="display:none;"',
+ html = '<div class="ui-timepicker-div" id="ui-timepicker-div-' + dp_id + '"><dl>' +
+ '<dt class="ui_tpicker_time_label" id="ui_tpicker_time_label_' + dp_id + '"' +
+ ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
+ '<dd class="ui_tpicker_time" id="ui_tpicker_time_' + dp_id + '"' +
+ ((o.showTime) ? '' : noDisplay) + '></dd>' +
+ '<dt class="ui_tpicker_hour_label" id="ui_tpicker_hour_label_' + dp_id + '"' +
+ ((o.showHour) ? '' : noDisplay) + '>' + o.hourText + '</dt>',
+ hourGridSize = 0,
+ minuteGridSize = 0,
+ secondGridSize = 0,
+ size;
+
+ if (o.showHour && o.hourGrid > 0) {
+ html += '<dd class="ui_tpicker_hour">' +
+ '<div id="ui_tpicker_hour_' + dp_id + '"' + ((o.showHour) ? '' : noDisplay) + '></div>' +
+ '<div style="padding-left: 1px"><table><tr>';
+
+ for (var h = o.hourMin; h < hourMax; h += o.hourGrid) {
+ hourGridSize++;
+ var tmph = (o.ampm && h > 12) ? h-12 : h;
+ if (tmph < 10) tmph = '0' + tmph;
+ if (o.ampm) {
+ if (h == 0) tmph = 12 +'a';
+ else if (h < 12) tmph += 'a';
+ else tmph += 'p';
+ }
+ html += '<td>' + tmph + '</td>';
+ }
+
+ html += '</tr></table></div>' +
+ '</dd>';
+ } else html += '<dd class="ui_tpicker_hour" id="ui_tpicker_hour_' + dp_id + '"' +
+ ((o.showHour) ? '' : noDisplay) + '></dd>';
+
+ html += '<dt class="ui_tpicker_minute_label" id="ui_tpicker_minute_label_' + dp_id + '"' +
+ ((o.showMinute) ? '' : noDisplay) + '>' + o.minuteText + '</dt>';
+
+ if (o.showMinute && o.minuteGrid > 0) {
+ html += '<dd class="ui_tpicker_minute ui_tpicker_minute_' + o.minuteGrid + '">' +
+ '<div id="ui_tpicker_minute_' + dp_id + '"' +
+ ((o.showMinute) ? '' : noDisplay) + '></div>' +
+ '<div style="padding-left: 1px"><table><tr>';
+
+ for (var m = o.minuteMin; m < minMax; m += o.minuteGrid) {
+ minuteGridSize++;
+ html += '<td>' + ((m < 10) ? '0' : '') + m + '</td>';
+ }
+
+ html += '</tr></table></div>' +
+ '</dd>';
+ } else html += '<dd class="ui_tpicker_minute" id="ui_tpicker_minute_' + dp_id + '"' +
+ ((o.showMinute) ? '' : noDisplay) + '></dd>';
+
+ html += '<dt class="ui_tpicker_second_label" id="ui_tpicker_second_label_' + dp_id + '"' +
+ ((o.showSecond) ? '' : noDisplay) + '>' + o.secondText + '</dt>';
+
+ if (o.showSecond && o.secondGrid > 0) {
+ html += '<dd class="ui_tpicker_second ui_tpicker_second_' + o.secondGrid + '">' +
+ '<div id="ui_tpicker_second_' + dp_id + '"' +
+ ((o.showSecond) ? '' : noDisplay) + '></div>' +
+ '<div style="padding-left: 1px"><table><tr>';
+
+ for (var s = o.secondMin; s < secMax; s += o.secondGrid) {
+ secondGridSize++;
+ html += '<td>' + ((s < 10) ? '0' : '') + s + '</td>';
+ }
+
+ html += '</tr></table></div>' +
+ '</dd>';
+ } else html += '<dd class="ui_tpicker_second" id="ui_tpicker_second_' + dp_id + '"' +
+ ((o.showSecond) ? '' : noDisplay) + '></dd>';
+
+ html += '</dl></div>';
+ $tp = $(html);
+
+ // if we only want time picker...
+ if (o.timeOnly === true) {
+ $tp.prepend(
+ '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' +
+ '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' +
+ '</div>');
+ $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
+ }
+
+ this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({
+ orientation: "horizontal",
+ value: this.hour,
+ min: o.hourMin,
+ max: hourMax,
+ step: o.stepHour,
+ slide: function(event, ui) {
+ tp_inst.hour_slider.slider( "option", "value", ui.value);
+ tp_inst._onTimeChange();
+ }
+ });
+
+ // Updated by Peter Medeiros:
+ // - Pass in Event and UI instance into slide function
+ this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({
+ orientation: "horizontal",
+ value: this.minute,
+ min: o.minuteMin,
+ max: minMax,
+ step: o.stepMinute,
+ slide: function(event, ui) {
+ // update the global minute slider instance value with the current slider value
+ tp_inst.minute_slider.slider( "option", "value", ui.value);
+ tp_inst._onTimeChange();
+ }
+ });
+
+ this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({
+ orientation: "horizontal",
+ value: this.second,
+ min: o.secondMin,
+ max: secMax,
+ step: o.stepSecond,
+ slide: function(event, ui) {
+ tp_inst.second_slider.slider( "option", "value", ui.value);
+ tp_inst._onTimeChange();
+ }
+ });
+
+ // Add grid functionality
+ if (o.showHour && o.hourGrid > 0) {
+ size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin);
+
+ $tp.find(".ui_tpicker_hour table").css({
+ width: size + "%",
+ marginLeft: (size / (-2 * hourGridSize)) + "%",
+ borderCollapse: 'collapse'
+ }).find("td").each( function(index) {
+ $(this).click(function() {
+ var h = $(this).html();
+ if(o.ampm) {
+ var ap = h.substring(2).toLowerCase(),
+ aph = parseInt(h.substring(0,2));
+ if (ap == 'a') {
+ if (aph == 12) h = 0;
+ else h = aph;
+ } else if (aph == 12) h = 12;
+ else h = aph + 12;
+ }
+ tp_inst.hour_slider.slider("option", "value", h);
+ tp_inst._onTimeChange();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / hourGridSize) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ });
+ }
+
+ if (o.showMinute && o.minuteGrid > 0) {
+ size = 100 * minuteGridSize * o.minuteGrid / (minMax - o.minuteMin);
+ $tp.find(".ui_tpicker_minute table").css({
+ width: size + "%",
+ marginLeft: (size / (-2 * minuteGridSize)) + "%",
+ borderCollapse: 'collapse'
+ }).find("td").each(function(index) {
+ $(this).click(function() {
+ tp_inst.minute_slider.slider("option", "value", $(this).html());
+ tp_inst._onTimeChange();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / minuteGridSize) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ });
+ }
+
+ if (o.showSecond && o.secondGrid > 0) {
+ $tp.find(".ui_tpicker_second table").css({
+ width: size + "%",
+ marginLeft: (size / (-2 * secondGridSize)) + "%",
+ borderCollapse: 'collapse'
+ }).find("td").each(function(index) {
+ $(this).click(function() {
+ tp_inst.second_slider.slider("option", "value", $(this).html());
+ tp_inst._onTimeChange();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / secondGridSize) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ });
+ }
+
+ var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
+ if ($buttonPanel.length) $buttonPanel.before($tp);
+ else $dp.append($tp);
+
+ this.$timeObj = $('#ui_tpicker_time_'+ dp_id);
+
+ if (this.inst !== null) {
+ var timeDefined = this.timeDefined;
+ this._onTimeChange();
+ this.timeDefined = timeDefined;
+ }
+
+ //Emulate datepicker onSelect behavior. Call on slidestop.
+ var onSelect = tp_inst._defaults['onSelect'];
+ if (onSelect) {
+ var inputEl = tp_inst.$input ? tp_inst.$input[0] : null;
+ var onSelectHandler = function() {
+ onSelect.apply(inputEl, [tp_inst.formattedDateTime, tp_inst]); // trigger custom callback*/
+ }
+ this.hour_slider.bind('slidestop',onSelectHandler);
+ this.minute_slider.bind('slidestop',onSelectHandler);
+ this.second_slider.bind('slidestop',onSelectHandler);
+ }
+ }
+ },
+
+ //########################################################################
+ // This function tries to limit the ability to go outside the
+ // min/max date range
+ //########################################################################
+ _limitMinMaxDateTime: function(dp_inst, adjustSliders){
+ var o = this._defaults,
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay),
+ tp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay, this.hour, this.minute, this.second, 0);
+
+ if(this._defaults.minDateTime !== null && dp_date){
+ var minDateTime = this._defaults.minDateTime,
+ minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
+
+ if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null){
+ this.hourMinOriginal = o.hourMin;
+ this.minuteMinOriginal = o.minuteMin;
+ this.secondMinOriginal = o.secondMin;
+ }
+
+ if(minDateTimeDate.getTime() == dp_date.getTime()){
+ this._defaults.hourMin = minDateTime.getHours();
+ this._defaults.minuteMin = minDateTime.getMinutes();
+ this._defaults.secondMin = minDateTime.getSeconds();
+
+ if(this.hour < this._defaults.hourMin) this.hour = this._defaults.hourMin;
+ if(this.minute < this._defaults.minuteMin) this.minute = this._defaults.minuteMin;
+ if(this.second < this._defaults.secondMin) this.second = this._defaults.secondMin;
+ }else{
+ this._defaults.hourMin = this.hourMinOriginal;
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ }
+ }
+
+ if(this._defaults.maxDateTime !== null && dp_date){
+ var maxDateTime = this._defaults.maxDateTime,
+ maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
+
+ if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){
+ this.hourMaxOriginal = o.hourMax;
+ this.minuteMaxOriginal = o.minuteMax;
+ this.secondMaxOriginal = o.secondMax;
+ }
+
+ if(maxDateTimeDate.getTime() == dp_date.getTime()){
+ this._defaults.hourMax = maxDateTime.getHours();
+ this._defaults.minuteMax = maxDateTime.getMinutes();
+ this._defaults.secondMax = maxDateTime.getSeconds();
+
+ if(this.hour > this._defaults.hourMax){ this.hour = this._defaults.hourMax; }
+ if(this.minute > this._defaults.minuteMax) this.minute = this._defaults.minuteMax;
+ if(this.second > this._defaults.secondMax) this.second = this._defaults.secondMax;
+ }else{
+ this._defaults.hourMax = this.hourMaxOriginal;
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ }
+ }
+
+ if(adjustSliders !== undefined && adjustSliders === true){
+ this.hour_slider.slider("option", { min: this._defaults.hourMin, max: this._defaults.hourMax }).slider('value', this.hour);
+ this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: this._defaults.minuteMax }).slider('value', this.minute);
+ this.second_slider.slider("option", { min: this._defaults.secondMin, max: this._defaults.secondMax }).slider('value', this.second);
+ }
+
+ },
+
+ //########################################################################
+ // when a slider moves, set the internal time...
+ // on time change is also called when the time is updated in the text field
+ //########################################################################
+ _onTimeChange: function() {
+ var hour = (this.hour_slider) ? this.hour_slider.slider('value') : false,
+ minute = (this.minute_slider) ? this.minute_slider.slider('value') : false,
+ second = (this.second_slider) ? this.second_slider.slider('value') : false;
+
+ if (hour !== false) hour = parseInt(hour,10);
+ if (minute !== false) minute = parseInt(minute,10);
+ if (second !== false) second = parseInt(second,10);
+
+ var ampm = (hour < 12) ? 'AM' : 'PM';
+
+ // If the update was done in the input field, the input field should not be updated.
+ // If the update was done using the sliders, update the input field.
+ var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || (this.ampm.length > 0 && this.ampm != ampm));
+
+ if (hasChanged) {
+
+ if (hour !== false)this.hour = hour;
+ if (minute !== false) this.minute = minute;
+ if (second !== false) this.second = second;
+ }
+ if (this._defaults.ampm) this.ampm = ampm;
+
+ this._formatTime();
+ if (this.$timeObj) this.$timeObj.text(this.formattedTime);
+ this.timeDefined = true;
+ if (hasChanged) this._updateDateTime();
+ },
+
+ //########################################################################
+ // format the time all pretty...
+ //########################################################################
+ _formatTime: function(time, format, ampm) {
+ if (ampm == undefined) ampm = this._defaults.ampm;
+ time = time || { hour: this.hour, minute: this.minute, second: this.second, ampm: this.ampm };
+ var tmptime = format || this._defaults.timeFormat.toString();
+
+ if (ampm) {
+ var hour12 = ((time.ampm == 'AM') ? (time.hour) : (time.hour % 12));
+ hour12 = (Number(hour12) === 0) ? 12 : hour12;
+ tmptime = tmptime.toString()
+ .replace(/hh/g, ((hour12 < 10) ? '0' : '') + hour12)
+ .replace(/h/g, hour12)
+ .replace(/mm/g, ((time.minute < 10) ? '0' : '') + time.minute)
+ .replace(/m/g, time.minute)
+ .replace(/ss/g, ((time.second < 10) ? '0' : '') + time.second)
+ .replace(/s/g, time.second)
+ .replace(/TT/g, time.ampm.toUpperCase())
+ .replace(/tt/g, time.ampm.toLowerCase())
+ .replace(/T/g, time.ampm.charAt(0).toUpperCase())
+ .replace(/t/g, time.ampm.charAt(0).toLowerCase());
+ } else {
+ tmptime = tmptime.toString()
+ .replace(/hh/g, ((time.hour < 10) ? '0' : '') + time.hour)
+ .replace(/h/g, time.hour)
+ .replace(/mm/g, ((time.minute < 10) ? '0' : '') + time.minute)
+ .replace(/m/g, time.minute)
+ .replace(/ss/g, ((time.second < 10) ? '0' : '') + time.second)
+ .replace(/s/g, time.second);
+ tmptime = $.trim(tmptime.replace(/t/gi, ''));
+ }
+
+ if (arguments.length) return tmptime;
+ else this.formattedTime = tmptime;
+ },
+
+ //########################################################################
+ // update our input with the new date time..
+ //########################################################################
+ _updateDateTime: function(dp_inst) {
+ dp_inst = this.inst || dp_inst,
+ dt = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay),
+ dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+ formatCfg = $.datepicker._getFormatConfig(dp_inst),
+ timeAvailable = dt !== null && this.timeDefined;
+ this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
+ var formattedDateTime = this.formattedDate;
+ if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0))
+ return;
+
+ if (this._defaults.timeOnly === true) {
+ formattedDateTime = this.formattedTime;
+ } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
+ formattedDateTime += this._defaults.separator + this.formattedTime;
+ }
+
+ this.formattedDateTime = formattedDateTime;
+
+ if(!this._defaults.showTimepicker) {
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
+ this.$altInput.val(this.formattedTime);
+ this.$input.val(this.formattedDate);
+ } else if(this.$altInput) {
+ this.$altInput.val(formattedDateTime);
+ this.$input.val(formattedDateTime);
+ } else {
+ this.$input.val(formattedDateTime);
+ }
+
+ this.$input.trigger("change");
+ }
+
+});
+
+$.fn.extend({
+ //########################################################################
+ // shorthand just to use timepicker..
+ //########################################################################
+ timepicker: function(o) {
+ o = o || {};
+ var tmp_args = arguments;
+
+ if (typeof o == 'object') tmp_args[0] = $.extend(o, { timeOnly: true });
+
+ return $(this).each(function() {
+ $.fn.datetimepicker.apply($(this), tmp_args);
+ });
+ },
+
+ //########################################################################
+ // extend timepicker to datepicker
+ //########################################################################
+ datetimepicker: function(o) {
+ o = o || {};
+ var $input = this,
+ tmp_args = arguments;
+
+ if (typeof(o) == 'string'){
+ if(o == 'getDate')
+ return $.fn.datepicker.apply($(this[0]), tmp_args);
+ else
+ return this.each(function() {
+ var $t = $(this);
+ $t.datepicker.apply($t, tmp_args);
+ });
+ }
+ else
+ return this.each(function() {
+ var $t = $(this);
+ $t.datepicker($.timepicker._newInst($t, o)._defaults);
+ });
+ }
+});
+
+//########################################################################
+// the bad hack :/ override datepicker so it doesnt close on select
+// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
+//########################################################################
+$.datepicker._base_selectDate = $.datepicker._selectDate;
+$.datepicker._selectDate = function (id, dateStr) {
+ var inst = this._getInst($(id)[0]),
+ tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ tp_inst._limitMinMaxDateTime(inst, true);
+ inst.inline = inst.stay_open = true;
+ //This way the onSelect handler called from calendarpicker get the full dateTime
+ this._base_selectDate(id, dateStr + tp_inst._defaults.separator + tp_inst.formattedTime);
+ inst.inline = inst.stay_open = false;
+ this._notifyChange(inst);
+ this._updateDatepicker(inst);
+ }
+ else this._base_selectDate(id, dateStr);
+};
+
+//#############################################################################################
+// second bad hack :/ override datepicker so it triggers an event when changing the input field
+// and does not redraw the datepicker on every selectDate event
+//#############################################################################################
+$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
+$.datepicker._updateDatepicker = function(inst) {
+ if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
+
+ this._base_updateDatepicker(inst);
+
+ // Reload the time control when changing something in the input text field.
+ var tp_inst = this._get(inst, 'timepicker');
+ if(tp_inst) tp_inst._addTimePicker(inst);
+ }
+};
+
+//#######################################################################################
+// third bad hack :/ override datepicker so it allows spaces and colan in the input field
+//#######################################################################################
+$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
+$.datepicker._doKeyPress = function(event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if ($.datepicker._get(inst, 'constrainInput')) {
+ var ampm = tp_inst._defaults.ampm,
+ datetimeChars = tp_inst._defaults.timeFormat.toString()
+ .replace(/[hms]/g, '')
+ .replace(/TT/g, ampm ? 'APM' : '')
+ .replace(/T/g, ampm ? 'AP' : '')
+ .replace(/tt/g, ampm ? 'apm' : '')
+ .replace(/t/g, ampm ? 'ap' : '') +
+ " " +
+ tp_inst._defaults.separator +
+ $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+ chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
+ return event.ctrlKey || (chr < ' ' || !datetimeChars || datetimeChars.indexOf(chr) > -1);
+ }
+ }
+
+ return $.datepicker._base_doKeyPress(event);
+};
+
+//#######################################################################################
+// Override key up event to sync manual input changes.
+//#######################################################################################
+$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
+$.datepicker._doKeyUp = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ }
+ catch (err) {
+ $.datepicker.log(err);
+ }
+ }
+ }
+
+ return $.datepicker._base_doKeyUp(event);
+};
+
+//#######################################################################################
+// override "Today" button to also grab the time.
+//#######################################################################################
+$.datepicker._base_gotoToday = $.datepicker._gotoToday;
+$.datepicker._gotoToday = function(id) {
+ this._base_gotoToday(id);
+ this._setTime(this._getInst($(id)[0]), new Date());
+};
+
+//#######################################################################################
+// Disable & enable the Time in the datetimepicker
+//#######################################################################################
+$.datepicker._disableTimepickerDatepicker = function(target, date, withDate) {
+ var inst = this._getInst(target),
+ tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._defaults.showTimepicker = false;
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+};
+
+$.datepicker._enableTimepickerDatepicker = function(target, date, withDate) {
+ var inst = this._getInst(target),
+ tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._defaults.showTimepicker = true;
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+};
+
+//#######################################################################################
+// Create our own set time function
+//#######################################################################################
+$.datepicker._setTime = function(inst, date) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var defaults = tp_inst._defaults,
+ // calling _setTime with no date sets time to defaults
+ hour = date ? date.getHours() : defaults.hour,
+ minute = date ? date.getMinutes() : defaults.minute,
+ second = date ? date.getSeconds() : defaults.second;
+
+ //check if within min/max times..
+ if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax)) {
+ hour = defaults.hourMin;
+ minute = defaults.minuteMin;
+ second = defaults.secondMin;
+ }
+
+ if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour);
+ else tp_inst.hour = hour;
+ if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute);
+ else tp_inst.minute = minute;
+ if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second);
+ else tp_inst.second = second;
+
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+};
+
+//#######################################################################################
+// Create new public method to set only time, callable as $().datepicker('setTime', date)
+//#######################################################################################
+$.datepicker._setTimeDatepicker = function(target, date, withDate) {
+ var inst = this._getInst(target),
+ tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ this._setDateFromField(inst);
+ var tp_date;
+ if (date) {
+ if (typeof date == "string") {
+ tp_inst._parseTime(date, withDate);
+ tp_date = new Date();
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second);
+ }
+ else tp_date = new Date(date.getTime());
+ if (tp_date.toString() == 'Invalid Date') tp_date = undefined;
+ }
+ this._setTime(inst, tp_date);
+ }
+
+};
+
+//#######################################################################################
+// override setDate() to allow setting time too within Date object
+//#######################################################################################
+$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
+$.datepicker._setDateDatepicker = function(target, date) {
+ var inst = this._getInst(target),
+ tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
+
+ this._updateDatepicker(inst);
+ this._base_setDateDatepicker.apply(this, arguments);
+ this._setTimeDatepicker(target, tp_date, true);
+};
+
+//#######################################################################################
+// override getDate() to allow getting time too within Date object
+//#######################################################################################
+$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
+$.datepicker._getDateDatepicker = function(target, noDefault) {
+ var inst = this._getInst(target),
+ tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ this._setDateFromField(inst, noDefault);
+ var date = this._getDate(inst);
+ if (date && tp_inst._parseTime($(target).val(), true)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second);
+ return date;
+ }
+ return this._base_getDateDatepicker(target, noDefault);
+};
+
+//#######################################################################################
+// jQuery extend now ignores nulls!
+//#######################################################################################
+function extendRemove(target, props) {
+ $.extend(target, props);
+ for (var name in props)
+ if (props[name] === null || props[name] === undefined)
+ target[name] = props[name];
+ return target;
+}
+
+$.timepicker = new Timepicker(); // singleton instance
+$.timepicker.version = "0.9.3";
+
+})(jQuery);
diff --git a/addons/web/static/lib/jquery.validate/jquery.validate.js b/addons/web/static/lib/jquery.validate/jquery.validate.js
new file mode 100644
index 00000000000..72296a61f20
--- /dev/null
+++ b/addons/web/static/lib/jquery.validate/jquery.validate.js
@@ -0,0 +1,1166 @@
+/**
+ * jQuery Validation Plugin 1.8.1
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
+ * http://docs.jquery.com/Plugins/Validation
+ *
+ * Copyright (c) 2006 - 2011 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+(function($) {
+
+$.extend($.fn, {
+ // http://docs.jquery.com/Plugins/Validation/validate
+ validate: function( options ) {
+
+ // if nothing is selected, return nothing; can't chain anyway
+ if (!this.length) {
+ options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
+ return;
+ }
+
+ // check if a validator for this form was already created
+ var validator = $.data(this[0], 'validator');
+ if ( validator ) {
+ return validator;
+ }
+
+ validator = new $.validator( options, this[0] );
+ $.data(this[0], 'validator', validator);
+
+ if ( validator.settings.onsubmit ) {
+
+ // allow suppresing validation by adding a cancel class to the submit button
+ this.find("input, button").filter(".cancel").click(function() {
+ validator.cancelSubmit = true;
+ });
+
+ // when a submitHandler is used, capture the submitting button
+ if (validator.settings.submitHandler) {
+ this.find("input, button").filter(":submit").click(function() {
+ validator.submitButton = this;
+ });
+ }
+
+ // validate the form on submit
+ this.submit( function( event ) {
+ if ( validator.settings.debug )
+ // prevent form submit to be able to see console output
+ event.preventDefault();
+
+ function handle() {
+ if ( validator.settings.submitHandler ) {
+ if (validator.submitButton) {
+ // insert a hidden input as a replacement for the missing submit button
+ var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
+ }
+ validator.settings.submitHandler.call( validator, validator.currentForm );
+ if (validator.submitButton) {
+ // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
+ hidden.remove();
+ }
+ return false;
+ }
+ return true;
+ }
+
+ // prevent submit for invalid forms or custom submit handlers
+ if ( validator.cancelSubmit ) {
+ validator.cancelSubmit = false;
+ return handle();
+ }
+ if ( validator.form() ) {
+ if ( validator.pendingRequest ) {
+ validator.formSubmitted = true;
+ return false;
+ }
+ return handle();
+ } else {
+ validator.focusInvalid();
+ return false;
+ }
+ });
+ }
+
+ return validator;
+ },
+ // http://docs.jquery.com/Plugins/Validation/valid
+ valid: function() {
+ if ( $(this[0]).is('form')) {
+ return this.validate().form();
+ } else {
+ var valid = true;
+ var validator = $(this[0].form).validate();
+ this.each(function() {
+ valid &= validator.element(this);
+ });
+ return valid;
+ }
+ },
+ // attributes: space seperated list of attributes to retrieve and remove
+ removeAttrs: function(attributes) {
+ var result = {},
+ $element = this;
+ $.each(attributes.split(/\s/), function(index, value) {
+ result[value] = $element.attr(value);
+ $element.removeAttr(value);
+ });
+ return result;
+ },
+ // http://docs.jquery.com/Plugins/Validation/rules
+ rules: function(command, argument) {
+ var element = this[0];
+
+ if (command) {
+ var settings = $.data(element.form, 'validator').settings;
+ var staticRules = settings.rules;
+ var existingRules = $.validator.staticRules(element);
+ switch(command) {
+ case "add":
+ $.extend(existingRules, $.validator.normalizeRule(argument));
+ staticRules[element.name] = existingRules;
+ if (argument.messages)
+ settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
+ break;
+ case "remove":
+ if (!argument) {
+ delete staticRules[element.name];
+ return existingRules;
+ }
+ var filtered = {};
+ $.each(argument.split(/\s/), function(index, method) {
+ filtered[method] = existingRules[method];
+ delete existingRules[method];
+ });
+ return filtered;
+ }
+ }
+
+ var data = $.validator.normalizeRules(
+ $.extend(
+ {},
+ $.validator.metadataRules(element),
+ $.validator.classRules(element),
+ $.validator.attributeRules(element),
+ $.validator.staticRules(element)
+ ), element);
+
+ // make sure required is at front
+ if (data.required) {
+ var param = data.required;
+ delete data.required;
+ data = $.extend({required: param}, data);
+ }
+
+ return data;
+ }
+});
+
+// Custom selectors
+$.extend($.expr[":"], {
+ // http://docs.jquery.com/Plugins/Validation/blank
+ blank: function(a) {return !$.trim("" + a.value);},
+ // http://docs.jquery.com/Plugins/Validation/filled
+ filled: function(a) {return !!$.trim("" + a.value);},
+ // http://docs.jquery.com/Plugins/Validation/unchecked
+ unchecked: function(a) {return !a.checked;}
+});
+
+// constructor for validator
+$.validator = function( options, form ) {
+ this.settings = $.extend( true, {}, $.validator.defaults, options );
+ this.currentForm = form;
+ this.init();
+};
+
+$.validator.format = function(source, params) {
+ if ( arguments.length == 1 )
+ return function() {
+ var args = $.makeArray(arguments);
+ args.unshift(source);
+ return $.validator.format.apply( this, args );
+ };
+ if ( arguments.length > 2 && params.constructor != Array ) {
+ params = $.makeArray(arguments).slice(1);
+ }
+ if ( params.constructor != Array ) {
+ params = [ params ];
+ }
+ $.each(params, function(i, n) {
+ source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
+ });
+ return source;
+};
+
+$.extend($.validator, {
+
+ defaults: {
+ messages: {},
+ groups: {},
+ rules: {},
+ errorClass: "error",
+ validClass: "valid",
+ errorElement: "label",
+ focusInvalid: true,
+ errorContainer: $( [] ),
+ errorLabelContainer: $( [] ),
+ onsubmit: true,
+ ignore: [],
+ ignoreTitle: false,
+ onfocusin: function(element) {
+ this.lastActive = element;
+
+ // hide error label and remove error class on focus if enabled
+ if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
+ this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
+ this.addWrapper(this.errorsFor(element)).hide();
+ }
+ },
+ onfocusout: function(element) {
+ if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
+ this.element(element);
+ }
+ },
+ onkeyup: function(element) {
+ if ( element.name in this.submitted || element == this.lastElement ) {
+ this.element(element);
+ }
+ },
+ onclick: function(element) {
+ // click on selects, radiobuttons and checkboxes
+ if ( element.name in this.submitted )
+ this.element(element);
+ // or option elements, check parent select in that case
+ else if (element.parentNode.name in this.submitted)
+ this.element(element.parentNode);
+ },
+ highlight: function(element, errorClass, validClass) {
+ if (element.type === 'radio') {
+ this.findByName(element.name).addClass(errorClass).removeClass(validClass);
+ } else {
+ $(element).addClass(errorClass).removeClass(validClass);
+ }
+ },
+ unhighlight: function(element, errorClass, validClass) {
+ if (element.type === 'radio') {
+ this.findByName(element.name).removeClass(errorClass).addClass(validClass);
+ } else {
+ $(element).removeClass(errorClass).addClass(validClass);
+ }
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
+ setDefaults: function(settings) {
+ $.extend( $.validator.defaults, settings );
+ },
+
+ messages: {
+ required: "This field is required.",
+ remote: "Please fix this field.",
+ email: "Please enter a valid email address.",
+ url: "Please enter a valid URL.",
+ date: "Please enter a valid date.",
+ dateISO: "Please enter a valid date (ISO).",
+ number: "Please enter a valid number.",
+ digits: "Please enter only digits.",
+ creditcard: "Please enter a valid credit card number.",
+ equalTo: "Please enter the same value again.",
+ accept: "Please enter a value with a valid extension.",
+ maxlength: $.validator.format("Please enter no more than {0} characters."),
+ minlength: $.validator.format("Please enter at least {0} characters."),
+ rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
+ range: $.validator.format("Please enter a value between {0} and {1}."),
+ max: $.validator.format("Please enter a value less than or equal to {0}."),
+ min: $.validator.format("Please enter a value greater than or equal to {0}.")
+ },
+
+ autoCreateRanges: false,
+
+ prototype: {
+
+ init: function() {
+ this.labelContainer = $(this.settings.errorLabelContainer);
+ this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
+ this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
+ this.submitted = {};
+ this.valueCache = {};
+ this.pendingRequest = 0;
+ this.pending = {};
+ this.invalid = {};
+ this.reset();
+
+ var groups = (this.groups = {});
+ $.each(this.settings.groups, function(key, value) {
+ $.each(value.split(/\s/), function(index, name) {
+ groups[name] = key;
+ });
+ });
+ var rules = this.settings.rules;
+ $.each(rules, function(key, value) {
+ rules[key] = $.validator.normalizeRule(value);
+ });
+
+ function delegate(event) {
+ var validator = $.data(this[0].form, "validator"),
+ eventType = "on" + event.type.replace(/^validate/, "");
+ validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
+ }
+ $(this.currentForm)
+ .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
+ .validateDelegate(":radio, :checkbox, select, option", "click", delegate);
+
+ if (this.settings.invalidHandler)
+ $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/form
+ form: function() {
+ this.checkForm();
+ $.extend(this.submitted, this.errorMap);
+ this.invalid = $.extend({}, this.errorMap);
+ if (!this.valid())
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
+ this.showErrors();
+ return this.valid();
+ },
+
+ checkForm: function() {
+ this.prepareForm();
+ for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
+ this.check( elements[i] );
+ }
+ return this.valid();
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/element
+ element: function( element ) {
+ element = this.clean( element );
+ this.lastElement = element;
+ this.prepareElement( element );
+ this.currentElements = $(element);
+ var result = this.check( element );
+ if ( result ) {
+ delete this.invalid[element.name];
+ } else {
+ this.invalid[element.name] = true;
+ }
+ if ( !this.numberOfInvalids() ) {
+ // Hide error containers on last error
+ this.toHide = this.toHide.add( this.containers );
+ }
+ this.showErrors();
+ return result;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
+ showErrors: function(errors) {
+ if(errors) {
+ // add items to error list and map
+ $.extend( this.errorMap, errors );
+ this.errorList = [];
+ for ( var name in errors ) {
+ this.errorList.push({
+ message: errors[name],
+ element: this.findByName(name)[0]
+ });
+ }
+ // remove items from success list
+ this.successList = $.grep( this.successList, function(element) {
+ return !(element.name in errors);
+ });
+ }
+ this.settings.showErrors
+ ? this.settings.showErrors.call( this, this.errorMap, this.errorList )
+ : this.defaultShowErrors();
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
+ resetForm: function() {
+ if ( $.fn.resetForm )
+ $( this.currentForm ).resetForm();
+ this.submitted = {};
+ this.prepareForm();
+ this.hideErrors();
+ this.elements().removeClass( this.settings.errorClass );
+ },
+
+ numberOfInvalids: function() {
+ return this.objectLength(this.invalid);
+ },
+
+ objectLength: function( obj ) {
+ var count = 0;
+ for ( var i in obj )
+ count++;
+ return count;
+ },
+
+ hideErrors: function() {
+ this.addWrapper( this.toHide ).hide();
+ },
+
+ valid: function() {
+ return this.size() == 0;
+ },
+
+ size: function() {
+ return this.errorList.length;
+ },
+
+ focusInvalid: function() {
+ if( this.settings.focusInvalid ) {
+ try {
+ $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
+ .filter(":visible")
+ .focus()
+ // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
+ .trigger("focusin");
+ } catch(e) {
+ // ignore IE throwing errors when focusing hidden elements
+ }
+ }
+ },
+
+ findLastActive: function() {
+ var lastActive = this.lastActive;
+ return lastActive && $.grep(this.errorList, function(n) {
+ return n.element.name == lastActive.name;
+ }).length == 1 && lastActive;
+ },
+
+ elements: function() {
+ var validator = this,
+ rulesCache = {};
+
+ // select all valid inputs inside the form (no submit or reset buttons)
+ return $(this.currentForm)
+ .find("input, select, textarea")
+ .not(":submit, :reset, :image, [disabled]")
+ .not( this.settings.ignore )
+ .filter(function() {
+ !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
+
+ // select only the first element for each name, and only those with rules specified
+ if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
+ return false;
+
+ rulesCache[this.name] = true;
+ return true;
+ });
+ },
+
+ clean: function( selector ) {
+ return $( selector )[0];
+ },
+
+ errors: function() {
+ return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
+ },
+
+ reset: function() {
+ this.successList = [];
+ this.errorList = [];
+ this.errorMap = {};
+ this.toShow = $([]);
+ this.toHide = $([]);
+ this.currentElements = $([]);
+ },
+
+ prepareForm: function() {
+ this.reset();
+ this.toHide = this.errors().add( this.containers );
+ },
+
+ prepareElement: function( element ) {
+ this.reset();
+ this.toHide = this.errorsFor(element);
+ },
+
+ check: function( element ) {
+ element = this.clean( element );
+
+ // if radio/checkbox, validate first element in group instead
+ if (this.checkable(element)) {
+ element = this.findByName( element.name ).not(this.settings.ignore)[0];
+ }
+
+ var rules = $(element).rules();
+ var dependencyMismatch = false;
+ for (var method in rules ) {
+ var rule = { method: method, parameters: rules[method] };
+ try {
+ var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
+
+ // if a method indicates that the field is optional and therefore valid,
+ // don't mark it as valid when there are no other rules
+ if ( result == "dependency-mismatch" ) {
+ dependencyMismatch = true;
+ continue;
+ }
+ dependencyMismatch = false;
+
+ if ( result == "pending" ) {
+ this.toHide = this.toHide.not( this.errorsFor(element) );
+ return;
+ }
+
+ if( !result ) {
+ this.formatAndAdd( element, rule );
+ return false;
+ }
+ } catch(e) {
+ this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
+ + ", check the '" + rule.method + "' method", e);
+ throw e;
+ }
+ }
+ if (dependencyMismatch)
+ return;
+ if ( this.objectLength(rules) )
+ this.successList.push(element);
+ return true;
+ },
+
+ // return the custom message for the given element and validation method
+ // specified in the element's "messages" metadata
+ customMetaMessage: function(element, method) {
+ if (!$.metadata)
+ return;
+
+ var meta = this.settings.meta
+ ? $(element).metadata()[this.settings.meta]
+ : $(element).metadata();
+
+ return meta && meta.messages && meta.messages[method];
+ },
+
+ // return the custom message for the given element name and validation method
+ customMessage: function( name, method ) {
+ var m = this.settings.messages[name];
+ return m && (m.constructor == String
+ ? m
+ : m[method]);
+ },
+
+ // return the first defined argument, allowing empty strings
+ findDefined: function() {
+ for(var i = 0; i < arguments.length; i++) {
+ if (arguments[i] !== undefined)
+ return arguments[i];
+ }
+ return undefined;
+ },
+
+ defaultMessage: function( element, method) {
+ return this.findDefined(
+ this.customMessage( element.name, method ),
+ this.customMetaMessage( element, method ),
+ // title is never undefined, so handle empty string as undefined
+ !this.settings.ignoreTitle && element.title || undefined,
+ $.validator.messages[method],
+ "<strong>Warning: No message defined for " + element.name + "</strong>"
+ );
+ },
+
+ formatAndAdd: function( element, rule ) {
+ var message = this.defaultMessage( element, rule.method ),
+ theregex = /\$?\{(\d+)\}/g;
+ if ( typeof message == "function" ) {
+ message = message.call(this, rule.parameters, element);
+ } else if (theregex.test(message)) {
+ message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
+ }
+ this.errorList.push({
+ message: message,
+ element: element
+ });
+
+ this.errorMap[element.name] = message;
+ this.submitted[element.name] = message;
+ },
+
+ addWrapper: function(toToggle) {
+ if ( this.settings.wrapper )
+ toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
+ return toToggle;
+ },
+
+ defaultShowErrors: function() {
+ for ( var i = 0; this.errorList[i]; i++ ) {
+ var error = this.errorList[i];
+ this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
+ this.showLabel( error.element, error.message );
+ }
+ if( this.errorList.length ) {
+ this.toShow = this.toShow.add( this.containers );
+ }
+ if (this.settings.success) {
+ for ( var i = 0; this.successList[i]; i++ ) {
+ this.showLabel( this.successList[i] );
+ }
+ }
+ if (this.settings.unhighlight) {
+ for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
+ this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
+ }
+ }
+ this.toHide = this.toHide.not( this.toShow );
+ this.hideErrors();
+ this.addWrapper( this.toShow ).show();
+ },
+
+ validElements: function() {
+ return this.currentElements.not(this.invalidElements());
+ },
+
+ invalidElements: function() {
+ return $(this.errorList).map(function() {
+ return this.element;
+ });
+ },
+
+ showLabel: function(element, message) {
+ var label = this.errorsFor( element );
+ if ( label.length ) {
+ // refresh error/success class
+ label.removeClass().addClass( this.settings.errorClass );
+
+ // check if we have a generated label, replace the message then
+ label.attr("generated") && label.html(message);
+ } else {
+ // create label
+ label = $("<" + this.settings.errorElement + "/>")
+ .attr({"for": this.idOrName(element), generated: true})
+ .addClass(this.settings.errorClass)
+ .html(message || "");
+ if ( this.settings.wrapper ) {
+ // make sure the element is visible, even in IE
+ // actually showing the wrapped element is handled elsewhere
+ label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
+ }
+ if ( !this.labelContainer.append(label).length )
+ this.settings.errorPlacement
+ ? this.settings.errorPlacement(label, $(element) )
+ : label.insertAfter(element);
+ }
+ if ( !message && this.settings.success ) {
+ label.text("");
+ typeof this.settings.success == "string"
+ ? label.addClass( this.settings.success )
+ : this.settings.success( label );
+ }
+ this.toShow = this.toShow.add(label);
+ },
+
+ errorsFor: function(element) {
+ var name = this.idOrName(element);
+ return this.errors().filter(function() {
+ return $(this).attr('for') == name;
+ });
+ },
+
+ idOrName: function(element) {
+ return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
+ },
+
+ checkable: function( element ) {
+ return /radio|checkbox/i.test(element.type);
+ },
+
+ findByName: function( name ) {
+ // select by name and filter by form for performance over form.find("[name=...]")
+ var form = this.currentForm;
+ return $(document.getElementsByName(name)).map(function(index, element) {
+ return element.form == form && element.name == name && element || null;
+ });
+ },
+
+ getLength: function(value, element) {
+ switch( element.nodeName.toLowerCase() ) {
+ case 'select':
+ return $("option:selected", element).length;
+ case 'input':
+ if( this.checkable( element) )
+ return this.findByName(element.name).filter(':checked').length;
+ }
+ return value.length;
+ },
+
+ depend: function(param, element) {
+ return this.dependTypes[typeof param]
+ ? this.dependTypes[typeof param](param, element)
+ : true;
+ },
+
+ dependTypes: {
+ "boolean": function(param, element) {
+ return param;
+ },
+ "string": function(param, element) {
+ return !!$(param, element.form).length;
+ },
+ "function": function(param, element) {
+ return param(element);
+ }
+ },
+
+ optional: function(element) {
+ return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
+ },
+
+ startRequest: function(element) {
+ if (!this.pending[element.name]) {
+ this.pendingRequest++;
+ this.pending[element.name] = true;
+ }
+ },
+
+ stopRequest: function(element, valid) {
+ this.pendingRequest--;
+ // sometimes synchronization fails, make sure pendingRequest is never < 0
+ if (this.pendingRequest < 0)
+ this.pendingRequest = 0;
+ delete this.pending[element.name];
+ if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
+ $(this.currentForm).submit();
+ this.formSubmitted = false;
+ } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
+ this.formSubmitted = false;
+ }
+ },
+
+ previousValue: function(element) {
+ return $.data(element, "previousValue") || $.data(element, "previousValue", {
+ old: null,
+ valid: true,
+ message: this.defaultMessage( element, "remote" )
+ });
+ }
+
+ },
+
+ classRuleSettings: {
+ required: {required: true},
+ email: {email: true},
+ url: {url: true},
+ date: {date: true},
+ dateISO: {dateISO: true},
+ dateDE: {dateDE: true},
+ number: {number: true},
+ numberDE: {numberDE: true},
+ digits: {digits: true},
+ creditcard: {creditcard: true}
+ },
+
+ addClassRules: function(className, rules) {
+ className.constructor == String ?
+ this.classRuleSettings[className] = rules :
+ $.extend(this.classRuleSettings, className);
+ },
+
+ classRules: function(element) {
+ var rules = {};
+ var classes = $(element).attr('class');
+ classes && $.each(classes.split(' '), function() {
+ if (this in $.validator.classRuleSettings) {
+ $.extend(rules, $.validator.classRuleSettings[this]);
+ }
+ });
+ return rules;
+ },
+
+ attributeRules: function(element) {
+ var rules = {};
+ var $element = $(element);
+
+ for (var method in $.validator.methods) {
+ var value = $element.attr(method);
+ if (value) {
+ rules[method] = value;
+ }
+ }
+
+ // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
+ if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
+ delete rules.maxlength;
+ }
+
+ return rules;
+ },
+
+ metadataRules: function(element) {
+ if (!$.metadata) return {};
+
+ var meta = $.data(element.form, 'validator').settings.meta;
+ return meta ?
+ $(element).metadata()[meta] :
+ $(element).metadata();
+ },
+
+ staticRules: function(element) {
+ var rules = {};
+ var validator = $.data(element.form, 'validator');
+ if (validator.settings.rules) {
+ rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
+ }
+ return rules;
+ },
+
+ normalizeRules: function(rules, element) {
+ // handle dependency check
+ $.each(rules, function(prop, val) {
+ // ignore rule when param is explicitly false, eg. required:false
+ if (val === false) {
+ delete rules[prop];
+ return;
+ }
+ if (val.param || val.depends) {
+ var keepRule = true;
+ switch (typeof val.depends) {
+ case "string":
+ keepRule = !!$(val.depends, element.form).length;
+ break;
+ case "function":
+ keepRule = val.depends.call(element, element);
+ break;
+ }
+ if (keepRule) {
+ rules[prop] = val.param !== undefined ? val.param : true;
+ } else {
+ delete rules[prop];
+ }
+ }
+ });
+
+ // evaluate parameters
+ $.each(rules, function(rule, parameter) {
+ rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
+ });
+
+ // clean number parameters
+ $.each(['minlength', 'maxlength', 'min', 'max'], function() {
+ if (rules[this]) {
+ rules[this] = Number(rules[this]);
+ }
+ });
+ $.each(['rangelength', 'range'], function() {
+ if (rules[this]) {
+ rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
+ }
+ });
+
+ if ($.validator.autoCreateRanges) {
+ // auto-create ranges
+ if (rules.min && rules.max) {
+ rules.range = [rules.min, rules.max];
+ delete rules.min;
+ delete rules.max;
+ }
+ if (rules.minlength && rules.maxlength) {
+ rules.rangelength = [rules.minlength, rules.maxlength];
+ delete rules.minlength;
+ delete rules.maxlength;
+ }
+ }
+
+ // To support custom messages in metadata ignore rule methods titled "messages"
+ if (rules.messages) {
+ delete rules.messages;
+ }
+
+ return rules;
+ },
+
+ // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
+ normalizeRule: function(data) {
+ if( typeof data == "string" ) {
+ var transformed = {};
+ $.each(data.split(/\s/), function() {
+ transformed[this] = true;
+ });
+ data = transformed;
+ }
+ return data;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
+ addMethod: function(name, method, message) {
+ $.validator.methods[name] = method;
+ $.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
+ if (method.length < 3) {
+ $.validator.addClassRules(name, $.validator.normalizeRule(name));
+ }
+ },
+
+ methods: {
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/required
+ required: function(value, element, param) {
+ // check if dependency is met
+ if ( !this.depend(param, element) )
+ return "dependency-mismatch";
+ switch( element.nodeName.toLowerCase() ) {
+ case 'select':
+ // could be an array for select-multiple or a string, both are fine this way
+ var val = $(element).val();
+ return val && val.length > 0;
+ case 'input':
+ if ( this.checkable(element) )
+ return this.getLength(value, element) > 0;
+ default:
+ return $.trim(value).length > 0;
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/remote
+ remote: function(value, element, param) {
+ if ( this.optional(element) )
+ return "dependency-mismatch";
+
+ var previous = this.previousValue(element);
+ if (!this.settings.messages[element.name] )
+ this.settings.messages[element.name] = {};
+ previous.originalMessage = this.settings.messages[element.name].remote;
+ this.settings.messages[element.name].remote = previous.message;
+
+ param = typeof param == "string" && {url:param} || param;
+
+ if ( this.pending[element.name] ) {
+ return "pending";
+ }
+ if ( previous.old === value ) {
+ return previous.valid;
+ }
+
+ previous.old = value;
+ var validator = this;
+ this.startRequest(element);
+ var data = {};
+ data[element.name] = value;
+ $.ajax($.extend(true, {
+ url: param,
+ mode: "abort",
+ port: "validate" + element.name,
+ dataType: "json",
+ data: data,
+ success: function(response) {
+ validator.settings.messages[element.name].remote = previous.originalMessage;
+ var valid = response === true;
+ if ( valid ) {
+ var submitted = validator.formSubmitted;
+ validator.prepareElement(element);
+ validator.formSubmitted = submitted;
+ validator.successList.push(element);
+ validator.showErrors();
+ } else {
+ var errors = {};
+ var message = response || validator.defaultMessage( element, "remote" );
+ errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
+ validator.showErrors(errors);
+ }
+ previous.valid = valid;
+ validator.stopRequest(element, valid);
+ }
+ }, param));
+ return "pending";
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/minlength
+ minlength: function(value, element, param) {
+ return this.optional(element) || this.getLength($.trim(value), element) >= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
+ maxlength: function(value, element, param) {
+ return this.optional(element) || this.getLength($.trim(value), element) <= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
+ rangelength: function(value, element, param) {
+ var length = this.getLength($.trim(value), element);
+ return this.optional(element) || ( length >= param[0] && length <= param[1] );
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/min
+ min: function( value, element, param ) {
+ return this.optional(element) || value >= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/max
+ max: function( value, element, param ) {
+ return this.optional(element) || value <= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/range
+ range: function( value, element, param ) {
+ return this.optional(element) || ( value >= param[0] && value <= param[1] );
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/email
+ email: function(value, element) {
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
+ return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/url
+ url: function(value, element) {
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
+ return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/date
+ date: function(value, element) {
+ return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
+ dateISO: function(value, element) {
+ return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/number
+ number: function(value, element) {
+ return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/digits
+ digits: function(value, element) {
+ return this.optional(element) || /^\d+$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
+ // based on http://en.wikipedia.org/wiki/Luhn
+ creditcard: function(value, element) {
+ if ( this.optional(element) )
+ return "dependency-mismatch";
+ // accept only digits and dashes
+ if (/[^0-9-]+/.test(value))
+ return false;
+ var nCheck = 0,
+ nDigit = 0,
+ bEven = false;
+
+ value = value.replace(/\D/g, "");
+
+ for (var n = value.length - 1; n >= 0; n--) {
+ var cDigit = value.charAt(n);
+ var nDigit = parseInt(cDigit, 10);
+ if (bEven) {
+ if ((nDigit *= 2) > 9)
+ nDigit -= 9;
+ }
+ nCheck += nDigit;
+ bEven = !bEven;
+ }
+
+ return (nCheck % 10) == 0;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/accept
+ accept: function(value, element, param) {
+ param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
+ return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
+ equalTo: function(value, element, param) {
+ // bind to the blur event of the target in order to revalidate whenever the target field is updated
+ // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
+ var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
+ $(element).valid();
+ });
+ return value == target.val();
+ }
+
+ }
+
+});
+
+// deprecated, use $.validator.format instead
+$.format = $.validator.format;
+
+})(jQuery);
+
+// ajax mode: abort
+// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
+// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
+;(function($) {
+ var pendingRequests = {};
+ // Use a prefilter if available (1.5+)
+ if ( $.ajaxPrefilter ) {
+ $.ajaxPrefilter(function(settings, _, xhr) {
+ var port = settings.port;
+ if (settings.mode == "abort") {
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ pendingRequests[port] = xhr;
+ }
+ });
+ } else {
+ // Proxy ajax
+ var ajax = $.ajax;
+ $.ajax = function(settings) {
+ var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
+ port = ( "port" in settings ? settings : $.ajaxSettings ).port;
+ if (mode == "abort") {
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ return (pendingRequests[port] = ajax.apply(this, arguments));
+ }
+ return ajax.apply(this, arguments);
+ };
+ }
+})(jQuery);
+
+// provides cross-browser focusin and focusout events
+// IE has native support, in other browsers, use event caputuring (neither bubbles)
+
+// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
+// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
+;(function($) {
+ // only implement if not provided by jQuery core (since 1.4)
+ // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
+ if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
+ $.each({
+ focus: 'focusin',
+ blur: 'focusout'
+ }, function( original, fix ){
+ $.event.special[fix] = {
+ setup:function() {
+ this.addEventListener( original, handler, true );
+ },
+ teardown:function() {
+ this.removeEventListener( original, handler, true );
+ },
+ handler: function(e) {
+ arguments[0] = $.event.fix(e);
+ arguments[0].type = fix;
+ return $.event.handle.apply(this, arguments);
+ }
+ };
+ function handler(e) {
+ e = $.event.fix(e);
+ e.type = fix;
+ return $.event.handle.call(this, e);
+ }
+ });
+ };
+ $.extend($.fn, {
+ validateDelegate: function(delegate, type, handler) {
+ return this.bind(type, function(event) {
+ var target = $(event.target);
+ if (target.is(delegate)) {
+ return handler.apply(target, arguments);
+ }
+ });
+ }
+ });
+})(jQuery);
diff --git a/addons/web/static/lib/jquery/jquery-1.6.2.js b/addons/web/static/lib/jquery/jquery-1.6.2.js
new file mode 100644
index 00000000000..f3201aacb6f
--- /dev/null
+++ b/addons/web/static/lib/jquery/jquery-1.6.2.js
@@ -0,0 +1,8981 @@
+/*!
+ * jQuery JavaScript Library v1.6.2
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Jun 30 14:16:56 2011 -0400
+ */
+(function( window, undefined ) {
+
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document,
+ navigator = window.navigator,
+ location = window.location;
+var jQuery = (function() {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // A simple way to check for HTML strings or ID strings
+ // (both of which we optimize for)
+ quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+ // Check if a string has a non-whitespace character in it
+ rnotwhite = /\S/,
+
+ // Used for trimming whitespace
+ trimLeft = /^\s+/,
+ trimRight = /\s+$/,
+
+ // Check for digits
+ rdigit = /\d/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+ // Useragent RegExp
+ rwebkit = /(webkit)[ \/]([\w.]+)/,
+ ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+ rmsie = /(msie) ([\w.]+)/,
+ rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+ // Matches dashed string for camelizing
+ rdashAlpha = /-([a-z])/ig,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ },
+
+ // Keep a UserAgent string for use with jQuery.browser
+ userAgent = navigator.userAgent,
+
+ // For matching the engine and version of the browser
+ browserMatch,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // The ready event handler
+ DOMContentLoaded,
+
+ // Save a reference to some core methods
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty,
+ push = Array.prototype.push,
+ slice = Array.prototype.slice,
+ trim = String.prototype.trim,
+ indexOf = Array.prototype.indexOf,
+
+ // [[Class]] -> type pairs
+ class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), or $(undefined)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // The body element only exists once, optimize finding it
+ if ( selector === "body" && !context && document.body ) {
+ this.context = document;
+ this[0] = document.body;
+ this.selector = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ // Are we dealing with HTML string or an ID?
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = quickExpr.exec( selector );
+ }
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+ doc = (context ? context.ownerDocument || context : document);
+
+ // If a single string is passed in and it's a single tag
+ // just do a createElement and skip the rest
+ ret = rsingleTag.exec( selector );
+
+ if ( ret ) {
+ if ( jQuery.isPlainObject( context ) ) {
+ selector = [ document.createElement( ret[1] ) ];
+ jQuery.fn.attr.call( selector, context, true );
+
+ } else {
+ selector = [ doc.createElement( ret[1] ) ];
+ }
+
+ } else {
+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+ selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $("#id")
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return (context || rootjQuery).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if (selector.selector !== undefined) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.6.2",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return slice.call( this, 0 );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+ // Build a new jQuery matched element set
+ var ret = this.constructor();
+
+ if ( jQuery.isArray( elems ) ) {
+ push.apply( ret, elems );
+
+ } else {
+ jQuery.merge( ret, elems );
+ }
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + (this.selector ? " " : "") + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Attach the listeners
+ jQuery.bindReady();
+
+ // Add the callback
+ readyList.done( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, +i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ),
+ "slice", slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+ // Either a released hold or an DOMready/load event and not yet ready
+ if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger( "ready" ).unbind( "ready" );
+ }
+ }
+ },
+
+ bindReady: function() {
+ if ( readyList ) {
+ return;
+ }
+
+ readyList = jQuery._Deferred();
+
+ // Catch cases where $(document).ready() is called after the
+ // browser event has already occurred.
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Mozilla, Opera and webkit nightlies currently support this event
+ if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else if ( document.attachEvent ) {
+ // ensure firing before onload,
+ // maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var toplevel = false;
+
+ try {
+ toplevel = window.frameElement == null;
+ } catch(e) {}
+
+ if ( document.documentElement.doScroll && toplevel ) {
+ doScrollCheck();
+ }
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ // A crude way of determining if an object is a window
+ isWindow: function( obj ) {
+ return obj && typeof obj === "object" && "setInterval" in obj;
+ },
+
+ isNaN: function( obj ) {
+ return obj == null || !rdigit.test( obj ) || isNaN( obj );
+ },
+
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw msg;
+ },
+
+ parseJSON: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return (new Function( "return " + data ))();
+
+ }
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ // (xml & tmp used internally)
+ parseXML: function( data , xml , tmp ) {
+
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+
+ tmp = xml.documentElement;
+
+ if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && rnotwhite.test( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Converts a dashed string to camelCased string;
+ // Used by both the css and data modules
+ camelCase: function( string ) {
+ return string.replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0,
+ length = object.length,
+ isObj = length === undefined || jQuery.isFunction( object );
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.apply( object[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( object[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return object;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: trim ?
+ function( text ) {
+ return text == null ?
+ "" :
+ trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( array, results ) {
+ var ret = results || [];
+
+ if ( array != null ) {
+ // The window, strings (and functions) also have 'length'
+ // The extra typeof function check is to prevent crashes
+ // in Safari 2 (See: #3039)
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ var type = jQuery.type( array );
+
+ if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+ push.call( ret, array );
+ } else {
+ jQuery.merge( ret, array );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+
+ if ( indexOf ) {
+ return indexOf.call( array, elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var i = first.length,
+ j = 0;
+
+ if ( typeof second.length === "number" ) {
+ for ( var l = second.length; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [], retVal;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value, key, ret = [],
+ i = 0,
+ length = elems.length,
+ // jquery objects are treated as arrays
+ isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( key in elems ) {
+ value = callback( elems[ key ], key, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ if ( typeof context === "string" ) {
+ var tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ var args = slice.call( arguments, 2 ),
+ proxy = function() {
+ return fn.apply( context, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Mutifunctional method to get and set values to a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, key, value, exec, fn, pass ) {
+ var length = elems.length;
+
+ // Setting many attributes
+ if ( typeof key === "object" ) {
+ for ( var k in key ) {
+ jQuery.access( elems, k, key[k], exec, fn, value );
+ }
+ return elems;
+ }
+
+ // Setting one attribute
+ if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = !pass && exec && jQuery.isFunction(value);
+
+ for ( var i = 0; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+
+ return elems;
+ }
+
+ // Getting an attribute
+ return length ? fn( elems[0], key ) : undefined;
+ },
+
+ now: function() {
+ return (new Date()).getTime();
+ },
+
+ // Use of jQuery.browser is frowned upon.
+ // More details: http://docs.jquery.com/Utilities/jQuery.browser
+ uaMatch: function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = rwebkit.exec( ua ) ||
+ ropera.exec( ua ) ||
+ rmsie.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+ [];
+
+ return { browser: match[1] || "", version: match[2] || "0" };
+ },
+
+ sub: function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ return jQuerySub;
+ },
+
+ browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+ jQuery.browser[ browserMatch.browser ] = true;
+ jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+ jQuery.browser.safari = true;
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+ trimLeft = /^[\s\xA0]+/;
+ trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+ DOMContentLoaded = function() {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ };
+
+} else if ( document.attachEvent ) {
+ DOMContentLoaded = function() {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( document.readyState === "complete" ) {
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+ if ( jQuery.isReady ) {
+ return;
+ }
+
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch(e) {
+ setTimeout( doScrollCheck, 1 );
+ return;
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+}
+
+return jQuery;
+
+})();
+
+
+var // Promise methods
+ promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
+ // Static reference to slice
+ sliceDeferred = [].slice;
+
+jQuery.extend({
+ // Create a simple deferred (one callbacks list)
+ _Deferred: function() {
+ var // callbacks list
+ callbacks = [],
+ // stored [ context , args ]
+ fired,
+ // to avoid firing when already doing so
+ firing,
+ // flag to know if the deferred has been cancelled
+ cancelled,
+ // the deferred itself
+ deferred = {
+
+ // done( f1, f2, ...)
+ done: function() {
+ if ( !cancelled ) {
+ var args = arguments,
+ i,
+ length,
+ elem,
+ type,
+ _fired;
+ if ( fired ) {
+ _fired = fired;
+ fired = 0;
+ }
+ for ( i = 0, length = args.length; i < length; i++ ) {
+ elem = args[ i ];
+ type = jQuery.type( elem );
+ if ( type === "array" ) {
+ deferred.done.apply( deferred, elem );
+ } else if ( type === "function" ) {
+ callbacks.push( elem );
+ }
+ }
+ if ( _fired ) {
+ deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
+ }
+ }
+ return this;
+ },
+
+ // resolve with given context and args
+ resolveWith: function( context, args ) {
+ if ( !cancelled && !fired && !firing ) {
+ // make sure args are available (#8421)
+ args = args || [];
+ firing = 1;
+ try {
+ while( callbacks[ 0 ] ) {
+ callbacks.shift().apply( context, args );
+ }
+ }
+ finally {
+ fired = [ context, args ];
+ firing = 0;
+ }
+ }
+ return this;
+ },
+
+ // resolve with this as context and given arguments
+ resolve: function() {
+ deferred.resolveWith( this, arguments );
+ return this;
+ },
+
+ // Has this deferred been resolved?
+ isResolved: function() {
+ return !!( firing || fired );
+ },
+
+ // Cancel
+ cancel: function() {
+ cancelled = 1;
+ callbacks = [];
+ return this;
+ }
+ };
+
+ return deferred;
+ },
+
+ // Full fledged deferred (two callbacks list)
+ Deferred: function( func ) {
+ var deferred = jQuery._Deferred(),
+ failDeferred = jQuery._Deferred(),
+ promise;
+ // Add errorDeferred methods, then and promise
+ jQuery.extend( deferred, {
+ then: function( doneCallbacks, failCallbacks ) {
+ deferred.done( doneCallbacks ).fail( failCallbacks );
+ return this;
+ },
+ always: function() {
+ return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
+ },
+ fail: failDeferred.done,
+ rejectWith: failDeferred.resolveWith,
+ reject: failDeferred.resolve,
+ isRejected: failDeferred.isResolved,
+ pipe: function( fnDone, fnFail ) {
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( {
+ done: [ fnDone, "resolve" ],
+ fail: [ fnFail, "reject" ]
+ }, function( handler, data ) {
+ var fn = data[ 0 ],
+ action = data[ 1 ],
+ returned;
+ if ( jQuery.isFunction( fn ) ) {
+ deferred[ handler ](function() {
+ returned = fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise().then( newDefer.resolve, newDefer.reject );
+ } else {
+ newDefer[ action ]( returned );
+ }
+ });
+ } else {
+ deferred[ handler ]( newDefer[ action ] );
+ }
+ });
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ if ( obj == null ) {
+ if ( promise ) {
+ return promise;
+ }
+ promise = obj = {};
+ }
+ var i = promiseMethods.length;
+ while( i-- ) {
+ obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
+ }
+ return obj;
+ }
+ });
+ // Make sure only one callback list will be used
+ deferred.done( failDeferred.cancel ).fail( deferred.cancel );
+ // Unexpose cancel
+ delete deferred.cancel;
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( firstParam ) {
+ var args = arguments,
+ i = 0,
+ length = args.length,
+ count = length,
+ deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+ firstParam :
+ jQuery.Deferred();
+ function resolveFunc( i ) {
+ return function( value ) {
+ args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ if ( !( --count ) ) {
+ // Strange bug in FF4:
+ // Values changed onto the arguments object sometimes end up as undefined values
+ // outside the $.when method. Cloning the object into a fresh array solves the issue
+ deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
+ }
+ };
+ }
+ if ( length > 1 ) {
+ for( ; i < length; i++ ) {
+ if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
+ args[ i ].promise().then( resolveFunc(i), deferred.reject );
+ } else {
+ --count;
+ }
+ }
+ if ( !count ) {
+ deferred.resolveWith( deferred, args );
+ }
+ } else if ( deferred !== firstParam ) {
+ deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+ }
+ return deferred.promise();
+ }
+});
+
+
+
+jQuery.support = (function() {
+
+ var div = document.createElement( "div" ),
+ documentElement = document.documentElement,
+ all,
+ a,
+ select,
+ opt,
+ input,
+ marginDiv,
+ support,
+ fragment,
+ body,
+ testElementParent,
+ testElement,
+ testElementStyle,
+ tds,
+ events,
+ eventName,
+ i,
+ isSupported;
+
+ // Preliminary tests
+ div.setAttribute("className", "t");
+ div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+ all = div.getElementsByTagName( "*" );
+ a = div.getElementsByTagName( "a" )[ 0 ];
+
+ // Can't get basic test support
+ if ( !all || !all.length || !a ) {
+ return {};
+ }
+
+ // First batch of supports tests
+ select = document.createElement( "select" );
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName( "input" )[ 0 ];
+
+ support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName( "tbody" ).length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName( "link" ).length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.55$/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: ( input.value === "on" ),
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
+ focusinBubbles: false,
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true
+ };
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+ div.attachEvent( "onclick", function() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ support.noCloneEvent = false;
+ });
+ div.cloneNode( true ).fireEvent( "onclick" );
+ }
+
+ // Check if a radio maintains it's value
+ // after being appended to the DOM
+ input = document.createElement("input");
+ input.value = "t";
+ input.setAttribute("type", "radio");
+ support.radioValue = input.value === "t";
+
+ input.setAttribute("checked", "checked");
+ div.appendChild( input );
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( div.firstChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ div.innerHTML = "";
+
+ // Figure out if the W3C box model works as expected
+ div.style.width = div.style.paddingLeft = "1px";
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ // We use our own, invisible, body unless the body is already present
+ // in which case we use a div (#9239)
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0
+ };
+ if ( body ) {
+ jQuery.extend( testElementStyle, {
+ position: "absolute",
+ left: -1000,
+ top: -1000
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ support.boxModel = div.offsetWidth === 2;
+
+ if ( "zoom" in div.style ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "";
+ div.innerHTML = "<div style='width:4px;'></div>";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
+ }
+
+ div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName( "td" );
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE < 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+ div.innerHTML = "";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ marginDiv = document.createElement( "div" );
+ marginDiv.style.width = "0";
+ marginDiv.style.marginRight = "0";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+ }
+
+ // Remove the body element we added
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+
+ // Technique from Juriy Zaytsev
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( div.attachEvent ) {
+ for( i in {
+ submit: 1,
+ change: 1,
+ focusin: 1
+ } ) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, "return;" );
+ isSupported = ( typeof div[ eventName ] === "function" );
+ }
+ support[ i + "Bubbles" ] = isSupported;
+ }
+ }
+
+ // Null connected elements to avoid leaks in IE
+ testElement = fragment = select = opt = body = marginDiv = div = input = null;
+
+ return support;
+})();
+
+// Keep track of boxModel
+jQuery.boxModel = jQuery.support.boxModel;
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+ rmultiDash = /([a-z])([A-Z])/g;
+
+jQuery.extend({
+ cache: {},
+
+ // Please use with caution
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ jQuery.expando ] = id = ++jQuery.uuid;
+ } else {
+ id = jQuery.expando;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+ // metadata on plain JS objects when the object is serialized using
+ // JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+ } else {
+ cache[ id ] = jQuery.extend(cache[ id ], name);
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // Internal jQuery data is stored in a separate object inside the object's data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data
+ if ( pvt ) {
+ if ( !thisCache[ internalKey ] ) {
+ thisCache[ internalKey ] = {};
+ }
+
+ thisCache = thisCache[ internalKey ];
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
+ // not attempt to inspect the internal events object using jQuery.data, as this
+ // internal data object is undocumented and subject to change.
+ if ( name === "events" && !thisCache[name] ) {
+ return thisCache[ internalKey ] && thisCache[ internalKey ].events;
+ }
+
+ return getByName ?
+ // Check for both converted-to-camel and non-converted data property names
+ thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] :
+ thisCache;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var internalKey = jQuery.expando, isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+
+ // See jQuery.data for more information
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+ var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+
+ if ( thisCache ) {
+ delete thisCache[ name ];
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !isEmptyDataObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( pvt ) {
+ delete cache[ id ][ internalKey ];
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject(cache[ id ]) ) {
+ return;
+ }
+ }
+
+ var internalCache = cache[ id ][ internalKey ];
+
+ // Browsers that fail expando deletion also refuse to delete expandos on
+ // the window, but it will allow it on all other JS objects; other browsers
+ // don't care
+ if ( jQuery.support.deleteExpando || cache != window ) {
+ delete cache[ id ];
+ } else {
+ cache[ id ] = null;
+ }
+
+ // We destroyed the entire user cache at once because it's faster than
+ // iterating through each key, but we need to continue to persist internal
+ // data if it existed
+ if ( internalCache ) {
+ cache[ id ] = {};
+ // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+ // metadata on plain JS objects when the object is serialized using
+ // JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+
+ cache[ id ][ internalKey ] = internalCache;
+
+ // Otherwise, we need to eliminate the expando on the node to avoid
+ // false lookups in the cache for entries that no longer exist
+ } else if ( isNode ) {
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( jQuery.support.deleteExpando ) {
+ delete elem[ jQuery.expando ];
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ } else {
+ elem[ jQuery.expando ] = null;
+ }
+ }
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ if ( elem.nodeName ) {
+ var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ if ( match ) {
+ return !(match === true || elem.getAttribute("classid") !== match);
+ }
+ }
+
+ return true;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var data = null;
+
+ if ( typeof key === "undefined" ) {
+ if ( this.length ) {
+ data = jQuery.data( this[0] );
+
+ if ( this[0].nodeType === 1 ) {
+ var attr = this[0].attributes, name;
+ for ( var i = 0, l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.substring(5) );
+
+ dataAttr( this[0], name, data[ name ] );
+ }
+ }
+ }
+ }
+
+ return data;
+
+ } else if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value === undefined ) {
+ data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && this.length ) {
+ data = jQuery.data( this[0], key );
+ data = dataAttr( this[0], key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+
+ } else {
+ return this.each(function() {
+ var $this = jQuery( this ),
+ args = [ parts[0], value ];
+
+ $this.triggerHandler( "setData" + parts[1] + "!", args );
+ jQuery.data( this, key, value );
+ $this.triggerHandler( "changeData" + parts[1] + "!", args );
+ });
+ }
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ !jQuery.isNaN( data ) ? parseFloat( data ) :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
+// property to be considered empty objects; this property always exists in
+// order to make sure JSON.stringify does not expose internal metadata
+function isEmptyDataObject( obj ) {
+ for ( var name in obj ) {
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+function handleQueueMarkDefer( elem, type, src ) {
+ var deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ defer = jQuery.data( elem, deferDataKey, undefined, true );
+ if ( defer &&
+ ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
+ ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
+ // Give room for hard-coded callbacks to fire first
+ // and eventually mark/queue something else on the element
+ setTimeout( function() {
+ if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
+ !jQuery.data( elem, markDataKey, undefined, true ) ) {
+ jQuery.removeData( elem, deferDataKey, true );
+ defer.resolve();
+ }
+ }, 0 );
+ }
+}
+
+jQuery.extend({
+
+ _mark: function( elem, type ) {
+ if ( elem ) {
+ type = (type || "fx") + "mark";
+ jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
+ }
+ },
+
+ _unmark: function( force, elem, type ) {
+ if ( force !== true ) {
+ type = elem;
+ elem = force;
+ force = false;
+ }
+ if ( elem ) {
+ type = type || "fx";
+ var key = type + "mark",
+ count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
+ if ( count ) {
+ jQuery.data( elem, key, count, true );
+ } else {
+ jQuery.removeData( elem, key, true );
+ handleQueueMarkDefer( elem, type, "mark" );
+ }
+ }
+ },
+
+ queue: function( elem, type, data ) {
+ if ( elem ) {
+ type = (type || "fx") + "queue";
+ var q = jQuery.data( elem, type, undefined, true );
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !q || jQuery.isArray(data) ) {
+ q = jQuery.data( elem, type, jQuery.makeArray(data), true );
+ } else {
+ q.push( data );
+ }
+ }
+ return q || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ fn = queue.shift(),
+ defer;
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ }
+
+ if ( fn ) {
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift("inprogress");
+ }
+
+ fn.call(elem, function() {
+ jQuery.dequeue(elem, type);
+ });
+ }
+
+ if ( !queue.length ) {
+ jQuery.removeData( elem, type + "queue", true );
+ handleQueueMarkDefer( elem, type, "queue" );
+ }
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ }
+
+ if ( data === undefined ) {
+ return jQuery.queue( this[0], type );
+ }
+ return this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function() {
+ var elem = this;
+ setTimeout(function() {
+ jQuery.dequeue( elem, type );
+ }, time );
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, object ) {
+ if ( typeof type !== "string" ) {
+ object = type;
+ type = undefined;
+ }
+ type = type || "fx";
+ var defer = jQuery.Deferred(),
+ elements = this,
+ i = elements.length,
+ count = 1,
+ deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ tmp;
+ function resolve() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ }
+ while( i-- ) {
+ if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+ ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
+ jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
+ jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+ count++;
+ tmp.done( resolve );
+ }
+ }
+ resolve();
+ return defer.promise();
+ }
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+ rspace = /\s+/,
+ rreturn = /\r/g,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea)?$/i,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ rinvalidChar = /\:|^on/,
+ formHook, boolHook;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, name, value, true, jQuery.attr );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, name, value, true, jQuery.prop );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classNames, i, l, elem,
+ setClass, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ classNames = value.split( rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className && classNames.length === 1 ) {
+ elem.className = value;
+
+ } else {
+ setClass = " " + elem.className + " ";
+
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
+ setClass += classNames[ c ] + " ";
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classNames, i, l, elem, className, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( (value && typeof value === "string") || value === undefined ) {
+ classNames = (value || "").split( rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 && elem.className ) {
+ if ( value ) {
+ className = (" " + elem.className + " ").replace( rclass, " " );
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ className = className.replace(" " + classNames[ c ] + " ", " ");
+ }
+ elem.className = jQuery.trim( className );
+
+ } else {
+ elem.className = "";
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.split( rspace );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space seperated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ";
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return undefined;
+ }
+
+ var isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var self = jQuery(this), val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value,
+ index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type === "select-one";
+
+ // Nothing was selected
+ if ( index < 0 ) {
+ return null;
+ }
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ // Don't return options that are disabled or in a disabled optgroup
+ if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+ (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+ if ( one && !values.length && options.length ) {
+ return jQuery( options[ index ] ).val();
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attrFn: {
+ val: true,
+ css: true,
+ html: true,
+ text: true,
+ data: true,
+ width: true,
+ height: true,
+ offset: true
+ },
+
+ attrFix: {
+ // Always normalize to ensure hook usage
+ tabindex: "tabIndex"
+ },
+
+ attr: function( elem, name, value, pass ) {
+ var nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return undefined;
+ }
+
+ if ( pass && name in jQuery.attrFn ) {
+ return jQuery( elem )[ name ]( value );
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( !("getAttribute" in elem) ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ var ret, hooks,
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // Normalize the name if needed
+ if ( notxml ) {
+ name = jQuery.attrFix[ name ] || name;
+
+ hooks = jQuery.attrHooks[ name ];
+
+ if ( !hooks ) {
+ // Use boolHook for boolean attributes
+ if ( rboolean.test( name ) ) {
+
+ hooks = boolHook;
+
+ // Use formHook for forms and if the name contains certain characters
+ } else if ( formHook && name !== "className" &&
+ (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) {
+
+ hooks = formHook;
+ }
+ }
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return undefined;
+
+ } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, "" + value );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ ret = elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret === null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, name ) {
+ var propName;
+ if ( elem.nodeType === 1 ) {
+ name = jQuery.attrFix[ name ] || name;
+
+ if ( jQuery.support.getSetAttribute ) {
+ // Use removeAttribute in browsers that support it
+ elem.removeAttribute( name );
+ } else {
+ jQuery.attr( elem, name, "" );
+ elem.removeAttributeNode( elem.getAttributeNode( name ) );
+ }
+
+ // Set corresponding property to false for boolean attributes
+ if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
+ elem[ propName ] = false;
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to it's default in case type is set after value
+ // This is for element creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ },
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabIndex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ },
+ // Use the value property for back compat
+ // Use the formHook for button elements in IE6/7 (#1954)
+ value: {
+ get: function( elem, name ) {
+ if ( formHook && jQuery.nodeName( elem, "button" ) ) {
+ return formHook.get( elem, name );
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value, name ) {
+ if ( formHook && jQuery.nodeName( elem, "button" ) ) {
+ return formHook.set( elem, value, name );
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return undefined;
+ }
+
+ var ret, hooks,
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return (elem[ name ] = value);
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {}
+});
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ return jQuery.prop( elem, name ) ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !jQuery.support.getSetAttribute ) {
+
+ // propFix is more comprehensive and contains all fixes
+ jQuery.attrFix = jQuery.propFix;
+
+ // Use this for any attribute on a form in IE6/7
+ formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret;
+ ret = elem.getAttributeNode( name );
+ // Return undefined if nodeValue is empty string
+ return ret && ret.nodeValue !== "" ?
+ ret.nodeValue :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Check form objects in IE (multiple bugs related)
+ // Only use nodeValue if the attribute node exists on the form
+ var ret = elem.getAttributeNode( name );
+ if ( ret ) {
+ ret.nodeValue = value;
+ return value;
+ }
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret === null ? undefined : ret;
+ }
+ });
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Normalize to lowercase since IE uppercases css property names
+ return elem.style.cssText.toLowerCase() || undefined;
+ },
+ set: function( elem, value ) {
+ return (elem.style.cssText = "" + value);
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+ });
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
+ }
+ }
+ });
+});
+
+
+
+
+var rnamespaces = /\.(.*)$/,
+ rformElems = /^(?:textarea|input|select)$/i,
+ rperiod = /\./g,
+ rspaces = / /g,
+ rescape = /[^\w\s.|`]/g,
+ fcleanup = function( nm ) {
+ return nm.replace(rescape, "\\$&");
+ };
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function( elem, types, handler, data ) {
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ if ( handler === false ) {
+ handler = returnFalse;
+ } else if ( !handler ) {
+ // Fixes bug #7229. Fix recommended by jdalton
+ return;
+ }
+
+ var handleObjIn, handleObj;
+
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ }
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure
+ var elemData = jQuery._data( elem );
+
+ // If no elemData is found then we must be trying to bind to one of the
+ // banned noData elements
+ if ( !elemData ) {
+ return;
+ }
+
+ var events = elemData.events,
+ eventHandle = elemData.handle;
+
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ }
+
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native events in IE.
+ eventHandle.elem = elem;
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ var type, i = 0, namespaces;
+
+ while ( (type = types[ i++ ]) ) {
+ handleObj = handleObjIn ?
+ jQuery.extend({}, handleObjIn) :
+ { handler: handler, data: data };
+
+ // Namespaced event handlers
+ if ( type.indexOf(".") > -1 ) {
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+ } else {
+ namespaces = [];
+ handleObj.namespace = "";
+ }
+
+ handleObj.type = type;
+ if ( !handleObj.guid ) {
+ handleObj.guid = handler.guid;
+ }
+
+ // Get the current list of functions bound to this event
+ var handlers = events[ type ],
+ special = jQuery.event.special[ type ] || {};
+
+ // Init the event handler queue
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers.push( handleObj );
+
+ // Keep track of which events have been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, pos ) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ if ( handler === false ) {
+ handler = returnFalse;
+ }
+
+ var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ events = elemData && elemData.events;
+
+ if ( !elemData || !events ) {
+ return;
+ }
+
+ // types is actually an event object here
+ if ( types && types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Unbind all events for the element
+ if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+ types = types || "";
+
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types );
+ }
+
+ return;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ while ( (type = types[ i++ ]) ) {
+ origType = type;
+ handleObj = null;
+ all = type.indexOf(".") < 0;
+ namespaces = [];
+
+ if ( !all ) {
+ // Namespaced event handlers
+ namespaces = type.split(".");
+ type = namespaces.shift();
+
+ namespace = new RegExp("(^|\\.)" +
+ jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ eventType = events[ type ];
+
+ if ( !eventType ) {
+ continue;
+ }
+
+ if ( !handler ) {
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ jQuery.event.remove( elem, origType, handleObj.handler, j );
+ eventType.splice( j--, 1 );
+ }
+ }
+
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+
+ for ( j = pos || 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( handler.guid === handleObj.guid ) {
+ // remove the given handler for the given type
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ if ( pos == null ) {
+ eventType.splice( j--, 1 );
+ }
+
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+
+ if ( pos != null ) {
+ break;
+ }
+ }
+ }
+
+ // remove generic event handler if no more handlers exist
+ if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ ret = null;
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ var handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ delete elemData.events;
+ delete elemData.handle;
+
+ if ( jQuery.isEmptyObject( elemData ) ) {
+ jQuery.removeData( elem, undefined, true );
+ }
+ }
+ },
+
+ // Events that are safe to short-circuit if no handlers are attached.
+ // Native DOM events should not be added, they may have inline handlers.
+ customEvent: {
+ "getData": true,
+ "setData": true,
+ "changeData": true
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ // Event object or event type
+ var type = event.type || event,
+ namespaces = [],
+ exclusive;
+
+ if ( type.indexOf("!") >= 0 ) {
+ // Exclusive events trigger only for the exact event (no namespaces)
+ type = type.slice(0, -1);
+ exclusive = true;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+
+ if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+ // No jQuery handlers for this event type, and it can't have inline handlers
+ return;
+ }
+
+ // Caller can pass in an Event, Object, or just an event type string
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[ jQuery.expando ] ? event :
+ // Object literal
+ new jQuery.Event( type, event ) :
+ // Just the event type (string)
+ new jQuery.Event( type );
+
+ event.type = type;
+ event.exclusive = exclusive;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
+
+ // triggerHandler() and global events don't bubble or run the default action
+ if ( onlyHandlers || !elem ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // TODO: Stop taunting the data cache; remove global events and always attach to document
+ jQuery.each( jQuery.cache, function() {
+ // internalKey variable is just used to make it easier to find
+ // and potentially change this stuff later; currently it just
+ // points to jQuery.expando
+ var internalKey = jQuery.expando,
+ internalCache = this[ internalKey ];
+ if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
+ jQuery.event.trigger( event, data, internalCache.handle.elem );
+ }
+ });
+ return;
+ }
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ event.target = elem;
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data != null ? jQuery.makeArray( data ) : [];
+ data.unshift( event );
+
+ var cur = elem,
+ // IE doesn't like method names with a colon (#3533, #8272)
+ ontype = type.indexOf(":") < 0 ? "on" + type : "";
+
+ // Fire event on the current element, then bubble up the DOM tree
+ do {
+ var handle = jQuery._data( cur, "handle" );
+
+ event.currentTarget = cur;
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Trigger an inline bound script
+ if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
+ event.result = false;
+ event.preventDefault();
+ }
+
+ // Bubble up to document, then to window
+ cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
+ } while ( cur && !event.isPropagationStopped() );
+
+ // If nobody prevented the default action, do it now
+ if ( !event.isDefaultPrevented() ) {
+ var old,
+ special = jQuery.event.special[ type ] || {};
+
+ if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction)() check here because IE6/7 fails that test.
+ // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
+ try {
+ if ( ontype && elem[ type ] ) {
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
+
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ }
+ } catch ( ieError ) {}
+
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+
+ jQuery.event.triggered = undefined;
+ }
+ }
+
+ return event.result;
+ },
+
+ handle: function( event ) {
+ event = jQuery.event.fix( event || window.event );
+ // Snapshot the handlers list since a called handler may add/remove events.
+ var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
+ run_all = !event.exclusive && !event.namespace,
+ args = Array.prototype.slice.call( arguments, 0 );
+
+ // Use the fix-ed Event rather than the (read-only) native event
+ args[0] = event;
+ event.currentTarget = this;
+
+ for ( var j = 0, l = handlers.length; j < l; j++ ) {
+ var handleObj = handlers[ j ];
+
+ // Triggered event must 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event.
+ if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handleObj.handler;
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ var ret = handleObj.handler.apply( this, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
+ }
+ }
+ return event.result;
+ },
+
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // store a copy of the original event object
+ // and "clone" to set read-only properties
+ var originalEvent = event;
+ event = jQuery.Event( originalEvent );
+
+ for ( var i = this.props.length, prop; i; ) {
+ prop = this.props[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary
+ if ( !event.target ) {
+ // Fixes #1925 where srcElement might not be defined either
+ event.target = event.srcElement || document;
+ }
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement ) {
+ event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+ }
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var eventDocument = event.target.ownerDocument || document,
+ doc = eventDocument.documentElement,
+ body = eventDocument.body;
+
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+ event.which = event.charCode != null ? event.charCode : event.keyCode;
+ }
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey ) {
+ event.metaKey = event.ctrlKey;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button !== undefined ) {
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+ }
+
+ return event;
+ },
+
+ // Deprecated, use jQuery.guid instead
+ guid: 1E8,
+
+ // Deprecated, use jQuery.proxy instead
+ proxy: jQuery.proxy,
+
+ special: {
+ ready: {
+ // Make sure the ready event is setup
+ setup: jQuery.bindReady,
+ teardown: jQuery.noop
+ },
+
+ live: {
+ add: function( handleObj ) {
+ jQuery.event.add( this,
+ liveConvert( handleObj.origType, handleObj.selector ),
+ jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
+ },
+
+ remove: function( handleObj ) {
+ jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
+ }
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
+ }
+ },
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ if ( elem.detachEvent ) {
+ elem.detachEvent( "on" + type, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !this.preventDefault ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // timeStamp is buggy for some events on Firefox(#3843)
+ // So we won't rely on the native value
+ this.timeStamp = jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // otherwise set the returnValue property of the original event to false (IE)
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function( event ) {
+
+ // Check if mouse(over|out) are still within the same parent element
+ var related = event.relatedTarget,
+ inside = false,
+ eventType = event.type;
+
+ event.type = event.data;
+
+ if ( related !== this ) {
+
+ if ( related ) {
+ inside = jQuery.contains( this, related );
+ }
+
+ if ( !inside ) {
+
+ jQuery.event.handle.apply( this, arguments );
+
+ event.type = eventType;
+ }
+ }
+},
+
+// In case of event delegation, we only need to rename the event.type,
+// liveHandler will take care of the rest.
+delegate = function( event ) {
+ event.type = event.data;
+ jQuery.event.handle.apply( this, arguments );
+};
+
+// Create mouseenter and mouseleave events
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ setup: function( data ) {
+ jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
+ },
+ teardown: function( data ) {
+ jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+ }
+ };
+});
+
+// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function( data, namespaces ) {
+ if ( !jQuery.nodeName( this, "form" ) ) {
+ jQuery.event.add(this, "click.specialSubmit", function( e ) {
+ var elem = e.target,
+ type = elem.type;
+
+ if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+ trigger( "submit", this, arguments );
+ }
+ });
+
+ jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+ var elem = e.target,
+ type = elem.type;
+
+ if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+ trigger( "submit", this, arguments );
+ }
+ });
+
+ } else {
+ return false;
+ }
+ },
+
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialSubmit" );
+ }
+ };
+
+}
+
+// change delegation, happens here so we have bind.
+if ( !jQuery.support.changeBubbles ) {
+
+ var changeFilters,
+
+ getVal = function( elem ) {
+ var type = elem.type, val = elem.value;
+
+ if ( type === "radio" || type === "checkbox" ) {
+ val = elem.checked;
+
+ } else if ( type === "select-multiple" ) {
+ val = elem.selectedIndex > -1 ?
+ jQuery.map( elem.options, function( elem ) {
+ return elem.selected;
+ }).join("-") :
+ "";
+
+ } else if ( jQuery.nodeName( elem, "select" ) ) {
+ val = elem.selectedIndex;
+ }
+
+ return val;
+ },
+
+ testChange = function testChange( e ) {
+ var elem = e.target, data, val;
+
+ if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
+ return;
+ }
+
+ data = jQuery._data( elem, "_change_data" );
+ val = getVal(elem);
+
+ // the current data will be also retrieved by beforeactivate
+ if ( e.type !== "focusout" || elem.type !== "radio" ) {
+ jQuery._data( elem, "_change_data", val );
+ }
+
+ if ( data === undefined || val === data ) {
+ return;
+ }
+
+ if ( data != null || val ) {
+ e.type = "change";
+ e.liveFired = undefined;
+ jQuery.event.trigger( e, arguments[1], elem );
+ }
+ };
+
+ jQuery.event.special.change = {
+ filters: {
+ focusout: testChange,
+
+ beforedeactivate: testChange,
+
+ click: function( e ) {
+ var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+
+ if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
+ testChange.call( this, e );
+ }
+ },
+
+ // Change has to be called before submit
+ // Keydown will be called before keypress, which is used in submit-event delegation
+ keydown: function( e ) {
+ var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+
+ if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
+ (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+ type === "select-multiple" ) {
+ testChange.call( this, e );
+ }
+ },
+
+ // Beforeactivate happens also before the previous element is blurred
+ // with this event you can't trigger a change event, but you can store
+ // information
+ beforeactivate: function( e ) {
+ var elem = e.target;
+ jQuery._data( elem, "_change_data", getVal(elem) );
+ }
+ },
+
+ setup: function( data, namespaces ) {
+ if ( this.type === "file" ) {
+ return false;
+ }
+
+ for ( var type in changeFilters ) {
+ jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+ }
+
+ return rformElems.test( this.nodeName );
+ },
+
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialChange" );
+
+ return rformElems.test( this.nodeName );
+ }
+ };
+
+ changeFilters = jQuery.event.special.change.filters;
+
+ // Handle when the input is .focus()'d
+ changeFilters.focus = changeFilters.beforeactivate;
+}
+
+function trigger( type, elem, args ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ // Don't pass args or remember liveFired; they apply to the donor event.
+ var event = jQuery.extend( {}, args[ 0 ] );
+ event.type = type;
+ event.originalEvent = {};
+ event.liveFired = undefined;
+ jQuery.event.handle.call( elem, event );
+ if ( event.isDefaultPrevented() ) {
+ args[ 0 ].preventDefault();
+ }
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0;
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+
+ function handler( donor ) {
+ // Donor event is always a native one; fix it and switch its type.
+ // Let focusin/out handler cancel the donor focus/blur event.
+ var e = jQuery.event.fix( donor );
+ e.type = fix;
+ e.originalEvent = {};
+ jQuery.event.trigger( e, null, e.target );
+ if ( e.isDefaultPrevented() ) {
+ donor.preventDefault();
+ }
+ }
+ });
+}
+
+jQuery.each(["bind", "one"], function( i, name ) {
+ jQuery.fn[ name ] = function( type, data, fn ) {
+ var handler;
+
+ // Handle object literals
+ if ( typeof type === "object" ) {
+ for ( var key in type ) {
+ this[ name ](key, data, type[key], fn);
+ }
+ return this;
+ }
+
+ if ( arguments.length === 2 || data === false ) {
+ fn = data;
+ data = undefined;
+ }
+
+ if ( name === "one" ) {
+ handler = function( event ) {
+ jQuery( this ).unbind( event, handler );
+ return fn.apply( this, arguments );
+ };
+ handler.guid = fn.guid || jQuery.guid++;
+ } else {
+ handler = fn;
+ }
+
+ if ( type === "unload" && name !== "one" ) {
+ this.one( type, data, fn );
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.add( this[i], type, handler, data );
+ }
+ }
+
+ return this;
+ };
+});
+
+jQuery.fn.extend({
+ unbind: function( type, fn ) {
+ // Handle object literals
+ if ( typeof type === "object" && !type.preventDefault ) {
+ for ( var key in type ) {
+ this.unbind(key, type[key]);
+ }
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.remove( this[i], type, fn );
+ }
+ }
+
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.live( types, data, fn, selector );
+ },
+
+ undelegate: function( selector, types, fn ) {
+ if ( arguments.length === 0 ) {
+ return this.unbind( "live" );
+
+ } else {
+ return this.die( types, null, fn, selector );
+ }
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ return jQuery.event.trigger( type, data, this[0], true );
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+var liveMap = {
+ focus: "focusin",
+ blur: "focusout",
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+};
+
+jQuery.each(["live", "die"], function( i, name ) {
+ jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+ var type, i = 0, match, namespaces, preType,
+ selector = origSelector || this.selector,
+ context = origSelector ? this : jQuery( this.context );
+
+ if ( typeof types === "object" && !types.preventDefault ) {
+ for ( var key in types ) {
+ context[ name ]( key, data, types[key], selector );
+ }
+
+ return this;
+ }
+
+ if ( name === "die" && !types &&
+ origSelector && origSelector.charAt(0) === "." ) {
+
+ context.unbind( origSelector );
+
+ return this;
+ }
+
+ if ( data === false || jQuery.isFunction( data ) ) {
+ fn = data || returnFalse;
+ data = undefined;
+ }
+
+ types = (types || "").split(" ");
+
+ while ( (type = types[ i++ ]) != null ) {
+ match = rnamespaces.exec( type );
+ namespaces = "";
+
+ if ( match ) {
+ namespaces = match[0];
+ type = type.replace( rnamespaces, "" );
+ }
+
+ if ( type === "hover" ) {
+ types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+ continue;
+ }
+
+ preType = type;
+
+ if ( liveMap[ type ] ) {
+ types.push( liveMap[ type ] + namespaces );
+ type = type + namespaces;
+
+ } else {
+ type = (liveMap[ type ] || type) + namespaces;
+ }
+
+ if ( name === "live" ) {
+ // bind live handler
+ for ( var j = 0, l = context.length; j < l; j++ ) {
+ jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
+ { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+ }
+
+ } else {
+ // unbind live handler
+ context.unbind( "live." + liveConvert( type, selector ), fn );
+ }
+ }
+
+ return this;
+ };
+});
+
+function liveHandler( event ) {
+ var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+ elems = [],
+ selectors = [],
+ events = jQuery._data( this, "events" );
+
+ // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
+ if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
+ return;
+ }
+
+ if ( event.namespace ) {
+ namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ event.liveFired = this;
+
+ var live = events.live.slice(0);
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+ selectors.push( handleObj.selector );
+
+ } else {
+ live.splice( j--, 1 );
+ }
+ }
+
+ match = jQuery( event.target ).closest( selectors, event.currentTarget );
+
+ for ( i = 0, l = match.length; i < l; i++ ) {
+ close = match[i];
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
+ elem = close.elem;
+ related = null;
+
+ // Those two events require additional checking
+ if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+ event.type = handleObj.preType;
+ related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
+
+ // Make sure not to accidentally match a child element with the same selector
+ if ( related && jQuery.contains( elem, related ) ) {
+ related = elem;
+ }
+ }
+
+ if ( !related || related !== elem ) {
+ elems.push({ elem: elem, handleObj: handleObj, level: close.level });
+ }
+ }
+ }
+ }
+
+ for ( i = 0, l = elems.length; i < l; i++ ) {
+ match = elems[i];
+
+ if ( maxLevel && match.level > maxLevel ) {
+ break;
+ }
+
+ event.currentTarget = match.elem;
+ event.data = match.handleObj.data;
+ event.handleObj = match.handleObj;
+
+ ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+ if ( ret === false || event.isPropagationStopped() ) {
+ maxLevel = match.level;
+
+ if ( ret === false ) {
+ stop = false;
+ }
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
+ }
+ }
+
+ return stop;
+}
+
+function liveConvert( type, selector ) {
+ return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
+}
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.bind( name, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
+});
+
+
+
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+
+ var origContext = context;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var m, set, checkSet, extra, ret, cur, pop, i,
+ prune = true,
+ contextXML = Sizzle.isXML( context ),
+ parts = [],
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ do {
+ chunker.exec( "" );
+ m = chunker.exec( soFar );
+
+ if ( m ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+ } while ( m );
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context );
+
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set );
+ }
+ }
+
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+ ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set )[0] :
+ ret.set[0];
+ }
+
+ if ( context ) {
+ ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+ set = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set ) :
+ ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray( set );
+
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ cur = parts.pop();
+ pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+
+ } else if ( context && context.nodeType === 1 ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+
+ } else {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[ i - 1 ] ) {
+ results.splice( i--, 1 );
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+ return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+ return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+ var set;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var match,
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ var left = match[1];
+ match.splice( 1, 1 );
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace( rBackslash, "" );
+ set = Expr.find[ type ]( match, context, isXML );
+
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( "*" ) :
+ [];
+ }
+
+ return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+ var match, anyFound,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ var found, item,
+ filter = Expr.filter[ type ],
+ left = match[1];
+
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+
+ } else {
+ curLoop[i] = false;
+ }
+
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+
+ leftMatch: {},
+
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+
+ attrHandle: {
+ href: function( elem ) {
+ return elem.getAttribute( "href" );
+ },
+ type: function( elem ) {
+ return elem.getAttribute( "type" );
+ }
+ },
+
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !rNonWord.test( part ),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+
+ ">": function( checkSet, part ) {
+ var elem,
+ isPartStr = typeof part === "string",
+ i = 0,
+ l = checkSet.length;
+
+ if ( isPartStr && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+
+ } else {
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+
+ "": function(checkSet, part, isXML){
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+ },
+
+ "~": function( checkSet, part, isXML ) {
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+ }
+ },
+
+ find: {
+ ID: function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ },
+
+ NAME: function( match, context ) {
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [],
+ results = context.getElementsByName( match[1] );
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+
+ TAG: function( match, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( match[1] );
+ }
+ }
+ },
+ preFilter: {
+ CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+ match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ ID: function( match ) {
+ return match[1].replace( rBackslash, "" );
+ },
+
+ TAG: function( match, curLoop ) {
+ return match[1].replace( rBackslash, "" ).toLowerCase();
+ },
+
+ CHILD: function( match ) {
+ if ( match[1] === "nth" ) {
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[2] = match[2].replace(/^\+|\s*/g, '');
+
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+ else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+
+ ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+ var name = match[1] = match[1].replace( rBackslash, "" );
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ // Handle if an un-quoted value was used
+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+
+ PSEUDO: function( match, curLoop, inplace, result, not ) {
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+
+ return false;
+ }
+
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+
+ POS: function( match ) {
+ match.unshift( true );
+
+ return match;
+ }
+ },
+
+ filters: {
+ enabled: function( elem ) {
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+
+ disabled: function( elem ) {
+ return elem.disabled === true;
+ },
+
+ checked: function( elem ) {
+ return elem.checked === true;
+ },
+
+ selected: function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ parent: function( elem ) {
+ return !!elem.firstChild;
+ },
+
+ empty: function( elem ) {
+ return !elem.firstChild;
+ },
+
+ has: function( elem, i, match ) {
+ return !!Sizzle( match[3], elem ).length;
+ },
+
+ header: function( elem ) {
+ return (/h\d/i).test( elem.nodeName );
+ },
+
+ text: function( elem ) {
+ var attr = elem.getAttribute( "type" ), type = elem.type;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+ },
+
+ radio: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+ },
+
+ checkbox: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+ },
+
+ file: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+ },
+
+ password: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+ },
+
+ submit: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "submit" === elem.type;
+ },
+
+ image: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+ },
+
+ reset: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "reset" === elem.type;
+ },
+
+ button: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && "button" === elem.type || name === "button";
+ },
+
+ input: function( elem ) {
+ return (/input|select|textarea|button/i).test( elem.nodeName );
+ },
+
+ focus: function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ }
+ },
+ setFilters: {
+ first: function( elem, i ) {
+ return i === 0;
+ },
+
+ last: function( elem, i, match, array ) {
+ return i === array.length - 1;
+ },
+
+ even: function( elem, i ) {
+ return i % 2 === 0;
+ },
+
+ odd: function( elem, i ) {
+ return i % 2 === 1;
+ },
+
+ lt: function( elem, i, match ) {
+ return i < match[3] - 0;
+ },
+
+ gt: function( elem, i, match ) {
+ return i > match[3] - 0;
+ },
+
+ nth: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ },
+
+ eq: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function( elem, match, i, array ) {
+ var name = match[1],
+ filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ } else {
+ Sizzle.error( name );
+ }
+ },
+
+ CHILD: function( elem, match ) {
+ var type = match[1],
+ node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ var first = match[2],
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ var doneName = match[0],
+ parent = elem.parentNode;
+
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+ var count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent.sizcache = doneName;
+ }
+
+ var diff = elem.nodeIndex - last;
+
+ if ( first === 0 ) {
+ return diff === 0;
+
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+
+ ID: function( elem, match ) {
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+
+ TAG: function( elem, match ) {
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+ },
+
+ CLASS: function( elem, match ) {
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+
+ ATTR: function( elem, match ) {
+ var name = match[1],
+ result = Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+
+ POS: function( elem, match, i, array ) {
+ var name = match[2],
+ filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+
+var makeArray = function( array, results ) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+ makeArray = function( array, results ) {
+ var i = 0,
+ ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+
+ } else {
+ for ( ; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+ };
+
+} else {
+ sortOrder = function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+ };
+}
+
+// Utility function for retreiving the text value of an array of DOM nodes
+Sizzle.getText = function( elems ) {
+ var ret = "", elem;
+
+ for ( var i = 0; elems[i]; i++ ) {
+ elem = elems[i];
+
+ // Get the text from text nodes and CDATA nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+ ret += elem.nodeValue;
+
+ // Traverse everything else, except comment nodes
+ } else if ( elem.nodeType !== 8 ) {
+ ret += Sizzle.getText( elem.childNodes );
+ }
+ }
+
+ return ret;
+};
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date()).getTime(),
+ root = document.documentElement;
+
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+
+ return m ?
+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+
+ Expr.filter.ID = function( elem, match ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+
+ // release memory in IE
+ root = form = null;
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function( match, context ) {
+ var results = context.getElementsByTagName( match[1] );
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "<a href='#'></a>";
+
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+
+ Expr.attrHandle.href = function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ };
+ }
+
+ // release memory in IE
+ div = null;
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle,
+ div = document.createElement("div"),
+ id = "__sizzle__";
+
+ div.innerHTML = "<p class='TEST'></p>";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function( query, context, extra, seed ) {
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && !Sizzle.isXML(context) ) {
+ // See if we find a selector to speed up
+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+ // Speed-up: Sizzle("TAG")
+ if ( match[1] ) {
+ return makeArray( context.getElementsByTagName( query ), extra );
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+ return makeArray( context.getElementsByClassName( match[2] ), extra );
+ }
+ }
+
+ if ( context.nodeType === 9 ) {
+ // Speed-up: Sizzle("body")
+ // The body element only exists once, optimize finding it
+ if ( query === "body" && context.body ) {
+ return makeArray( [ context.body ], extra );
+
+ // Speed-up: Sizzle("#ID")
+ } else if ( match && match[3] ) {
+ var elem = context.getElementById( match[3] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id === match[3] ) {
+ return makeArray( [ elem ], extra );
+ }
+
+ } else {
+ return makeArray( [], extra );
+ }
+ }
+
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || id,
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if ( !old ) {
+ context.setAttribute( "id", nid );
+ } else {
+ nid = nid.replace( /'/g, "\\$&" );
+ }
+ if ( relativeHierarchySelector && hasParent ) {
+ context = context.parentNode;
+ }
+
+ try {
+ if ( !relativeHierarchySelector || hasParent ) {
+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+ }
+
+ } catch(pseudoError) {
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ // release memory in IE
+ div = null;
+ })();
+}
+
+(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+ if ( matches ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9 fails this)
+ var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+ pseudoWorks = false;
+
+ try {
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( document.documentElement, "[test!='']:sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ Sizzle.matchesSelector = function( node, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+ if ( !Sizzle.isXML( node ) ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+ var ret = matches.call( node, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || !disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9, so check for that
+ node.document && node.document.nodeType !== 11 ) {
+ return ret;
+ }
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ // Opera can't find a second classname (in 9.6)
+ // Also, make sure that getElementsByClassName actually exists
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function( match, context, isXML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ // release memory in IE
+ div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+if ( document.documentElement.contains ) {
+ Sizzle.contains = function( a, b ) {
+ return a !== b && (a.contains ? a.contains(b) : true);
+ };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+ Sizzle.contains = function( a, b ) {
+ return !!(a.compareDocumentPosition(b) & 16);
+ };
+
+} else {
+ Sizzle.contains = function() {
+ return false;
+ };
+}
+
+Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context ) {
+ var match,
+ tmpSet = [],
+ later = "",
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+ // Note: This RegExp should be improved, or likely pulled from Sizzle
+ rmultiselector = /,/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ slice = Array.prototype.slice,
+ POS = jQuery.expr.match.POS,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var self = this,
+ i, l;
+
+ if ( typeof selector !== "string" ) {
+ return jQuery( selector ).filter(function() {
+ for ( i = 0, l = self.length; i < l; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ });
+ }
+
+ var ret = this.pushStack( "", "find", selector ),
+ length, n, r;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( n = length; n < ret.length; n++ ) {
+ for ( r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var targets = jQuery( target );
+ return this.filter(function() {
+ for ( var i = 0, l = targets.length; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && ( typeof selector === "string" ?
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var ret = [], i, l, cur = this[0];
+
+ // Array
+ if ( jQuery.isArray( selectors ) ) {
+ var match, selector,
+ matches = {},
+ level = 1;
+
+ if ( cur && selectors.length ) {
+ for ( i = 0, l = selectors.length; i < l; i++ ) {
+ selector = selectors[i];
+
+ if ( !matches[ selector ] ) {
+ matches[ selector ] = POS.test( selector ) ?
+ jQuery( selector, context || this.context ) :
+ selector;
+ }
+ }
+
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( selector in matches ) {
+ match = matches[ selector ];
+
+ if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
+ ret.push({ selector: selector, elem: cur, level: level });
+ }
+ }
+
+ cur = cur.parentNode;
+ level++;
+ }
+ }
+
+ return ret;
+ }
+
+ // String
+ var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+
+ } else {
+ cur = cur.parentNode;
+ if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ if ( !elem || typeof elem === "string" ) {
+ return jQuery.inArray( this[0],
+ // If it receives a string, the selector is used
+ // If it receives nothing, the siblings are used
+ elem ? jQuery( elem ) : this.parent().children() );
+ }
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return jQuery.nth( elem, 2, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return jQuery.nth( elem, 2, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( elem.parentNode.firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.makeArray( elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until ),
+ // The variable 'args' was introduced in
+ // https://github.com/jquery/jquery/commit/52a0238
+ // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
+ // http://code.google.com/p/v8/issues/detail?id=1050
+ args = slice.call(arguments);
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, args.join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function( cur, result, dir, elem ) {
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] ) {
+ if ( cur.nodeType === 1 && ++num === result ) {
+ break;
+ }
+ }
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+ // Can't pass null or undefined to indexOf in Firefox 4
+ // Set to 0 to skip string check
+ qualifier = qualifier || 0;
+
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return (elem === qualifier) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+ });
+}
+
+
+
+
+var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnocache = /<(?:script|object|embed|option|style)/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /\/(java|ecma)script/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ area: [ 1, "<map>", "</map>" ],
+ _default: [ 0, "", "" ]
+ };
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+ text: function( text ) {
+ if ( jQuery.isFunction(text) ) {
+ return this.each(function(i) {
+ var self = jQuery( this );
+
+ self.text( text.call(this, i, self.text()) );
+ });
+ }
+
+ if ( typeof text !== "object" && text !== undefined ) {
+ return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+ }
+
+ return jQuery.text( this );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ return this.each(function() {
+ jQuery( this ).wrapAll( html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ } else if ( arguments.length ) {
+ var set = jQuery(arguments[0]);
+ set.push.apply( set, this.toArray() );
+ return this.pushStack( set, "before", arguments );
+ }
+ },
+
+ after: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ } else if ( arguments.length ) {
+ var set = this.pushStack( this, "after", arguments );
+ set.push.apply( set, jQuery(arguments[0]).toArray() );
+ return set;
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ if ( value === undefined ) {
+ return this[0] && this[0].nodeType === 1 ?
+ this[0].innerHTML.replace(rinlinejQuery, "") :
+ null;
+
+ // See if we can take a shortcut and just use innerHTML
+ } else if ( typeof value === "string" && !rnocache.test( value ) &&
+ (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
+ !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
+
+ value = value.replace(rxhtmlTag, "<$1></$2>");
+
+ try {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( this[i].nodeType === 1 ) {
+ jQuery.cleanData( this[i].getElementsByTagName("*") );
+ this[i].innerHTML = value;
+ }
+ }
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {
+ this.empty().append( value );
+ }
+
+ } else if ( jQuery.isFunction( value ) ) {
+ this.each(function(i){
+ var self = jQuery( this );
+
+ self.html( value.call(this, i, self.html()) );
+ });
+
+ } else {
+ this.empty().append( value );
+ }
+
+ return this;
+ },
+
+ replaceWith: function( value ) {
+ if ( this[0] && this[0].parentNode ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery( value ).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ jQuery( this ).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ } else {
+ return this.length ?
+ this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+ this;
+ }
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+ var results, first, fragment, parent,
+ value = args[0],
+ scripts = [];
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback, true );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call(this, i, table ? self.html() : undefined);
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ parent = value && value.parentNode;
+
+ // If we're in a fragment, just use that instead of building a new one
+ if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+ results = { fragment: parent };
+
+ } else {
+ results = jQuery.buildFragment( args, this, scripts );
+ }
+
+ fragment = results.fragment;
+
+ if ( fragment.childNodes.length === 1 ) {
+ first = fragment = fragment.firstChild;
+ } else {
+ first = fragment.firstChild;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+ callback.call(
+ table ?
+ root(this[i], first) :
+ this[i],
+ // Make sure that we do not leak memory by inadvertently discarding
+ // the original fragment (which might have attached data) instead of
+ // using it; in addition, use the original fragment object for the last
+ // item instead of first because it can end up being emptied incorrectly
+ // in certain situations (Bug #8070).
+ // Fragments from the fragment cache must always be cloned and never used
+ // in place.
+ results.cacheable || (l > 1 && i < lastIndex) ?
+ jQuery.clone( fragment, true, true ) :
+ fragment
+ );
+ }
+ }
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, evalScript );
+ }
+ }
+
+ return this;
+ }
+});
+
+function root( elem, cur ) {
+ return jQuery.nodeName(elem, "table") ?
+ (elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+ elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var internalKey = jQuery.expando,
+ oldData = jQuery.data( src ),
+ curData = jQuery.data( dest, oldData );
+
+ // Switch to use the internal data object, if it exists, for the next
+ // stage of data copying
+ if ( (oldData = oldData[ internalKey ]) ) {
+ var events = oldData.events;
+ curData = curData[ internalKey ] = jQuery.extend({}, oldData);
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( var type in events ) {
+ for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
+ }
+ }
+ }
+ }
+}
+
+function cloneFixAttributes( src, dest ) {
+ var nodeName;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // clearAttributes removes the attributes, which we don't want,
+ // but also removes the attachEvent events, which we *do* want
+ if ( dest.clearAttributes ) {
+ dest.clearAttributes();
+ }
+
+ // mergeAttributes, in contrast, only merges back on the
+ // original attributes, not the events
+ if ( dest.mergeAttributes ) {
+ dest.mergeAttributes( src );
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 fail to clone children inside object elements that use
+ // the proprietary classid attribute value (rather than the type
+ // attribute) to identify the type of content to display
+ if ( nodeName === "object" ) {
+ dest.outerHTML = src.outerHTML;
+
+ } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+ if ( src.checked ) {
+ dest.defaultChecked = dest.checked = src.checked;
+ }
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+
+ // Event data gets referenced instead of copied if the expando
+ // gets copied too
+ dest.removeAttribute( jQuery.expando );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+ var fragment, cacheable, cacheresults, doc;
+
+ // nodes may contain either an explicit document object,
+ // a jQuery collection or context object.
+ // If nodes[0] contains a valid object to assign to doc
+ if ( nodes && nodes[0] ) {
+ doc = nodes[0].ownerDocument || nodes[0];
+ }
+
+ // Ensure that an attr object doesn't incorrectly stand in as a document object
+ // Chrome and Firefox seem to allow this to occur and will throw exception
+ // Fixes #8950
+ if ( !doc.createDocumentFragment ) {
+ doc = document;
+ }
+
+ // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
+ args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
+
+ cacheable = true;
+
+ cacheresults = jQuery.fragments[ args[0] ];
+ if ( cacheresults && cacheresults !== 1 ) {
+ fragment = cacheresults;
+ }
+ }
+
+ if ( !fragment ) {
+ fragment = doc.createDocumentFragment();
+ jQuery.clean( args, doc, fragment, scripts );
+ }
+
+ if ( cacheable ) {
+ jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = [],
+ insert = jQuery( selector ),
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+
+ } else {
+ for ( var i = 0, l = insert.length; i < l; i++ ) {
+ var elems = (i > 0 ? this.clone(true) : this).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+function getAll( elem ) {
+ if ( "getElementsByTagName" in elem ) {
+ return elem.getElementsByTagName( "*" );
+
+ } else if ( "querySelectorAll" in elem ) {
+ return elem.querySelectorAll( "*" );
+
+ } else {
+ return [];
+ }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( elem.type === "checkbox" || elem.type === "radio" ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ fixDefaultChecked( elem );
+ } else if ( "getElementsByTagName" in elem ) {
+ jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var clone = elem.cloneNode(true),
+ srcElements,
+ destElements,
+ i;
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+ // IE copies events bound via attachEvent when using cloneNode.
+ // Calling detachEvent on the clone will also remove the events
+ // from the original. In order to get around this, we use some
+ // proprietary methods to clear the events. Thanks to MooTools
+ // guys for this hotness.
+
+ cloneFixAttributes( elem, clone );
+
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName
+ // instead
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ // Weird iteration because IE will replace the length property
+ // with an element if you are cloning the body and one of the
+ // elements on the page has a name or id of "length"
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ cloneCopyEvent( elem, clone );
+
+ if ( deepDataAndEvents ) {
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneCopyEvent( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ srcElements = destElements = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ clean: function( elems, context, fragment, scripts ) {
+ var checkScriptType;
+
+ context = context || document;
+
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if ( typeof context.createElement === "undefined" ) {
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+ }
+
+ var ret = [], j;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" ) {
+ if ( !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+ } else {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
+ wrap = wrapMap[ tag ] || wrapMap._default,
+ depth = wrap[0],
+ div = context.createElement("div");
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var hasBody = rtbody.test(elem),
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+ }
+ }
+
+ // Resets defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ var len;
+ if ( !jQuery.support.appendChecked ) {
+ if ( elem[0] && typeof (len = elem.length) === "number" ) {
+ for ( j = 0; j < len; j++ ) {
+ findInputs( elem[j] );
+ }
+ } else {
+ findInputs( elem );
+ }
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ ret = jQuery.merge( ret, elem );
+ }
+ }
+
+ if ( fragment ) {
+ checkScriptType = function( elem ) {
+ return !elem.type || rscriptType.test( elem.type );
+ };
+ for ( i = 0; ret[i]; i++ ) {
+ if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
+ scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+
+ } else {
+ if ( ret[i].nodeType === 1 ) {
+ var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
+
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ }
+ fragment.appendChild( ret[i] );
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems ) {
+ var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
+ deleteExpando = jQuery.support.deleteExpando;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ continue;
+ }
+
+ id = elem[ jQuery.expando ];
+
+ if ( id ) {
+ data = cache[ id ] && cache[ id ][ internalKey ];
+
+ if ( data && data.events ) {
+ for ( var type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+
+ // Null the DOM reference to avoid IE6/7/8 leak (#7054)
+ if ( data.handle ) {
+ data.handle.elem = null;
+ }
+ }
+
+ if ( deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ delete cache[ id ];
+ }
+ }
+ }
+});
+
+function evalScript( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+}
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity=([^)]*)/,
+ // fixed for IE9, see #8346
+ rupper = /([A-Z]|^ms)/g,
+ rnumpx = /^-?\d+(?:px)?$/i,
+ rnum = /^-?\d/,
+ rrelNum = /^[+\-]=/,
+ rrelNumFilter = /[^+\-\.\de]+/g,
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssWidth = [ "Left", "Right" ],
+ cssHeight = [ "Top", "Bottom" ],
+ curCSS,
+
+ getComputedStyle,
+ currentStyle;
+
+jQuery.fn.css = function( name, value ) {
+ // Setting 'undefined' is a no-op
+ if ( arguments.length === 2 && value === undefined ) {
+ return this;
+ }
+
+ return jQuery.access( this, name, value, true, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ });
+};
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity", "opacity" );
+ return ret === "" ? "1" : ret;
+
+ } else {
+ return elem.style.opacity;
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, origName = jQuery.camelCase( name ),
+ style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+ name = jQuery.cssProps[ origName ] || origName;
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( type === "number" && isNaN( value ) || value == null ) {
+ return;
+ }
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && rrelNum.test( value ) ) {
+ value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra ) {
+ var ret, hooks;
+
+ // Make sure that we're working with the right name
+ name = jQuery.camelCase( name );
+ hooks = jQuery.cssHooks[ name ];
+ name = jQuery.cssProps[ name ] || name;
+
+ // cssFloat needs a special treatment
+ if ( name === "cssFloat" ) {
+ name = "float";
+ }
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+ return ret;
+
+ // Otherwise, if a way to get the computed value exists, use that
+ } else if ( curCSS ) {
+ return curCSS( elem, name );
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+ }
+});
+
+// DEPRECATED, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+jQuery.each(["height", "width"], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ var val;
+
+ if ( computed ) {
+ if ( elem.offsetWidth !== 0 ) {
+ return getWH( elem, name, extra );
+ } else {
+ jQuery.swap( elem, cssShow, function() {
+ val = getWH( elem, name, extra );
+ });
+ }
+
+ return val;
+ }
+ },
+
+ set: function( elem, value ) {
+ if ( rnumpx.test( value ) ) {
+ // ignore negative width and height values #1599
+ value = parseFloat( value );
+
+ if ( value >= 0 ) {
+ return value + "px";
+ }
+
+ } else {
+ return value;
+ }
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle;
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // Set the alpha filter to set the opacity
+ var opacity = jQuery.isNaN( value ) ?
+ "" :
+ "alpha(opacity=" + value * 100 + ")",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery(function() {
+ // This hook cannot be added until DOM ready because the support test
+ // for it is not run until after DOM ready
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ var ret;
+ jQuery.swap( elem, { "display": "inline-block" }, function() {
+ if ( computed ) {
+ ret = curCSS( elem, "margin-right", "marginRight" );
+ } else {
+ ret = elem.style.marginRight;
+ }
+ });
+ return ret;
+ }
+ };
+ }
+});
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ getComputedStyle = function( elem, name ) {
+ var ret, defaultView, computedStyle;
+
+ name = name.replace( rupper, "-$1" ).toLowerCase();
+
+ if ( !(defaultView = elem.ownerDocument.defaultView) ) {
+ return undefined;
+ }
+
+ if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+ ret = computedStyle.getPropertyValue( name );
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+ }
+
+ return ret;
+ };
+}
+
+if ( document.documentElement.currentStyle ) {
+ currentStyle = function( elem, name ) {
+ var left,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
+ style = elem.style;
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+ // Remember the original values
+ left = style.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : (ret || 0);
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWH( elem, name, extra ) {
+
+ // Start with offset property
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ which = name === "width" ? cssWidth : cssHeight;
+
+ if ( val > 0 ) {
+ if ( extra !== "border" ) {
+ jQuery.each( which, function() {
+ if ( !extra ) {
+ val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
+ } else {
+ val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
+ }
+ });
+ }
+
+ return val + "px";
+ }
+
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ] || 0;
+ }
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+
+ // Add padding, border, margin
+ if ( extra ) {
+ jQuery.each( which, function() {
+ val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
+ if ( extra !== "padding" ) {
+ val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
+ }
+ });
+ }
+
+ return val + "px";
+}
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ var width = elem.offsetWidth,
+ height = elem.offsetHeight;
+
+ return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rhash = /#.*$/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rquery = /\?/,
+ rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ rselectTextarea = /^(?:select|textarea)/i,
+ rspacesAjax = /\s+/,
+ rts = /([?&])_=[^&]*/,
+ rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Document location
+ ajaxLocation,
+
+ // Document location segments
+ ajaxLocParts;
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ if ( jQuery.isFunction( func ) ) {
+ var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+ i = 0,
+ length = dataTypes.length,
+ dataType,
+ list,
+ placeBefore;
+
+ // For each dataType in the dataTypeExpression
+ for(; i < length; i++ ) {
+ dataType = dataTypes[ i ];
+ // We control if we're asked to add before
+ // any existing element
+ placeBefore = /^\+/.test( dataType );
+ if ( placeBefore ) {
+ dataType = dataType.substr( 1 ) || "*";
+ }
+ list = structure[ dataType ] = structure[ dataType ] || [];
+ // then we add to the structure accordingly
+ list[ placeBefore ? "unshift" : "push" ]( func );
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+ dataType /* internal */, inspected /* internal */ ) {
+
+ dataType = dataType || options.dataTypes[ 0 ];
+ inspected = inspected || {};
+
+ inspected[ dataType ] = true;
+
+ var list = structure[ dataType ],
+ i = 0,
+ length = list ? list.length : 0,
+ executeOnly = ( structure === prefilters ),
+ selection;
+
+ for(; i < length && ( executeOnly || !selection ); i++ ) {
+ selection = list[ i ]( options, originalOptions, jqXHR );
+ // If we got redirected to another dataType
+ // we try there if executing only and not done already
+ if ( typeof selection === "string" ) {
+ if ( !executeOnly || inspected[ selection ] ) {
+ selection = undefined;
+ } else {
+ options.dataTypes.unshift( selection );
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, selection, inspected );
+ }
+ }
+ }
+ // If we're only executing or nothing was selected
+ // we try the catchall dataType if not done already
+ if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, "*", inspected );
+ }
+ // unnecessary when only executing (prefilters)
+ // but it'll be ignored by the caller in that case
+ return selection;
+}
+
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+
+ // Don't do a request if no elements are being requested
+ } else if ( !this.length ) {
+ return this;
+ }
+
+ var off = url.indexOf( " " );
+ if ( off >= 0 ) {
+ var selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params ) {
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( typeof params === "object" ) {
+ params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+ type = "POST";
+ }
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ // Complete callback (responseText is used internally)
+ complete: function( jqXHR, status, responseText ) {
+ // Store the response as specified by the jqXHR object
+ responseText = jqXHR.responseText;
+ // If successful, inject the HTML into all the matched elements
+ if ( jqXHR.isResolved() ) {
+ // #4825: Get the actual response in case
+ // a dataFilter is present in ajaxSettings
+ jqXHR.done(function( r ) {
+ responseText = r;
+ });
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(responseText.replace(rscript, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ responseText );
+ }
+
+ if ( callback ) {
+ self.each( callback, [ responseText, status, jqXHR ] );
+ }
+ }
+ });
+
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+
+ serializeArray: function() {
+ return this.map(function(){
+ return this.elements ? jQuery.makeArray( this.elements ) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
+ rinput.test( this.type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val, i ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+ jQuery.fn[ o ] = function( f ){
+ return this.bind( o, f );
+ };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ type: method,
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ };
+});
+
+jQuery.extend({
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function ( target, settings ) {
+ if ( !settings ) {
+ // Only one parameter, we extend ajaxSettings
+ settings = target;
+ target = jQuery.extend( true, jQuery.ajaxSettings, settings );
+ } else {
+ // target was provided, we extend into it
+ jQuery.extend( true, target, jQuery.ajaxSettings, settings );
+ }
+ // Flatten fields we don't want deep extended
+ for( var field in { context: 1, url: 1 } ) {
+ if ( field in settings ) {
+ target[ field ] = settings[ field ];
+ } else if( field in jQuery.ajaxSettings ) {
+ target[ field ] = jQuery.ajaxSettings[ field ];
+ }
+ }
+ return target;
+ },
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ type: "GET",
+ contentType: "application/x-www-form-urlencoded",
+ processData: true,
+ async: true,
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ text: "text/plain",
+ json: "application/json, text/javascript",
+ "*": "*/*"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText"
+ },
+
+ // List of data converters
+ // 1) key format is "source_type destination_type" (a single space in-between)
+ // 2) the catchall symbol "*" can be used for source_type
+ converters: {
+
+ // Convert anything to text
+ "* text": window.String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ }
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events
+ // It's the callbackContext if one was provided in the options
+ // and if it's a DOM node or a jQuery collection
+ globalEventContext = callbackContext !== s &&
+ ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+ jQuery( callbackContext ) : jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery._Deferred(),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // ifModified key
+ ifModifiedKey,
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // transport
+ transport,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // The jqXHR state
+ state = 0,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Fake xhr
+ jqXHR = {
+
+ readyState: 0,
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( !state ) {
+ var lname = name.toLowerCase();
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match === undefined ? null : match;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ statusText = statusText || "abort";
+ if ( transport ) {
+ transport.abort( statusText );
+ }
+ done( 0, statusText );
+ return this;
+ }
+ };
+
+ // Callback for when everything is done
+ // It is defined here because jslint complains if it is declared
+ // at the end of the function (which would be more logical and readable)
+ function done( status, statusText, responses, headers ) {
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status ? 4 : 0;
+
+ var isSuccess,
+ success,
+ error,
+ response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+ lastModified,
+ etag;
+
+ // If successful, handle type chaining
+ if ( status >= 200 && status < 300 || status === 304 ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+
+ if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+ jQuery.lastModified[ ifModifiedKey ] = lastModified;
+ }
+ if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+ jQuery.etag[ ifModifiedKey ] = etag;
+ }
+ }
+
+ // If not modified
+ if ( status === 304 ) {
+
+ statusText = "notmodified";
+ isSuccess = true;
+
+ // If we have data
+ } else {
+
+ try {
+ success = ajaxConvert( s, response );
+ statusText = "success";
+ isSuccess = true;
+ } catch(e) {
+ // We have a parsererror
+ statusText = "parsererror";
+ error = e;
+ }
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if( !statusText || status ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = statusText;
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+ jqXHR.complete = completeDeferred.done;
+
+ // Status-dependent callbacks
+ jqXHR.statusCode = function( map ) {
+ if ( map ) {
+ var tmp;
+ if ( state < 2 ) {
+ for( tmp in map ) {
+ statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+ }
+ } else {
+ tmp = map[ jqXHR.status ];
+ jqXHR.then( tmp, tmp );
+ }
+ }
+ return this;
+ };
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+ // Determine if a cross-domain request is in order
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefiler, stop there
+ if ( state === 2 ) {
+ return false;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+ }
+
+ // Get ifModifiedKey before adding the anti-cache parameter
+ ifModifiedKey = s.url;
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+
+ var ts = jQuery.now(),
+ // try replacing _= if it is there
+ ret = s.url.replace( rts, "$1_=" + ts );
+
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ ifModifiedKey = ifModifiedKey || s.url;
+ if ( jQuery.lastModified[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+ }
+ if ( jQuery.etag[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+ }
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already
+ jqXHR.abort();
+ return false;
+
+ }
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout( function(){
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch (e) {
+ // Propagate exception as error if not done
+ if ( status < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ jQuery.error( e );
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a, traditional ) {
+ var s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : value;
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( var prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+ }
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && obj != null && typeof obj === "object" ) {
+ // Serialize object item.
+ for ( var name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var contents = s.contents,
+ dataTypes = s.dataTypes,
+ responseFields = s.responseFields,
+ ct,
+ type,
+ finalDataType,
+ firstDataType;
+
+ // Fill responseXXX fields
+ for( type in responseFields ) {
+ if ( type in responses ) {
+ jqXHR[ responseFields[type] ] = responses[ type ];
+ }
+ }
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+ // Apply the dataFilter if provided
+ if ( s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ var dataTypes = s.dataTypes,
+ converters = {},
+ i,
+ key,
+ length = dataTypes.length,
+ tmp,
+ // Current and previous dataTypes
+ current = dataTypes[ 0 ],
+ prev,
+ // Conversion expression
+ conversion,
+ // Conversion function
+ conv,
+ // Conversion functions (transitive conversion)
+ conv1,
+ conv2;
+
+ // For each dataType in the chain
+ for( i = 1; i < length; i++ ) {
+
+ // Create converters map
+ // with lowercased keys
+ if ( i === 1 ) {
+ for( key in s.converters ) {
+ if( typeof key === "string" ) {
+ converters[ key.toLowerCase() ] = s.converters[ key ];
+ }
+ }
+ }
+
+ // Get the dataTypes
+ prev = current;
+ current = dataTypes[ i ];
+
+ // If current is auto dataType, update it to prev
+ if( current === "*" ) {
+ current = prev;
+ // If no auto and dataTypes are actually different
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Get the converter
+ conversion = prev + " " + current;
+ conv = converters[ conversion ] || converters[ "* " + current ];
+
+ // If there is no direct converter, search transitively
+ if ( !conv ) {
+ conv2 = undefined;
+ for( conv1 in converters ) {
+ tmp = conv1.split( " " );
+ if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+ conv2 = converters[ tmp[1] + " " + current ];
+ if ( conv2 ) {
+ conv1 = converters[ conv1 ];
+ if ( conv1 === true ) {
+ conv = conv2;
+ } else if ( conv2 === true ) {
+ conv = conv1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ // If we found no converter, dispatch an error
+ if ( !( conv || conv2 ) ) {
+ jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+ }
+ // If found converter is not an equivalence
+ if ( conv !== true ) {
+ // Convert with 1 or 2 converters accordingly
+ response = conv ? conv( response ) : conv2( conv1(response) );
+ }
+ }
+ }
+ return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+ jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ return jQuery.expando + "_" + ( jsc++ );
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
+ ( typeof s.data === "string" );
+
+ if ( s.dataTypes[ 0 ] === "jsonp" ||
+ s.jsonp !== false && ( jsre.test( s.url ) ||
+ inspectData && jsre.test( s.data ) ) ) {
+
+ var responseContainer,
+ jsonpCallback = s.jsonpCallback =
+ jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+ previous = window[ jsonpCallback ],
+ url = s.url,
+ data = s.data,
+ replace = "$1" + jsonpCallback + "$2";
+
+ if ( s.jsonp !== false ) {
+ url = url.replace( jsre, replace );
+ if ( s.url === url ) {
+ if ( inspectData ) {
+ data = data.replace( jsre, replace );
+ }
+ if ( s.data === data ) {
+ // Add callback manually
+ url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+ }
+ }
+ }
+
+ s.url = url;
+ s.data = data;
+
+ // Install callback
+ window[ jsonpCallback ] = function( response ) {
+ responseContainer = [ response ];
+ };
+
+ // Clean-up function
+ jqXHR.always(function() {
+ // Set callback back to previous value
+ window[ jsonpCallback ] = previous;
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( previous ) ) {
+ window[ jsonpCallback ]( responseContainer[ 0 ] );
+ }
+ });
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( jsonpCallback + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /javascript|ecmascript/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement( "script" );
+
+ script.async = "async";
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( head && script.parentNode ) {
+ head.removeChild( script );
+ }
+
+ // Dereference the script
+ script = undefined;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709 and #4378).
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( 0, 1 );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject ? function() {
+ // Abort all pending requests
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( 0, 1 );
+ }
+ } : false,
+ xhrId = 0,
+ xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+ jQuery.extend( jQuery.support, {
+ ajax: !!xhr,
+ cors: !!xhr && ( "withCredentials" in xhr )
+ });
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var xhr = s.xhr(),
+ handle,
+ i;
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( _ ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+
+ var status,
+ statusText,
+ responseHeaders,
+ responses,
+ xml;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occured
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ status = xhr.status;
+ responseHeaders = xhr.getAllResponseHeaders();
+ responses = {};
+ xml = xhr.responseXML;
+
+ // Construct response list
+ if ( xml && xml.documentElement /* #4958 */ ) {
+ responses.xml = xml;
+ }
+ responses.text = xhr.responseText;
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ // if we're in sync mode or it's in cache
+ // and has been retrieved directly (IE6 & IE7)
+ // we need to manually fire the callback
+ if ( !s.async || xhr.readyState === 4 ) {
+ callback();
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback(0,1);
+ }
+ }
+ };
+ }
+ });
+}
+
+
+
+
+var elemdisplay = {},
+ iframe, iframeDoc,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+ timerId,
+ fxAttrs = [
+ // height animations
+ [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+ // width animations
+ [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+ // opacity animations
+ [ "opacity" ]
+ ],
+ fxNow,
+ requestAnimationFrame = window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame;
+
+jQuery.fn.extend({
+ show: function( speed, easing, callback ) {
+ var elem, display;
+
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("show", 3), speed, easing, callback);
+
+ } else {
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ elem = this[i];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+ display = elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
+ jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ elem = this[i];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ if ( display === "" || display === "none" ) {
+ elem.style.display = jQuery._data(elem, "olddisplay") || "";
+ }
+ }
+ }
+
+ return this;
+ }
+ },
+
+ hide: function( speed, easing, callback ) {
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("hide", 3), speed, easing, callback);
+
+ } else {
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ if ( this[i].style ) {
+ var display = jQuery.css( this[i], "display" );
+
+ if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
+ jQuery._data( this[i], "olddisplay", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ if ( this[i].style ) {
+ this[i].style.display = "none";
+ }
+ }
+
+ return this;
+ }
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2, callback ) {
+ var bool = typeof fn === "boolean";
+
+ if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+ this._toggle.apply( this, arguments );
+
+ } else if ( fn == null || bool ) {
+ this.each(function() {
+ var state = bool ? fn : jQuery(this).is(":hidden");
+ jQuery(this)[ state ? "show" : "hide" ]();
+ });
+
+ } else {
+ this.animate(genFx("toggle", 3), fn, fn2, callback);
+ }
+
+ return this;
+ },
+
+ fadeTo: function( speed, to, easing, callback ) {
+ return this.filter(":hidden").css("opacity", 0).show().end()
+ .animate({opacity: to}, speed, easing, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed(speed, easing, callback);
+
+ if ( jQuery.isEmptyObject( prop ) ) {
+ return this.each( optall.complete, [ false ] );
+ }
+
+ // Do not change referenced properties as per-property easing will be lost
+ prop = jQuery.extend( {}, prop );
+
+ return this[ optall.queue === false ? "each" : "queue" ](function() {
+ // XXX 'this' does not always have a nodeName when running the
+ // test suite
+
+ if ( optall.queue === false ) {
+ jQuery._mark( this );
+ }
+
+ var opt = jQuery.extend( {}, optall ),
+ isElement = this.nodeType === 1,
+ hidden = isElement && jQuery(this).is(":hidden"),
+ name, val, p,
+ display, e,
+ parts, start, end, unit;
+
+ // will store per property easing and be used to determine when an animation is complete
+ opt.animatedProperties = {};
+
+ for ( p in prop ) {
+
+ // property name normalization
+ name = jQuery.camelCase( p );
+ if ( p !== name ) {
+ prop[ name ] = prop[ p ];
+ delete prop[ p ];
+ }
+
+ val = prop[ name ];
+
+ // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+ if ( jQuery.isArray( val ) ) {
+ opt.animatedProperties[ name ] = val[ 1 ];
+ val = prop[ name ] = val[ 0 ];
+ } else {
+ opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+ }
+
+ if ( val === "hide" && hidden || val === "show" && !hidden ) {
+ return opt.complete.call( this );
+ }
+
+ if ( isElement && ( name === "height" || name === "width" ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height
+ // animated
+ if ( jQuery.css( this, "display" ) === "inline" &&
+ jQuery.css( this, "float" ) === "none" ) {
+ if ( !jQuery.support.inlineBlockNeedsLayout ) {
+ this.style.display = "inline-block";
+
+ } else {
+ display = defaultDisplay( this.nodeName );
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( display === "inline" ) {
+ this.style.display = "inline-block";
+
+ } else {
+ this.style.display = "inline";
+ this.style.zoom = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if ( opt.overflow != null ) {
+ this.style.overflow = "hidden";
+ }
+
+ for ( p in prop ) {
+ e = new jQuery.fx( this, opt, p );
+ val = prop[ p ];
+
+ if ( rfxtypes.test(val) ) {
+ e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
+
+ } else {
+ parts = rfxnum.exec( val );
+ start = e.cur();
+
+ if ( parts ) {
+ end = parseFloat( parts[2] );
+ unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+ // We need to compute starting value
+ if ( unit !== "px" ) {
+ jQuery.style( this, p, (end || 1) + unit);
+ start = ((end || 1) / e.cur()) * start;
+ jQuery.style( this, p, start + unit);
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] ) {
+ end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+ }
+
+ e.custom( start, end, unit );
+
+ } else {
+ e.custom( start, val, "" );
+ }
+ }
+ }
+
+ // For JS strict compliance
+ return true;
+ });
+ },
+
+ stop: function( clearQueue, gotoEnd ) {
+ if ( clearQueue ) {
+ this.queue([]);
+ }
+
+ this.each(function() {
+ var timers = jQuery.timers,
+ i = timers.length;
+ // clear marker counters if we know they won't be
+ if ( !gotoEnd ) {
+ jQuery._unmark( true, this );
+ }
+ while ( i-- ) {
+ if ( timers[i].elem === this ) {
+ if (gotoEnd) {
+ // force the next step to be the last
+ timers[i](true);
+ }
+
+ timers.splice(i, 1);
+ }
+ }
+ });
+
+ // start the next in the queue if the last step wasn't forced
+ if ( !gotoEnd ) {
+ this.dequeue();
+ }
+
+ return this;
+ }
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout( clearFxNow, 0 );
+ return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+ fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+ var obj = {};
+
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+ obj[ this ] = type;
+ });
+
+ return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show", 1),
+ slideUp: genFx("hide", 1),
+ slideToggle: genFx("toggle", 1),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.extend({
+ speed: function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
+
+ // Queueing
+ opt.old = opt.complete;
+ opt.complete = function( noUnmark ) {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue !== false ) {
+ jQuery.dequeue( this );
+ } else if ( noUnmark !== false ) {
+ jQuery._unmark( this );
+ }
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p, n, firstNum, diff ) {
+ return firstNum + diff * p;
+ },
+ swing: function( p, n, firstNum, diff ) {
+ return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ }
+ },
+
+ timers: [],
+
+ fx: function( elem, options, prop ) {
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ options.orig = options.orig || {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+ // Simple function for setting a style value
+ update: function() {
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+ },
+
+ // Get the current size
+ cur: function() {
+ if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+ return this.elem[ this.prop ];
+ }
+
+ var parsed,
+ r = jQuery.css( this.elem, this.prop );
+ // Empty strings, null, undefined and "auto" are converted to 0,
+ // complex values such as "rotate(1rad)" are returned as is,
+ // simple values such as "10px" are parsed to Float.
+ return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+ },
+
+ // Start an animation from one number to another
+ custom: function( from, to, unit ) {
+ var self = this,
+ fx = jQuery.fx,
+ raf;
+
+ this.startTime = fxNow || createFxNow();
+ this.start = from;
+ this.end = to;
+ this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+ this.now = this.start;
+ this.pos = this.state = 0;
+
+ function t( gotoEnd ) {
+ return self.step(gotoEnd);
+ }
+
+ t.elem = this.elem;
+
+ if ( t() && jQuery.timers.push(t) && !timerId ) {
+ // Use requestAnimationFrame instead of setInterval if available
+ if ( requestAnimationFrame ) {
+ timerId = true;
+ raf = function() {
+ // When timerId gets set to null at any point, this stops
+ if ( timerId ) {
+ requestAnimationFrame( raf );
+ fx.tick();
+ }
+ };
+ requestAnimationFrame( raf );
+ } else {
+ timerId = setInterval( fx.tick, fx.interval );
+ }
+ }
+ },
+
+ // Simple 'show' function
+ show: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ // Make sure that we start at a small width/height to avoid any
+ // flash of content
+ this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+
+ // Start by showing the element
+ jQuery( this.elem ).show();
+ },
+
+ // Simple 'hide' function
+ hide: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom(this.cur(), 0);
+ },
+
+ // Each step of an animation
+ step: function( gotoEnd ) {
+ var t = fxNow || createFxNow(),
+ done = true,
+ elem = this.elem,
+ options = this.options,
+ i, n;
+
+ if ( gotoEnd || t >= options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ options.animatedProperties[ this.prop ] = true;
+
+ for ( i in options.animatedProperties ) {
+ if ( options.animatedProperties[i] !== true ) {
+ done = false;
+ }
+ }
+
+ if ( done ) {
+ // Reset the overflow
+ if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+ jQuery.each( [ "", "X", "Y" ], function (index, value) {
+ elem.style[ "overflow" + value ] = options.overflow[index];
+ });
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( options.hide ) {
+ jQuery(elem).hide();
+ }
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( options.hide || options.show ) {
+ for ( var p in options.animatedProperties ) {
+ jQuery.style( elem, p, options.orig[p] );
+ }
+ }
+
+ // Execute the complete function
+ options.complete.call( elem );
+ }
+
+ return false;
+
+ } else {
+ // classical easing cannot be used with an Infinity duration
+ if ( options.duration == Infinity ) {
+ this.now = t;
+ } else {
+ n = t - this.startTime;
+ this.state = n / options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );
+ this.now = this.start + ((this.end - this.start) * this.pos);
+ }
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+};
+
+jQuery.extend( jQuery.fx, {
+ tick: function() {
+ for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
+ if ( !timers[i]() ) {
+ timers.splice(i--, 1);
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ },
+
+ interval: 13,
+
+ stop: function() {
+ clearInterval( timerId );
+ timerId = null;
+ },
+
+ speeds: {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+ },
+
+ step: {
+ opacity: function( fx ) {
+ jQuery.style( fx.elem, "opacity", fx.now );
+ },
+
+ _default: function( fx ) {
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+ fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+ } else {
+ fx.elem[ fx.prop ] = fx.now;
+ }
+ }
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+ if ( !elemdisplay[ nodeName ] ) {
+
+ var body = document.body,
+ elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+ display = elem.css( "display" );
+
+ elem.remove();
+
+ // If the simple way fails,
+ // get element's real default display by attaching it to a temp iframe
+ if ( display === "none" || display === "" ) {
+ // No iframe to use yet, so create it
+ if ( !iframe ) {
+ iframe = document.createElement( "iframe" );
+ iframe.frameBorder = iframe.width = iframe.height = 0;
+ }
+
+ body.appendChild( iframe );
+
+ // Create a cacheable copy of the iframe document on first call.
+ // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+ // document to it; WebKit & Firefox won't allow reusing the iframe document.
+ if ( !iframeDoc || !iframe.createElement ) {
+ iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+ iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
+ iframeDoc.close();
+ }
+
+ elem = iframeDoc.createElement( nodeName );
+
+ iframeDoc.body.appendChild( elem );
+
+ display = jQuery.css( elem, "display" );
+
+ body.removeChild( iframe );
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return elemdisplay[ nodeName ];
+}
+
+
+
+
+var rtable = /^t(?:able|d|h)$/i,
+ rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+ jQuery.fn.offset = function( options ) {
+ var elem = this[0], box;
+
+ if ( options ) {
+ return this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ if ( !elem || !elem.ownerDocument ) {
+ return null;
+ }
+
+ if ( elem === elem.ownerDocument.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ try {
+ box = elem.getBoundingClientRect();
+ } catch(e) {}
+
+ var doc = elem.ownerDocument,
+ docElem = doc.documentElement;
+
+ // Make sure we're not dealing with a disconnected DOM node
+ if ( !box || !jQuery.contains( docElem, elem ) ) {
+ return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+ }
+
+ var body = doc.body,
+ win = getWindow(doc),
+ clientTop = docElem.clientTop || body.clientTop || 0,
+ clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
+ scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+ top = box.top + scrollTop - clientTop,
+ left = box.left + scrollLeft - clientLeft;
+
+ return { top: top, left: left };
+ };
+
+} else {
+ jQuery.fn.offset = function( options ) {
+ var elem = this[0];
+
+ if ( options ) {
+ return this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ if ( !elem || !elem.ownerDocument ) {
+ return null;
+ }
+
+ if ( elem === elem.ownerDocument.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ jQuery.offset.initialize();
+
+ var computedStyle,
+ offsetParent = elem.offsetParent,
+ prevOffsetParent = elem,
+ doc = elem.ownerDocument,
+ docElem = doc.documentElement,
+ body = doc.body,
+ defaultView = doc.defaultView,
+ prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+ top = elem.offsetTop,
+ left = elem.offsetLeft;
+
+ while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+ if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+ break;
+ }
+
+ computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+ top -= elem.scrollTop;
+ left -= elem.scrollLeft;
+
+ if ( elem === offsetParent ) {
+ top += elem.offsetTop;
+ left += elem.offsetLeft;
+
+ if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevOffsetParent = offsetParent;
+ offsetParent = elem.offsetParent;
+ }
+
+ if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevComputedStyle = computedStyle;
+ }
+
+ if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+ top += body.offsetTop;
+ left += body.offsetLeft;
+ }
+
+ if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+ top += Math.max( docElem.scrollTop, body.scrollTop );
+ left += Math.max( docElem.scrollLeft, body.scrollLeft );
+ }
+
+ return { top: top, left: left };
+ };
+}
+
+jQuery.offset = {
+ initialize: function() {
+ var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
+ html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+
+ jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
+
+ container.innerHTML = html;
+ body.insertBefore( container, body.firstChild );
+ innerDiv = container.firstChild;
+ checkDiv = innerDiv.firstChild;
+ td = innerDiv.nextSibling.firstChild.firstChild;
+
+ this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
+ this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
+
+ checkDiv.style.position = "fixed";
+ checkDiv.style.top = "20px";
+
+ // safari subtracts parent border width here which is 5px
+ this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
+ checkDiv.style.position = checkDiv.style.top = "";
+
+ innerDiv.style.overflow = "hidden";
+ innerDiv.style.position = "relative";
+
+ this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+
+ this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+
+ body.removeChild( container );
+ jQuery.offset.initialize = jQuery.noop;
+ },
+
+ bodyOffset: function( body ) {
+ var top = body.offsetTop,
+ left = body.offsetLeft;
+
+ jQuery.offset.initialize();
+
+ if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
+ top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+ left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+ }
+
+ return { top: top, left: left };
+ },
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if (options.top != null) {
+ props.top = (options.top - curOffset.top) + curTop;
+ }
+ if (options.left != null) {
+ props.left = (options.left - curOffset.left) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+ position: function() {
+ if ( !this[0] ) {
+ return null;
+ }
+
+ var elem = this[0],
+
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+ offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+ // Add offsetParent borders
+ parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+ parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+ // Subtract the two offsets
+ return {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.body;
+ while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ["Left", "Top"], function( i, name ) {
+ var method = "scroll" + name;
+
+ jQuery.fn[ method ] = function( val ) {
+ var elem, win;
+
+ if ( val === undefined ) {
+ elem = this[ 0 ];
+
+ if ( !elem ) {
+ return null;
+ }
+
+ win = getWindow( elem );
+
+ // Return the scroll offset
+ return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
+ jQuery.support.boxModel && win.document.documentElement[ method ] ||
+ win.document.body[ method ] :
+ elem[ method ];
+ }
+
+ // Set the scroll offset
+ return this.each(function() {
+ win = getWindow( this );
+
+ if ( win ) {
+ win.scrollTo(
+ !i ? val : jQuery( win ).scrollLeft(),
+ i ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ this[ method ] = val;
+ }
+ });
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+
+
+
+// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function( i, name ) {
+
+ var type = name.toLowerCase();
+
+ // innerHeight and innerWidth
+ jQuery.fn[ "inner" + name ] = function() {
+ var elem = this[0];
+ return elem && elem.style ?
+ parseFloat( jQuery.css( elem, type, "padding" ) ) :
+ null;
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn[ "outer" + name ] = function( margin ) {
+ var elem = this[0];
+ return elem && elem.style ?
+ parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+ null;
+ };
+
+ jQuery.fn[ type ] = function( size ) {
+ // Get window width or height
+ var elem = this[0];
+ if ( !elem ) {
+ return size == null ? null : this;
+ }
+
+ if ( jQuery.isFunction( size ) ) {
+ return this.each(function( i ) {
+ var self = jQuery( this );
+ self[ type ]( size.call( this, i, self[ type ]() ) );
+ });
+ }
+
+ if ( jQuery.isWindow( elem ) ) {
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+ var docElemProp = elem.document.documentElement[ "client" + name ];
+ return elem.document.compatMode === "CSS1Compat" && docElemProp ||
+ elem.document.body[ "client" + name ] || docElemProp;
+
+ // Get document width or height
+ } else if ( elem.nodeType === 9 ) {
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ return Math.max(
+ elem.documentElement["client" + name],
+ elem.body["scroll" + name], elem.documentElement["scroll" + name],
+ elem.body["offset" + name], elem.documentElement["offset" + name]
+ );
+
+ // Get or set width or height on the element
+ } else if ( size === undefined ) {
+ var orig = jQuery.css( elem, type ),
+ ret = parseFloat( orig );
+
+ return jQuery.isNaN( ret ) ? orig : ret;
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ } else {
+ return this.css( type, typeof size === "string" ? size : size + "px" );
+ }
+ };
+
+});
+
+
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+})(window);
diff --git a/addons/web/static/lib/json/json2.js b/addons/web/static/lib/json/json2.js
new file mode 100755
index 00000000000..b4c02d3f08b
--- /dev/null
+++ b/addons/web/static/lib/json/json2.js
@@ -0,0 +1,480 @@
+/*
+ http://www.JSON.org/json2.js
+ 2011-02-23
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+*/
+
+/*jslint evil: true, strict: false, regexp: false */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+var JSON;
+if (!JSON) {
+ JSON = {};
+}
+
+(function () {
+ "use strict";
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf()) ?
+ this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z' : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' : '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' : gap ?
+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ if (typeof rep[i] === 'string') {
+ k = rep[i];
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' : gap ?
+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
+ '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
diff --git a/addons/web/static/lib/labjs/LAB.src.js b/addons/web/static/lib/labjs/LAB.src.js
new file mode 100644
index 00000000000..99807cd222e
--- /dev/null
+++ b/addons/web/static/lib/labjs/LAB.src.js
@@ -0,0 +1,514 @@
+/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
+ v2.0.3 (c) Kyle Simpson
+ MIT License
+*/
+
+(function(global){
+ var _$LAB = global.$LAB,
+
+ // constants for the valid keys of the options object
+ _UseLocalXHR = "UseLocalXHR",
+ _AlwaysPreserveOrder = "AlwaysPreserveOrder",
+ _AllowDuplicates = "AllowDuplicates",
+ _CacheBust = "CacheBust",
+ /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
+ _BasePath = "BasePath",
+
+ // stateless variables used across all $LAB instances
+ root_page = /^[^?#]*\//.exec(location.href)[0],
+ root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
+ append_to = document.head || document.getElementsByTagName("head"),
+
+ // inferences... ick, but still necessary
+ opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
+
+/*!START_DEBUG*/
+ // console.log() and console.error() wrappers
+ log_msg = function(){},
+ log_error = log_msg,
+/*!END_DEBUG*/
+
+ // feature sniffs (yay!)
+ test_script_elem = document.createElement("script"),
+ explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
+ real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
+ script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+
+ // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
+ xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
+ ;
+
+/*!START_DEBUG*/
+ // define console wrapper functions if applicable
+ if (global.console && global.console.log) {
+ if (!global.console.error) global.console.error = global.console.log;
+ log_msg = function(msg) { global.console.log(msg); };
+ log_error = function(msg,err) { global.console.error(msg,err); };
+ }
+/*!END_DEBUG*/
+
+ // test for function
+ function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
+
+ // test for array
+ function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
+
+ // make script URL absolute/canonical
+ function canonical_uri(src,base_path) {
+ var absolute_regex = /^\w+\:\/\//;
+
+ // is `src` is protocol-relative (begins with // or ///), prepend protocol
+ if (/^\/\/\/?/.test(src)) {
+ src = location.protocol + src;
+ }
+ // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
+ else if (!absolute_regex.test(src) && src.charAt(0) != "/") {
+ // prepend `base_path`, if any
+ src = (base_path || "") + src;
+ }
+ // make sure to return `src` as absolute
+ return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src);
+ }
+
+ // merge `source` into `target`
+ function merge_objs(source,target) {
+ for (var k in source) { if (source.hasOwnProperty(k)) {
+ target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
+ }}
+ return target;
+ }
+
+ // does the chain group have any ready-to-execute scripts?
+ function check_chain_group_scripts_ready(chain_group) {
+ var any_scripts_ready = false;
+ for (var i=0; i<chain_group.scripts.length; i++) {
+ if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
+ any_scripts_ready = true;
+ chain_group.scripts[i].exec_trigger();
+ chain_group.scripts[i].exec_trigger = null;
+ }
+ }
+ return any_scripts_ready;
+ }
+
+ // creates a script load listener
+ function create_script_load_listener(elem,registry_item,flag,onload) {
+ elem.onload = elem.onreadystatechange = function() {
+ if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
+ elem.onload = elem.onreadystatechange = null;
+ onload();
+ };
+ }
+
+ // script executed handler
+ function script_executed(registry_item) {
+ registry_item.ready = registry_item.finished = true;
+ for (var i=0; i<registry_item.finished_listeners.length; i++) {
+ registry_item.finished_listeners[i]();
+ }
+ registry_item.ready_listeners = [];
+ registry_item.finished_listeners = [];
+ }
+
+ // make the request for a scriptha
+ function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
+ // setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
+ setTimeout(function(){
+ var script, src = script_obj.real_src, xhr;
+
+ // don't proceed until `append_to` is ready to append to
+ if ("item" in append_to) { // check if `append_to` ref is still a live node list
+ if (!append_to[0]) { // `append_to` node not yet ready
+ // try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
+ setTimeout(arguments.callee,25);
+ return;
+ }
+ // reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
+ append_to = append_to[0];
+ }
+ script = document.createElement("script");
+ if (script_obj.type) script.type = script_obj.type;
+ if (script_obj.charset) script.charset = script_obj.charset;
+
+ // should preloading be used for this script?
+ if (preload_this_script) {
+ // real script preloading?
+ if (real_preloading) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload: "+src);/*!END_DEBUG*/
+ registry_item.elem = script;
+ if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
+ script.preload = true;
+ script.onpreload = onload;
+ }
+ else {
+ script.onreadystatechange = function(){
+ if (script.readyState == "loaded") onload();
+ };
+ }
+ script.src = src;
+ // NOTE: no append to DOM yet, appending will happen when ready to execute
+ }
+ // same-domain and XHR allowed? use XHR preloading
+ else if (preload_this_script && src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR]) {
+ xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);/*!END_DEBUG*/
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ xhr.onreadystatechange = function(){}; // fix a memory leak in IE
+ registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
+ onload();
+ }
+ };
+ xhr.open("GET",src);
+ xhr.send();
+ }
+ // as a last resort, use cache-preloading
+ else {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);/*!END_DEBUG*/
+ script.type = "text/cache-script";
+ create_script_load_listener(script,registry_item,"ready",function() {
+ append_to.removeChild(script);
+ onload();
+ });
+ script.src = src;
+ append_to.insertBefore(script,append_to.firstChild);
+ }
+ }
+ // use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+ else if (script_ordered_async) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);/*!END_DEBUG*/
+ script.async = false;
+ create_script_load_listener(script,registry_item,"finished",onload);
+ script.src = src;
+ append_to.insertBefore(script,append_to.firstChild);
+ }
+ // otherwise, just a normal script element
+ else {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load: "+src);/*!END_DEBUG*/
+ create_script_load_listener(script,registry_item,"finished",onload);
+ script.src = src;
+ append_to.insertBefore(script,append_to.firstChild);
+ }
+ },0);
+ }
+
+ // create a clean instance of $LAB
+ function create_sandbox() {
+ var global_defaults = {},
+ can_use_preloading = real_preloading || xhr_or_cache_preloading,
+ queue = [],
+ registry = {},
+ instanceAPI
+ ;
+
+ // global defaults
+ global_defaults[_UseLocalXHR] = true;
+ global_defaults[_AlwaysPreserveOrder] = false;
+ global_defaults[_AllowDuplicates] = false;
+ global_defaults[_CacheBust] = false;
+ /*!START_DEBUG*/global_defaults[_Debug] = false;/*!END_DEBUG*/
+ global_defaults[_BasePath] = "";
+
+ // execute a script that has been preloaded already
+ function execute_preloaded_script(chain_opts,script_obj,registry_item) {
+ var script;
+
+ function preload_execute_finished() {
+ if (script != null) { // make sure this only ever fires once
+ script = null;
+ script_executed(registry_item);
+ }
+ }
+
+ if (registry[script_obj.src].finished) return;
+ if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;
+
+ script = registry_item.elem || document.createElement("script");
+ if (script_obj.type) script.type = script_obj.type;
+ if (script_obj.charset) script.charset = script_obj.charset;
+ create_script_load_listener(script,registry_item,"finished",preload_execute_finished);
+
+ // script elem was real-preloaded
+ if (registry_item.elem) {
+ registry_item.elem = null;
+ }
+ // script was XHR preloaded
+ else if (registry_item.text) {
+ script.onload = script.onreadystatechange = null; // script injection doesn't fire these events
+ script.text = registry_item.text;
+ }
+ // script was cache-preloaded
+ else {
+ script.src = script_obj.real_src;
+ }
+ append_to.insertBefore(script,append_to.firstChild);
+
+ // manually fire execution callback for injected scripts, since events don't fire
+ if (registry_item.text) {
+ preload_execute_finished();
+ }
+ }
+
+ // process the script request setup
+ function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
+ var registry_item,
+ registry_items,
+ ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
+ finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
+ ;
+
+ script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
+ script_obj.real_src = script_obj.src +
+ // append cache-bust param to URL?
+ (chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
+ ;
+
+ if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
+ registry_items = registry[script_obj.src].items;
+
+ // allowing duplicates, or is this the first recorded load of this script?
+ if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
+ registry_item = registry_items[registry_items.length] = {
+ ready:false,
+ finished:false,
+ ready_listeners:[ready_cb],
+ finished_listeners:[finished_cb]
+ };
+
+ request_script(chain_opts,script_obj,registry_item,
+ // which callback type to pass?
+ (
+ (preload_this_script) ? // depends on script-preloading
+ function(){
+ registry_item.ready = true;
+ for (var i=0; i<registry_item.ready_listeners.length; i++) {
+ registry_item.ready_listeners[i]();
+ }
+ registry_item.ready_listeners = [];
+ } :
+ function(){ script_executed(registry_item); }
+ ),
+ // signal if script-preloading should be used or not
+ preload_this_script
+ );
+ }
+ else {
+ registry_item = registry_items[0];
+ if (registry_item.finished) {
+ finished_cb();
+ }
+ else {
+ registry_item.finished_listeners.push(finished_cb);
+ }
+ }
+ }
+
+ // creates a closure for each separate chain spawned from this $LAB instance, to keep state cleanly separated between chains
+ function create_chain() {
+ var chainedAPI,
+ chain_opts = merge_objs(global_defaults,{}),
+ chain = [],
+ exec_cursor = 0,
+ scripts_currently_loading = false,
+ group
+ ;
+
+ // called when a script has finished preloading
+ function chain_script_ready(script_obj,exec_trigger) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);/*!END_DEBUG*/
+ script_obj.ready = true;
+ script_obj.exec_trigger = exec_trigger;
+ advance_exec_cursor(); // will only check for 'ready' scripts to be executed
+ }
+
+ // called when a script has finished executing
+ function chain_script_executed(script_obj,chain_group) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);/*!END_DEBUG*/
+ script_obj.ready = script_obj.finished = true;
+ script_obj.exec_trigger = null;
+ // check if chain group is all finished
+ for (var i=0; i<chain_group.scripts.length; i++) {
+ if (!chain_group.scripts[i].finished) return;
+ }
+ // chain_group is all finished if we get this far
+ chain_group.finished = true;
+ advance_exec_cursor();
+ }
+
+ // main driver for executing each part of the chain
+ function advance_exec_cursor() {
+ while (exec_cursor < chain.length) {
+ if (is_func(chain[exec_cursor])) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);/*!END_DEBUG*/
+ try { chain[exec_cursor++](); } catch (err) {
+ /*!START_DEBUG*/if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);/*!END_DEBUG*/
+ }
+ continue;
+ }
+ else if (!chain[exec_cursor].finished) {
+ if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
+ break;
+ }
+ exec_cursor++;
+ }
+ // we've reached the end of the chain (so far)
+ if (exec_cursor == chain.length) {
+ scripts_currently_loading = false;
+ group = false;
+ }
+ }
+
+ // setup next chain script group
+ function init_script_chain_group() {
+ if (!group || !group.scripts) {
+ chain.push(group = {scripts:[],finished:true});
+ }
+ }
+
+ // API for $LAB chains
+ chainedAPI = {
+ // start loading one or more scripts
+ script:function(){
+ for (var i=0; i<arguments.length; i++) {
+ (function(script_obj,script_list){
+ var splice_args;
+
+ if (!is_array(script_obj)) {
+ script_list = [script_obj];
+ }
+ for (var j=0; j<script_list.length; j++) {
+ init_script_chain_group();
+ script_obj = script_list[j];
+
+ if (is_func(script_obj)) script_obj = script_obj();
+ if (!script_obj) continue;
+ if (is_array(script_obj)) {
+ // set up an array of arguments to pass to splice()
+ splice_args = [].slice.call(script_obj); // first include the actual array elements we want to splice in
+ splice_args.unshift(j,1); // next, put the `index` and `howMany` parameters onto the beginning of the splice-arguments array
+ [].splice.apply(script_list,splice_args); // use the splice-arguments array as arguments for splice()
+ j--; // adjust `j` to account for the loop's subsequent `j++`, so that the next loop iteration uses the same `j` index value
+ continue;
+ }
+ if (typeof script_obj == "string") script_obj = {src:script_obj};
+ script_obj = merge_objs(script_obj,{
+ ready:false,
+ ready_cb:chain_script_ready,
+ finished:false,
+ finished_cb:chain_script_executed
+ });
+ group.finished = false;
+ group.scripts.push(script_obj);
+
+ do_script(chain_opts,script_obj,group,(can_use_preloading && scripts_currently_loading));
+ scripts_currently_loading = true;
+
+ if (chain_opts[_AlwaysPreserveOrder]) chainedAPI.wait();
+ }
+ })(arguments[i],arguments[i]);
+ }
+ return chainedAPI;
+ },
+ // force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding
+ wait:function(){
+ if (arguments.length > 0) {
+ for (var i=0; i<arguments.length; i++) {
+ chain.push(arguments[i]);
+ }
+ group = chain[chain.length-1];
+ }
+ else group = false;
+
+ advance_exec_cursor();
+
+ return chainedAPI;
+ }
+ };
+
+ // the first chain link API (includes `setOptions` only this first time)
+ return {
+ script:chainedAPI.script,
+ wait:chainedAPI.wait,
+ setOptions:function(opts){
+ merge_objs(opts,chain_opts);
+ return chainedAPI;
+ }
+ };
+ }
+
+ // API for each initial $LAB instance (before chaining starts)
+ instanceAPI = {
+ // main API functions
+ setGlobalDefaults:function(opts){
+ merge_objs(opts,global_defaults);
+ return instanceAPI;
+ },
+ setOptions:function(){
+ return create_chain().setOptions.apply(null,arguments);
+ },
+ script:function(){
+ return create_chain().script.apply(null,arguments);
+ },
+ wait:function(){
+ return create_chain().wait.apply(null,arguments);
+ },
+
+ // built-in queuing for $LAB `script()` and `wait()` calls
+ // useful for building up a chain programmatically across various script locations, and simulating
+ // execution of the chain
+ queueScript:function(){
+ queue[queue.length] = {type:"script", args:[].slice.call(arguments)};
+ return instanceAPI;
+ },
+ queueWait:function(){
+ queue[queue.length] = {type:"wait", args:[].slice.call(arguments)};
+ return instanceAPI;
+ },
+ runQueue:function(){
+ var $L = instanceAPI, len=queue.length, i=len, val;
+ for (;--i>=0;) {
+ val = queue.shift();
+ $L = $L[val.type].apply(null,val.args);
+ }
+ return $L;
+ },
+
+ // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
+ noConflict:function(){
+ global.$LAB = _$LAB;
+ return instanceAPI;
+ },
+
+ // create another clean instance of $LAB
+ sandbox:function(){
+ return create_sandbox();
+ }
+ };
+
+ return instanceAPI;
+ }
+
+ // create the main instance of $LAB
+ global.$LAB = create_sandbox();
+
+
+ /* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
+ NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
+
+ The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does
+ proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked
+ document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready.
+ For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or
+ fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
+ */
+ (function(addEvent,domLoaded,handler){
+ if (document.readyState == null && document[addEvent]){
+ document.readyState = "loading";
+ document[addEvent](domLoaded,handler = function(){
+ document.removeEventListener(domLoaded,handler,false);
+ document.readyState = "complete";
+ },false);
+ }
+ })("addEventListener","DOMContentLoaded");
+
+})(this); \ No newline at end of file
diff --git a/addons/web/static/lib/qunit/qunit-2011-23-22.css b/addons/web/static/lib/qunit/qunit-2011-23-22.css
new file mode 100644
index 00000000000..cc791a9b099
--- /dev/null
+++ b/addons/web/static/lib/qunit/qunit-2011-23-22.css
@@ -0,0 +1,248 @@
+/** Font Family and Sizes */
+
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+}
+
+#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li {
+ font-size: small;
+}
+
+#qunit-tests {
+ font-size: smaller;
+}
+
+/** Resets */
+
+#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
+ margin: 0;
+ padding: 0;
+}
+
+/** Header */
+
+#qunit-header {
+ padding: 0.5em 0 0.5em 1em;
+
+ color: #8699a4;
+ background-color: #0d3349;
+
+ font-size: 1.5em;
+ line-height: 1em;
+ font-weight: normal;
+
+ border-radius: 15px 15px 0 0;
+ -moz-border-radius: 15px 15px 0 0;
+ -webkit-border-top-right-radius: 15px;
+ -webkit-border-top-left-radius: 15px;
+}
+
+#qunit-header a {
+ text-decoration: none;
+ color: #c2ccd1;
+}
+
+#qunit-header a:hover,
+#qunit-header a:focus {
+ color: #fff;
+}
+
+#qunit-banner {
+ height: 5px;
+}
+
+#qunit-testrunner-toolbar {
+ padding: 0.5em 0 0.5em 2em;
+ color: #5E740B;
+ background-color: #eee;
+}
+
+#qunit-userAgent {
+ padding: 0.5em 0 0.5em 2.5em;
+ background-color: #2b81af;
+ color: #fff;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+
+/** Tests: Pass/Fail */
+
+#qunit-tests {
+ list-style-position: inside;
+}
+
+#qunit-tests li {
+ padding: 0.4em 0.5em 0.4em 2.5em;
+ border-bottom: 1px solid #fff;
+ list-style-position: inside;
+}
+
+#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
+ display: none;
+}
+
+#qunit-tests li strong {
+ cursor: pointer;
+}
+
+#qunit-tests li a {
+ padding: 0.5em;
+ color: #c2ccd1;
+ text-decoration: none;
+}
+
+#qunit-tests li a:hover,
+#qunit-tests li a:focus {
+ color: #000;
+}
+
+#qunit-tests ol {
+ margin-top: 0.5em;
+ padding: 0.5em;
+
+ background-color: #fff;
+
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+
+ box-shadow: inset 0px 2px 13px #999;
+ -moz-box-shadow: inset 0px 2px 13px #999;
+ -webkit-box-shadow: inset 0px 2px 13px #999;
+}
+
+#qunit-tests table {
+ border-collapse: collapse;
+ margin-top: .2em;
+}
+
+#qunit-tests th {
+ text-align: right;
+ vertical-align: top;
+ padding: 0 .5em 0 0;
+}
+
+#qunit-tests td {
+ vertical-align: top;
+}
+
+#qunit-tests pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#qunit-tests del {
+ background-color: #e0f2be;
+ color: #374e0c;
+ text-decoration: none;
+}
+
+#qunit-tests ins {
+ background-color: #ffcaca;
+ color: #500;
+ text-decoration: none;
+}
+
+/*** Test Counts */
+
+#qunit-tests b.counts {
+ color: black;
+}
+
+#qunit-tests b.passed {
+ color: #5E740B;
+}
+
+#qunit-tests b.failed {
+ color: #710909;
+}
+
+#qunit-tests li li {
+ margin: 0.5em;
+ padding: 0.4em 0.5em 0.4em 0.5em;
+ background-color: #fff;
+ border-bottom: none;
+ list-style-position: inside;
+}
+
+/*** Passing Styles */
+
+#qunit-tests li li.pass {
+ color: #5E740B;
+ background-color: #fff;
+ border-left: 26px solid #C6E746;
+}
+
+#qunit-tests .pass {
+ color: #528CE0;
+ background-color: #D2E0E6;
+}
+
+#qunit-tests .pass .test-name {
+ color: #366097;
+}
+
+#qunit-tests .pass .test-actual,
+#qunit-tests .pass .test-expected {
+ color: #999999;
+}
+
+#qunit-banner.qunit-pass {
+ background-color: #C6E746;
+}
+
+/*** Failing Styles */
+
+#qunit-tests li li.fail {
+ color: #710909;
+ background-color: #fff;
+ border-left: 26px solid #EE5757;
+}
+
+#qunit-tests > li:last-child {
+ border-radius: 0 0 15px 15px;
+ -moz-border-radius: 0 0 15px 15px;
+ -webkit-border-bottom-right-radius: 15px;
+ -webkit-border-bottom-left-radius: 15px;
+}
+
+#qunit-tests .fail {
+ color: #000000;
+ background-color: #EE5757;
+}
+
+#qunit-tests .fail .test-name,
+#qunit-tests .fail .module-name {
+ color: #000000;
+}
+
+#qunit-tests .fail .test-actual {
+ color: #EE5757;
+}
+
+#qunit-tests .fail .test-expected {
+ color: green;
+}
+
+#qunit-banner.qunit-fail {
+ background-color: #EE5757;
+}
+
+/** Result */
+
+#qunit-testresult {
+ padding: 0.5em 0.5em 0.5em 2.5em;
+
+ color: #2b81af;
+ background-color: #D2E0E6;
+
+ border-bottom: 1px solid white;
+}
+
+/** Fixture */
+
+#qunit-fixture {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+}
diff --git a/addons/web/static/lib/qunit/qunit-2011-23-22.js b/addons/web/static/lib/qunit/qunit-2011-23-22.js
new file mode 100644
index 00000000000..18f8ae1715c
--- /dev/null
+++ b/addons/web/static/lib/qunit/qunit-2011-23-22.js
@@ -0,0 +1,1456 @@
+/*
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * or GPL (GPL-LICENSE.txt) licenses.
+ */
+
+(function(window) {
+
+ var defined = {
+ setTimeout: typeof window.setTimeout !== "undefined",
+ sessionStorage: (function() {
+ try {
+ return !!sessionStorage.getItem;
+ } catch(e) {
+ return false;
+ }
+ })()
+ };
+
+ var testId = 0;
+
+ var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
+ this.name = name;
+ this.testName = testName;
+ this.expected = expected;
+ this.testEnvironmentArg = testEnvironmentArg;
+ this.async = async;
+ this.callback = callback;
+ this.assertions = [];
+ };
+ Test.prototype = {
+ init: function() {
+ var tests = id("qunit-tests");
+ if (tests) {
+ var b = document.createElement("strong");
+ b.innerHTML = "Running " + this.name;
+ var li = document.createElement("li");
+ li.appendChild(b);
+ li.className = "running";
+ li.id = this.id = "test-output" + testId++;
+ tests.appendChild(li);
+ }
+ },
+ setup: function() {
+ if (this.module != config.previousModule) {
+ if (config.previousModule) {
+ QUnit.moduleDone({
+ name: config.previousModule,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all
+ });
+ }
+ config.previousModule = this.module;
+ config.moduleStats = { all: 0, bad: 0 };
+ QUnit.moduleStart({
+ name: this.module
+ });
+ }
+
+ config.current = this;
+ this.testEnvironment = extend({
+ setup: function() {
+ },
+ teardown: function() {
+ }
+ }, this.moduleTestEnvironment);
+ if (this.testEnvironmentArg) {
+ extend(this.testEnvironment, this.testEnvironmentArg);
+ }
+
+ QUnit.testStart({
+ name: this.testName
+ });
+
+ // allow utility functions to access the current test environment
+ // TODO why??
+ QUnit.current_testEnvironment = this.testEnvironment;
+
+ try {
+ if (!config.pollution) {
+ saveGlobal();
+ }
+
+ this.testEnvironment.setup.call(this.testEnvironment);
+ } catch(e) {
+ QUnit.ok(false, "Setup failed on " + this.testName + ": " + e.message);
+ }
+ },
+ run: function() {
+ if (this.async) {
+ QUnit.stop();
+ }
+
+ if (config.notrycatch) {
+ this.callback.call(this.testEnvironment);
+ return;
+ }
+ try {
+ this.callback.call(this.testEnvironment);
+ } catch(e) {
+ fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
+ QUnit.ok(false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e));
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Restart the tests if they're blocking
+ if (config.blocking) {
+ start();
+ }
+ }
+ },
+ teardown: function() {
+ try {
+ checkPollution();
+ this.testEnvironment.teardown.call(this.testEnvironment);
+ } catch(e) {
+ QUnit.ok(false, "Teardown failed on " + this.testName + ": " + e.message);
+ }
+ },
+ finish: function() {
+ if (this.expected && this.expected != this.assertions.length) {
+ QUnit.ok(false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run");
+ }
+
+ var good = 0, bad = 0,
+ tests = id("qunit-tests");
+
+ config.stats.all += this.assertions.length;
+ config.moduleStats.all += this.assertions.length;
+
+ if (tests) {
+ var ol = document.createElement("ol");
+
+ for (var i = 0; i < this.assertions.length; i++) {
+ var assertion = this.assertions[i];
+
+ var li = document.createElement("li");
+ li.className = assertion.result ? "pass" : "fail";
+ li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
+ ol.appendChild(li);
+
+ if (assertion.result) {
+ good++;
+ } else {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+
+ // store result when possible
+ if (QUnit.config.reorder && defined.sessionStorage) {
+ if (bad) {
+ sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad)
+ } else {
+ sessionStorage.removeItem("qunit-" + this.testName);
+ }
+ }
+
+ if (bad == 0) {
+ ol.style.display = "none";
+ }
+
+ var b = document.createElement("strong");
+ b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
+
+ var a = document.createElement("a");
+ a.innerHTML = "Rerun";
+ a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
+
+ addEvent(b, "click", function() {
+ var next = b.nextSibling.nextSibling,
+ display = next.style.display;
+ next.style.display = display === "none" ? "block" : "none";
+ });
+
+ addEvent(b, "dblclick", function(e) {
+ var target = e && e.target ? e.target : window.event.srcElement;
+ if (target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b") {
+ target = target.parentNode;
+ }
+ if (window.location && target.nodeName.toLowerCase() === "strong") {
+ window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
+ }
+ });
+
+ var li = id(this.id);
+ li.className = bad ? "fail" : "pass";
+ li.removeChild(li.firstChild);
+ li.appendChild(b);
+ li.appendChild(a);
+ li.appendChild(ol);
+
+ } else {
+ for (var i = 0; i < this.assertions.length; i++) {
+ if (!this.assertions[i].result) {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+ }
+
+ try {
+ QUnit.reset();
+ } catch(e) {
+ fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
+ }
+
+ QUnit.testDone({
+ name: this.testName,
+ failed: bad,
+ passed: this.assertions.length - bad,
+ total: this.assertions.length
+ });
+ },
+
+ queue: function() {
+ var test = this;
+ synchronize(function() {
+ test.init();
+ });
+ function run() {
+ // each of these can by async
+ synchronize(function() {
+ test.setup();
+ });
+ synchronize(function() {
+ test.run();
+ });
+ synchronize(function() {
+ test.teardown();
+ });
+ synchronize(function() {
+ test.finish();
+ });
+ }
+
+ // defer when previous test run passed, if storage is available
+ var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
+ if (bad) {
+ run();
+ } else {
+ synchronize(run);
+ }
+ ;
+ }
+
+ };
+
+ var QUnit = {
+
+ // call on start of module test to prepend name to all tests
+ module: function(name, testEnvironment) {
+ config.currentModule = name;
+ config.currentModuleTestEnviroment = testEnvironment;
+ },
+
+ asyncTest: function(testName, expected, callback) {
+ if (arguments.length === 2) {
+ callback = expected;
+ expected = 0;
+ }
+
+ QUnit.test(testName, expected, callback, true);
+ },
+
+ test: function(testName, expected, callback, async) {
+ var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
+
+ if (arguments.length === 2) {
+ callback = expected;
+ expected = null;
+ }
+ // is 2nd argument a testEnvironment?
+ if (expected && typeof expected === 'object') {
+ testEnvironmentArg = expected;
+ expected = null;
+ }
+
+ if (config.currentModule) {
+ name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
+ }
+
+ if (!validTest(config.currentModule + ": " + testName)) {
+ return;
+ }
+
+ var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
+ test.module = config.currentModule;
+ test.moduleTestEnvironment = config.currentModuleTestEnviroment;
+ test.queue();
+ },
+
+ /**
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
+ */
+ expect: function(asserts) {
+ config.current.expected = asserts;
+ },
+
+ /**
+ * Asserts true.
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
+ */
+ ok: function(a, msg) {
+ a = !!a;
+ var details = {
+ result: a,
+ message: msg
+ };
+ msg = escapeHtml(msg);
+ QUnit.log(details);
+ config.current.assertions.push({
+ result: a,
+ message: msg
+ });
+ },
+
+ /**
+ * Checks that the first two arguments are equal, with an optional message.
+ * Prints out both actual and expected values.
+ *
+ * Prefered to ok( actual == expected, message )
+ *
+ * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
+ *
+ * @param Object actual
+ * @param Object expected
+ * @param String message (optional)
+ */
+ equal: function(actual, expected, message) {
+ QUnit.push(expected == actual, actual, expected, message);
+ },
+
+ notEqual: function(actual, expected, message) {
+ QUnit.push(expected != actual, actual, expected, message);
+ },
+
+ deepEqual: function(actual, expected, message) {
+ QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
+ },
+
+ notDeepEqual: function(actual, expected, message) {
+ QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
+ },
+
+ strictEqual: function(actual, expected, message) {
+ QUnit.push(expected === actual, actual, expected, message);
+ },
+
+ notStrictEqual: function(actual, expected, message) {
+ QUnit.push(expected !== actual, actual, expected, message);
+ },
+
+ raises: function(block, expected, message) {
+ var actual, ok = false;
+
+ if (typeof expected === 'string') {
+ message = expected;
+ expected = null;
+ }
+
+ try {
+ block();
+ } catch (e) {
+ actual = e;
+ }
+
+ if (actual) {
+ // we don't want to validate thrown error
+ if (!expected) {
+ ok = true;
+ // expected is a regexp
+ } else if (QUnit.objectType(expected) === "regexp") {
+ ok = expected.test(actual);
+ // expected is a constructor
+ } else if (actual instanceof expected) {
+ ok = true;
+ // expected is a validation function which returns true is validation passed
+ } else if (expected.call({}, actual) === true) {
+ ok = true;
+ }
+ }
+
+ QUnit.ok(ok, message);
+ },
+
+ start: function() {
+ config.semaphore--;
+ if (config.semaphore > 0) {
+ // don't start until equal number of stop-calls
+ return;
+ }
+ if (config.semaphore < 0) {
+ // ignore if start is called more often then stop
+ config.semaphore = 0;
+ }
+ // A slight delay, to avoid any current callbacks
+ if (defined.setTimeout) {
+ window.setTimeout(function() {
+ if (config.timeout) {
+ clearTimeout(config.timeout);
+ }
+
+ config.blocking = false;
+ process();
+ }, 13);
+ } else {
+ config.blocking = false;
+ process();
+ }
+ },
+
+ stop: function(timeout) {
+ config.semaphore++;
+ config.blocking = true;
+
+ if (timeout && defined.setTimeout) {
+ clearTimeout(config.timeout);
+ config.timeout = window.setTimeout(function() {
+ QUnit.ok(false, "Test timed out");
+ QUnit.start();
+ }, timeout);
+ }
+ }
+ };
+
+// Backwards compatibility, deprecated
+ QUnit.equals = QUnit.equal;
+ QUnit.same = QUnit.deepEqual;
+
+// Maintain internal state
+ var config = {
+ // The queue of tests to run
+ queue: [],
+
+ // block until document ready
+ blocking: true,
+
+ // by default, run previously failed tests first
+ // very useful in combination with "Hide passed tests" checked
+ reorder: true,
+
+ noglobals: false,
+ notrycatch: false
+ };
+
+// Load paramaters
+ (function() {
+ var location = window.location || { search: "", protocol: "file:" },
+ params = location.search.slice(1).split("&"),
+ length = params.length,
+ urlParams = {},
+ current;
+
+ if (params[ 0 ]) {
+ for (var i = 0; i < length; i++) {
+ current = params[ i ].split("=");
+ current[ 0 ] = decodeURIComponent(current[ 0 ]);
+ // allow just a key to turn on a flag, e.g., test.html?noglobals
+ current[ 1 ] = current[ 1 ] ? decodeURIComponent(current[ 1 ]) : true;
+ urlParams[ current[ 0 ] ] = current[ 1 ];
+ if (current[ 0 ] in config) {
+ config[ current[ 0 ] ] = current[ 1 ];
+ }
+ }
+ }
+
+ QUnit.urlParams = urlParams;
+ config.filter = urlParams.filter;
+
+ // Figure out if we're running the tests from a server or not
+ QUnit.isLocal = !!(location.protocol === 'file:');
+ })();
+
+// Expose the API as global variables, unless an 'exports'
+// object exists, in that case we assume we're in CommonJS
+ if (typeof exports === "undefined" || typeof require === "undefined") {
+ extend(window, QUnit);
+ window.QUnit = QUnit;
+ } else {
+ extend(exports, QUnit);
+ exports.QUnit = QUnit;
+ }
+
+// define these after exposing globals to keep them in these QUnit namespace only
+ extend(QUnit, {
+ config: config,
+
+ // Initialize the configuration options
+ init: function() {
+ extend(config, {
+ stats: { all: 0, bad: 0 },
+ moduleStats: { all: 0, bad: 0 },
+ started: +new Date,
+ updateRate: 1000,
+ blocking: false,
+ autostart: true,
+ autorun: false,
+ filter: "",
+ queue: [],
+ semaphore: 0
+ });
+
+ var tests = id("qunit-tests"),
+ banner = id("qunit-banner"),
+ result = id("qunit-testresult");
+
+ if (tests) {
+ tests.innerHTML = "";
+ }
+
+ if (banner) {
+ banner.className = "";
+ }
+
+ if (result) {
+ result.parentNode.removeChild(result);
+ }
+
+ if (tests) {
+ result = document.createElement("p");
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore(result, tests);
+ result.innerHTML = 'Running...<br/>&nbsp;';
+ }
+ },
+
+ /**
+ * Resets the test setup. Useful for tests that modify the DOM.
+ *
+ * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
+ */
+ reset: function() {
+ if (window.jQuery) {
+ jQuery("#main, #qunit-fixture").html(config.fixture);
+ } else {
+ var main = id('main') || id('qunit-fixture');
+ if (main) {
+ main.innerHTML = config.fixture;
+ }
+ }
+ },
+
+ /**
+ * Trigger an event on an element.
+ *
+ * @example triggerEvent( document.body, "click" );
+ *
+ * @param {Element} elem
+ * @param {String} type
+ */
+ triggerEvent: function(elem, type, event) {
+ if (document.createEvent) {
+ event = document.createEvent("MouseEvents");
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ elem.dispatchEvent(event);
+
+ } else if (elem.fireEvent) {
+ elem.fireEvent("on" + type);
+ }
+ },
+
+ // Safe object type checking
+ is: function(type, obj) {
+ return QUnit.objectType(obj) == type;
+ },
+
+ objectType: function(obj) {
+ if (typeof obj === "undefined") {
+ return "undefined";
+
+ // consider: typeof null === object
+ }
+ if (obj === null) {
+ return "null";
+ }
+
+ var type = Object.prototype.toString.call(obj)
+ .match(/^\[object\s(.*)\]$/)[1] || '';
+
+ switch (type) {
+ case 'Number':
+ if (isNaN(obj)) {
+ return "nan";
+ } else {
+ return "number";
+ }
+ case 'String':
+ case 'Boolean':
+ case 'Array':
+ case 'Date':
+ case 'RegExp':
+ case 'Function':
+ return type.toLowerCase();
+ }
+ if (typeof obj === "object") {
+ return "object";
+ }
+ return undefined;
+ },
+
+ push: function(result, actual, expected, message) {
+ var details = {
+ result: result,
+ message: message,
+ actual: actual,
+ expected: expected
+ };
+
+ message = escapeHtml(message) || (result ? "okay" : "failed");
+ message = '<span class="test-message">' + message + "</span>";
+ expected = escapeHtml(QUnit.jsDump.parse(expected));
+ actual = escapeHtml(QUnit.jsDump.parse(actual));
+ var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
+ if (actual != expected) {
+ output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
+ output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) + '</pre></td></tr>';
+ }
+ if (!result) {
+ var source = sourceFromStacktrace();
+ if (source) {
+ details.source = source;
+ output += '<tr class="test-source"><th>Source: </th><td><pre>' + source + '</pre></td></tr>';
+ }
+ }
+ output += "</table>";
+
+ QUnit.log(details);
+
+ config.current.assertions.push({
+ result: !!result,
+ message: output
+ });
+ },
+
+ url: function(params) {
+ params = extend(extend({}, QUnit.urlParams), params);
+ var querystring = "?",
+ key;
+ for (key in params) {
+ querystring += encodeURIComponent(key) + "=" +
+ encodeURIComponent(params[ key ]) + "&";
+ }
+ return window.location.pathname + querystring.slice(0, -1);
+ },
+
+ // Logging callbacks; all receive a single argument with the listed properties
+ // run test/logs.html for any related changes
+ begin: function() {
+ },
+ // done: { failed, passed, total, runtime }
+ done: function() {
+ },
+ // log: { result, actual, expected, message }
+ log: function() {
+ },
+ // testStart: { name }
+ testStart: function() {
+ },
+ // testDone: { name, failed, passed, total }
+ testDone: function() {
+ },
+ // moduleStart: { name }
+ moduleStart: function() {
+ },
+ // moduleDone: { name, failed, passed, total }
+ moduleDone: function() {
+ }
+ });
+
+ if (typeof document === "undefined" || document.readyState === "complete") {
+ config.autorun = true;
+ }
+
+ addEvent(window, "load", function() {
+ QUnit.begin({});
+
+ // Initialize the config, saving the execution queue
+ var oldconfig = extend({}, config);
+ QUnit.init();
+ extend(config, oldconfig);
+
+ config.blocking = false;
+
+ var userAgent = id("qunit-userAgent");
+ if (userAgent) {
+ userAgent.innerHTML = navigator.userAgent;
+ }
+ var banner = id("qunit-header");
+ if (banner) {
+ banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' +
+ '<label><input name="noglobals" type="checkbox"' + ( config.noglobals ? ' checked="checked"' : '' ) + '>noglobals</label>' +
+ '<label><input name="notrycatch" type="checkbox"' + ( config.notrycatch ? ' checked="checked"' : '' ) + '>notrycatch</label>';
+ addEvent(banner, "change", function(event) {
+ var params = {};
+ params[ event.target.name ] = event.target.checked ? true : undefined;
+ window.location = QUnit.url(params);
+ });
+ }
+
+ var toolbar = id("qunit-testrunner-toolbar");
+ if (toolbar) {
+ var filter = document.createElement("input");
+ filter.type = "checkbox";
+ filter.id = "qunit-filter-pass";
+ addEvent(filter, "click", function() {
+ var ol = document.getElementById("qunit-tests");
+ if (filter.checked) {
+ ol.className = ol.className + " hidepass";
+ } else {
+ var tmp = " " + ol.className.replace(/[\n\t\r]/g, " ") + " ";
+ ol.className = tmp.replace(/ hidepass /, " ");
+ }
+ if (defined.sessionStorage) {
+ if (filter.checked) {
+ sessionStorage.setItem("qunit-filter-passed-tests", "true");
+ } else {
+ sessionStorage.removeItem("qunit-filter-passed-tests");
+ }
+ }
+ });
+ if (defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests")) {
+ filter.checked = true;
+ var ol = document.getElementById("qunit-tests");
+ ol.className = ol.className + " hidepass";
+ }
+ toolbar.appendChild(filter);
+
+ var label = document.createElement("label");
+ label.setAttribute("for", "qunit-filter-pass");
+ label.innerHTML = "Hide passed tests";
+ toolbar.appendChild(label);
+ }
+
+ var main = id('main') || id('qunit-fixture');
+ if (main) {
+ config.fixture = main.innerHTML;
+ }
+
+ if (config.autostart) {
+ QUnit.start();
+ }
+ });
+
+ function done() {
+ config.autorun = true;
+
+ // Log the last module results
+ if (config.currentModule) {
+ QUnit.moduleDone({
+ name: config.currentModule,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all
+ });
+ }
+
+ var banner = id("qunit-banner"),
+ tests = id("qunit-tests"),
+ runtime = +new Date - config.started,
+ passed = config.stats.all - config.stats.bad,
+ html = [
+ 'Tests completed in ',
+ runtime,
+ ' milliseconds.<br/>',
+ '<span class="passed">',
+ passed,
+ '</span> tests of <span class="total">',
+ config.stats.all,
+ '</span> passed, <span class="failed">',
+ config.stats.bad,
+ '</span> failed.'
+ ].join('');
+
+ if (banner) {
+ banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
+ }
+
+ if (tests) {
+ id("qunit-testresult").innerHTML = html;
+ }
+
+ QUnit.done({
+ failed: config.stats.bad,
+ passed: passed,
+ total: config.stats.all,
+ runtime: runtime
+ });
+ }
+
+ function validTest(name) {
+ var filter = config.filter,
+ run = false;
+
+ if (!filter) {
+ return true;
+ }
+
+ var not = filter.charAt(0) === "!";
+ if (not) {
+ filter = filter.slice(1);
+ }
+
+ if (name.indexOf(filter) !== -1) {
+ return !not;
+ }
+
+ if (not) {
+ run = true;
+ }
+
+ return run;
+ }
+
+// so far supports only Firefox, Chrome and Opera (buggy)
+// could be extended in the future to use something like https://github.com/csnover/TraceKit
+ function sourceFromStacktrace() {
+ try {
+ throw new Error();
+ } catch (e) {
+ if (e.stacktrace) {
+ // Opera
+ return e.stacktrace.split("\n")[6];
+ } else if (e.stack) {
+ // Firefox, Chrome
+ return e.stack.split("\n")[4];
+ }
+ }
+ }
+
+ function escapeHtml(s) {
+ if (!s) {
+ return "";
+ }
+ s = s + "";
+ return s.replace(/[\&"<>\\]/g, function(s) {
+ switch (s) {
+ case "&": return "&amp;";
+ case "\\": return "\\\\";
+ case '"': return '\"';
+ case "<": return "&lt;";
+ case ">": return "&gt;";
+ default: return s;
+ }
+ });
+ }
+
+ function synchronize(callback) {
+ config.queue.push(callback);
+
+ if (config.autorun && !config.blocking) {
+ process();
+ }
+ }
+
+ function process() {
+ var start = (new Date()).getTime();
+
+ while (config.queue.length && !config.blocking) {
+ if (config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate)) {
+ config.queue.shift()();
+ } else {
+ window.setTimeout(process, 13);
+ break;
+ }
+ }
+ if (!config.blocking && !config.queue.length) {
+ done();
+ }
+ }
+
+ function saveGlobal() {
+ config.pollution = [];
+
+ if (config.noglobals) {
+ for (var key in window) {
+ config.pollution.push(key);
+ }
+ }
+ }
+
+ function checkPollution(name) {
+ var old = config.pollution;
+ saveGlobal();
+
+ var newGlobals = diff(config.pollution, old);
+ if (newGlobals.length > 0) {
+ ok(false, "Introduced global variable(s): " + newGlobals.join(", "));
+ }
+
+ var deletedGlobals = diff(old, config.pollution);
+ if (deletedGlobals.length > 0) {
+ ok(false, "Deleted global variable(s): " + deletedGlobals.join(", "));
+ }
+ }
+
+// returns a new Array with the elements that are in a but not in b
+ function diff(a, b) {
+ var result = a.slice();
+ for (var i = 0; i < result.length; i++) {
+ for (var j = 0; j < b.length; j++) {
+ if (result[i] === b[j]) {
+ result.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ function fail(message, exception, callback) {
+ if (typeof console !== "undefined" && console.error && console.warn) {
+ console.error(message);
+ console.error(exception);
+ console.warn(callback.toString());
+
+ } else if (window.opera && opera.postError) {
+ opera.postError(message, exception, callback.toString);
+ }
+ }
+
+ function extend(a, b) {
+ for (var prop in b) {
+ if (b[prop] === undefined) {
+ delete a[prop];
+ } else {
+ a[prop] = b[prop];
+ }
+ }
+
+ return a;
+ }
+
+ function addEvent(elem, type, fn) {
+ if (elem.addEventListener) {
+ elem.addEventListener(type, fn, false);
+ } else if (elem.attachEvent) {
+ elem.attachEvent("on" + type, fn);
+ } else {
+ fn();
+ }
+ }
+
+ function id(name) {
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
+ document.getElementById(name);
+ }
+
+// Test for equality any JavaScript type.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+ QUnit.equiv = function () {
+
+ var innerEquiv; // the real equiv function
+ var callers = []; // stack to decide between skip/abort functions
+ var parents = []; // stack to avoiding loops from circular referencing
+
+ // Call the o related callback with the given arguments.
+ function bindCallbacks(o, callbacks, args) {
+ var prop = QUnit.objectType(o);
+ if (prop) {
+ if (QUnit.objectType(callbacks[prop]) === "function") {
+ return callbacks[prop].apply(callbacks, args);
+ } else {
+ return callbacks[prop]; // or undefined
+ }
+ }
+ }
+
+ var callbacks = function () {
+
+ // for string, boolean, number and null
+ function useStrictEquality(b, a) {
+ if (b instanceof a.constructor || a instanceof b.constructor) {
+ // to catch short annotaion VS 'new' annotation of a declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+
+ "nan": function (b) {
+ return isNaN(b);
+ },
+
+ "date": function (b, a) {
+ return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
+ },
+
+ "regexp": function (b, a) {
+ return QUnit.objectType(b) === "regexp" &&
+ a.source === b.source && // the regex itself
+ a.global === b.global && // and its modifers (gmi) ...
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function": function () {
+ var caller = callers[callers.length - 1];
+ return caller !== Object &&
+ typeof caller !== "undefined";
+ },
+
+ "array": function (b, a) {
+ var i, j, loop;
+ var len;
+
+ // b could be an object literal here
+ if (! (QUnit.objectType(b) === "array")) {
+ return false;
+ }
+
+ len = a.length;
+ if (len !== b.length) { // safe and faster
+ return false;
+ }
+
+ //track reference to avoid circular references
+ parents.push(a);
+ for (i = 0; i < len; i++) {
+ loop = false;
+ for (j = 0; j < parents.length; j++) {
+ if (parents[j] === a[i]) {
+ loop = true;//dont rewalk array
+ }
+ }
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ parents.pop();
+ return false;
+ }
+ }
+ parents.pop();
+ return true;
+ },
+
+ "object": function (b, a) {
+ var i, j, loop;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of strings
+
+ // comparing constructors is more strict than using instanceof
+ if (a.constructor !== b.constructor) {
+ return false;
+ }
+
+ // stack constructor before traversing properties
+ callers.push(a.constructor);
+ //track reference to avoid circular references
+ parents.push(a);
+
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
+ loop = false;
+ for (j = 0; j < parents.length; j++) {
+ if (parents[j] === a[i])
+ loop = true; //don't go down the same path twice
+ }
+ aProperties.push(i); // collect a's properties
+
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ eq = false;
+ break;
+ }
+ }
+
+ callers.pop(); // unstack, we are done
+ parents.pop();
+
+ for (i in b) {
+ bProperties.push(i); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
+ }
+ };
+ }();
+
+ innerEquiv = function () { // can take multiple arguments
+ var args = Array.prototype.slice.apply(arguments);
+ if (args.length < 2) {
+ return true; // end transition
+ }
+
+ return (function (a, b) {
+ if (a === b) {
+ return true; // catch the most you can
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
+ return false; // don't lose time with error prone cases
+ } else {
+ return bindCallbacks(a, callbacks, [b, a]);
+ }
+
+ // apply transition with (1..n) arguments
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length - 1));
+ };
+
+ return innerEquiv;
+
+ }();
+
+ /**
+ * jsDump
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
+ * Date: 5/15/2008
+ * @projectDescription Advanced and extensible data dumping for Javascript.
+ * @version 1.0.0
+ * @author Ariel Flesler
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
+ */
+ QUnit.jsDump = (function() {
+ function quote(str) {
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
+ }
+
+ function literal(o) {
+ return o + '';
+ }
+
+ function join(pre, arr, post) {
+ var s = jsDump.separator(),
+ base = jsDump.indent(),
+ inner = jsDump.indent(1);
+ if (arr.join)
+ arr = arr.join(',' + s + inner);
+ if (!arr)
+ return pre + post;
+ return [ pre, inner + arr, base + post ].join(s);
+ }
+
+ function array(arr) {
+ var i = arr.length, ret = Array(i);
+ this.up();
+ while (i--)
+ ret[i] = this.parse(arr[i]);
+ this.down();
+ return join('[', ret, ']');
+ }
+
+ var reName = /^function (\w+)/;
+
+ var jsDump = {
+ parse:function(obj, type) { //type is used mostly internally, you can fix a (custom)type in advance
+ var parser = this.parsers[ type || this.typeOf(obj) ];
+ type = typeof parser;
+
+ return type == 'function' ? parser.call(this, obj) :
+ type == 'string' ? parser :
+ this.parsers.error;
+ },
+ typeOf:function(obj) {
+ var type;
+ if (obj === null) {
+ type = "null";
+ } else if (typeof obj === "undefined") {
+ type = "undefined";
+ } else if (QUnit.is("RegExp", obj)) {
+ type = "regexp";
+ } else if (QUnit.is("Date", obj)) {
+ type = "date";
+ } else if (QUnit.is("Function", obj)) {
+ type = "function";
+ } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
+ type = "window";
+ } else if (obj.nodeType === 9) {
+ type = "document";
+ } else if (obj.nodeType) {
+ type = "node";
+ } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
+ type = "array";
+ } else {
+ type = typeof obj;
+ }
+ return type;
+ },
+ separator:function() {
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
+ },
+ indent:function(extra) {// extra can be a number, shortcut for increasing-calling-decreasing
+ if (!this.multiline)
+ return '';
+ var chr = this.indentChar;
+ if (this.HTML)
+ chr = chr.replace(/\t/g, ' ').replace(/ /g, '&nbsp;');
+ return Array(this._depth_ + (extra || 0)).join(chr);
+ },
+ up:function(a) {
+ this._depth_ += a || 1;
+ },
+ down:function(a) {
+ this._depth_ -= a || 1;
+ },
+ setParser:function(name, parser) {
+ this.parsers[name] = parser;
+ },
+ // The next 3 are exposed so you can use them
+ quote:quote,
+ literal:literal,
+ join:join,
+ //
+ _depth_: 1,
+ // This is the list of parsers, to modify them, use jsDump.setParser
+ parsers:{
+ window: '[Window]',
+ document: '[Document]',
+ error:'[ERROR]', //when no parser is found, shouldn't happen
+ unknown: '[Unknown]',
+ 'null':'null',
+ 'undefined':'undefined',
+ 'function':function(fn) {
+ var ret = 'function',
+ name = 'name' in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE
+ if (name)
+ ret += ' ' + name;
+ ret += '(';
+
+ ret = [ ret, QUnit.jsDump.parse(fn, 'functionArgs'), '){'].join('');
+ return join(ret, QUnit.jsDump.parse(fn, 'functionCode'), '}');
+ },
+ array: array,
+ nodelist: array,
+ arguments: array,
+ object:function(map) {
+ var ret = [ ];
+ QUnit.jsDump.up();
+ for (var key in map)
+ ret.push(QUnit.jsDump.parse(key, 'key') + ': ' + QUnit.jsDump.parse(map[key]));
+ QUnit.jsDump.down();
+ return join('{', ret, '}');
+ },
+ node:function(node) {
+ var open = QUnit.jsDump.HTML ? '&lt;' : '<',
+ close = QUnit.jsDump.HTML ? '&gt;' : '>';
+
+ var tag = node.nodeName.toLowerCase(),
+ ret = open + tag;
+
+ for (var a in QUnit.jsDump.DOMAttrs) {
+ var val = node[QUnit.jsDump.DOMAttrs[a]];
+ if (val)
+ ret += ' ' + a + '=' + QUnit.jsDump.parse(val, 'attribute');
+ }
+ return ret + close + open + '/' + tag + close;
+ },
+ functionArgs:function(fn) {//function calls it internally, it's the arguments part of the function
+ var l = fn.length;
+ if (!l) return '';
+
+ var args = Array(l);
+ while (l--)
+ args[l] = String.fromCharCode(97 + l);//97 is 'a'
+ return ' ' + args.join(', ') + ' ';
+ },
+ key:quote, //object calls it internally, the key part of an item in a map
+ functionCode:'[code]', //function calls it internally, it's the content of the function
+ attribute:quote, //node calls it internally, it's an html attribute value
+ string:quote,
+ date:quote,
+ regexp:literal, //regex
+ number:literal,
+ 'boolean':literal
+ },
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
+ id:'id',
+ name:'name',
+ 'class':'className'
+ },
+ HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
+ indentChar:' ',//indentation unit
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
+ };
+
+ return jsDump;
+ })();
+
+// from Sizzle.js
+ function getText(elems) {
+ var ret = "", elem;
+
+ for (var i = 0; elems[i]; i++) {
+ elem = elems[i];
+
+ // Get the text from text nodes and CDATA nodes
+ if (elem.nodeType === 3 || elem.nodeType === 4) {
+ ret += elem.nodeValue;
+
+ // Traverse everything else, except comment nodes
+ } else if (elem.nodeType !== 8) {
+ ret += getText(elem.childNodes);
+ }
+ }
+
+ return ret;
+ }
+
+ /*
+ * Javascript Diff Algorithm
+ * By John Resig (http://ejohn.org/)
+ * Modified by Chu Alan "sprite"
+ *
+ * Released under the MIT license.
+ *
+ * More Info:
+ * http://ejohn.org/projects/javascript-diff-algorithm/
+ *
+ * Usage: QUnit.diff(expected, actual)
+ *
+ * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
+ */
+ QUnit.diff = (function() {
+ function diff(o, n) {
+ var ns = new Object();
+ var os = new Object();
+
+ for (var i = 0; i < n.length; i++) {
+ if (ns[n[i]] == null)
+ ns[n[i]] = {
+ rows: new Array(),
+ o: null
+ };
+ ns[n[i]].rows.push(i);
+ }
+
+ for (var i = 0; i < o.length; i++) {
+ if (os[o[i]] == null)
+ os[o[i]] = {
+ rows: new Array(),
+ n: null
+ };
+ os[o[i]].rows.push(i);
+ }
+
+ for (var i in ns) {
+ if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
+ n[ns[i].rows[0]] = {
+ text: n[ns[i].rows[0]],
+ row: os[i].rows[0]
+ };
+ o[os[i].rows[0]] = {
+ text: o[os[i].rows[0]],
+ row: ns[i].rows[0]
+ };
+ }
+ }
+
+ for (var i = 0; i < n.length - 1; i++) {
+ if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
+ n[i + 1] == o[n[i].row + 1]) {
+ n[i + 1] = {
+ text: n[i + 1],
+ row: n[i].row + 1
+ };
+ o[n[i].row + 1] = {
+ text: o[n[i].row + 1],
+ row: i + 1
+ };
+ }
+ }
+
+ for (var i = n.length - 1; i > 0; i--) {
+ if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
+ n[i - 1] == o[n[i].row - 1]) {
+ n[i - 1] = {
+ text: n[i - 1],
+ row: n[i].row - 1
+ };
+ o[n[i].row - 1] = {
+ text: o[n[i].row - 1],
+ row: i - 1
+ };
+ }
+ }
+
+ return {
+ o: o,
+ n: n
+ };
+ }
+
+ return function(o, n) {
+ o = o.replace(/\s+$/, '');
+ n = n.replace(/\s+$/, '');
+ var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
+
+ var str = "";
+
+ var oSpace = o.match(/\s+/g);
+ if (oSpace == null) {
+ oSpace = [" "];
+ }
+ else {
+ oSpace.push(" ");
+ }
+ var nSpace = n.match(/\s+/g);
+ if (nSpace == null) {
+ nSpace = [" "];
+ }
+ else {
+ nSpace.push(" ");
+ }
+
+ if (out.n.length == 0) {
+ for (var i = 0; i < out.o.length; i++) {
+ str += '<del>' + out.o[i] + oSpace[i] + "</del>";
+ }
+ }
+ else {
+ if (out.n[0].text == null) {
+ for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
+ str += '<del>' + out.o[n] + oSpace[n] + "</del>";
+ }
+ }
+
+ for (var i = 0; i < out.n.length; i++) {
+ if (out.n[i].text == null) {
+ str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
+ }
+ else {
+ var pre = "";
+
+ for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
+ pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
+ }
+ str += " " + out.n[i].text + nSpace[i] + pre;
+ }
+ }
+ }
+
+ return str;
+ };
+ })();
+
+})(this);
diff --git a/addons/web/static/lib/qweb/qweb-benchmark.html b/addons/web/static/lib/qweb/qweb-benchmark.html
new file mode 100644
index 00000000000..0cc67e7e54f
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-benchmark.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html style="height: 100%">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" src="qweb.js"></script>
+ <script type="text/javascript" src="qweb2.js"></script>
+ <script type="text/javascript">
+ var dict = {
+ session : true,
+ testing : 'yes',
+ name : 'AGR'
+ }
+ console.time("Load template with QWeb");
+ QWeb.add_template("qweb-benchmark.xml");
+ console.timeEnd("Load template with QWeb");
+
+ console.time("Load template with QWeb2");
+ var engine = new QWeb2.Engine("qweb-benchmark.xml")
+ engine.debug = true;
+ console.timeEnd("Load template with QWeb2")
+
+ var iter = 1000;
+ console.log("Rendering...");
+ console.time("Render " + iter + " templates with QWeb");
+ for (var i = 0; i < iter; i++) {
+ var qweb = QWeb.render('benchmark', dict);
+ }
+ console.timeEnd("Render " + iter + " templates with QWeb");
+
+ console.time("Render " + iter + " templates with QWeb2");
+ for (var i = 0; i < iter; i++) {
+ var qweb2 = engine.render('benchmark', dict);
+ }
+ console.timeEnd("Render " + iter + " templates with QWeb2");
+ </script>
+</head>
+
+<body>
+Please, check your console for results
+</body>
+
+</html>
+
diff --git a/addons/web/static/lib/qweb/qweb-benchmark.xml b/addons/web/static/lib/qweb/qweb-benchmark.xml
new file mode 100644
index 00000000000..71452572e51
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-benchmark.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vim:fdl=1:
+-->
+<templates id="template">
+<t t-name="benchmark"><div id="oe_notification" class="oe_notification">
+ <div id="oe_notification_default">
+ <a class="ui-notify-cross ui-notify-close" href="#">x</a>
+ <h1>title</h1>
+ <p>text</p>
+ </div>
+ <div id="oe_notification_alert" class="ui-state-error">
+ <a class="ui-notify-cross ui-notify-close" href="#">x</a>
+ <span style="float:left; margin:2px 5px 0 0;" class="ui-icon ui-icon-alert"></span>
+ <h1>title</h1>
+ <p>text</p>
+ </div>
+ </div>
+ <t t-js="d">
+ d.iter = 'one,two,three,four,five'.split(',')
+ </t>
+ <t t-foreach="iter" t-as="i">
+ <t t-call="benchmark_call">
+ + <t t-esc="i"/>
+ </t>
+ </t>
+ <t t-set="enplus">1</t>
+ <t t-set="novar">true</t>
+ <div t-attf-class="id_#{enplus}"/>
+ <div t-if="testing || true" t-att-class="novar || 'yes'" style="display: none">
+ <t t-set="novar"></t>
+ <t t-set="style">height: 200px; border: 1px solid red;</t>
+ <div t-att="{ 'style' : style, 'disabled' : 'false', 'readonly' : novar or undefined }" t-opentag="true"/>
+ <t t-foreach="{'my': 'first', 'my2': 'second' }" t-as="v">
+ * <t t-esc="v"/> : <t t-esc="v_value"/>
+ </t>
+ Ok this is good <t t-esc="name"/>!
+ <t t-set="myvar">Hi there !</t>
+ [<t t-raw="myvar"/>]
+ <t t-set="myvar2" t-value="'a,b,c,d,e'.split(',')"/>
+ <t t-foreach="myvar2" t-as="i">
+ (<t t-esc="i"/>)
+ </t>
+ </div>
+ <div id="oe_notification" class="oe_notification">
+ <div id="oe_notification_default">
+ <a class="ui-notify-cross ui-notify-close" href="#">x</a>
+ <h1>title</h1>
+ <p>text</p>
+ </div>
+ </div>
+</t>
+<t t-name="benchmark_call">
+ <div id="oe_notification_alert" class="ui-state-error">
+ <a class="ui-notify-cross ui-notify-close" href="#">x</a>
+ <span style="float:left; margin:2px 5px 0 0;" class="ui-icon ui-icon-alert"></span>
+ <h1>Here's your value : (<t t-esc="0"/>) !!</h1>
+ </div>
+</t>
+</templates>
+
diff --git a/addons/web/static/lib/qweb/qweb-test-attributes.xml b/addons/web/static/lib/qweb/qweb-test-attributes.xml
new file mode 100644
index 00000000000..91317d5194b
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-attributes.xml
@@ -0,0 +1,22 @@
+<templates>
+ <t t-name="fixed-literal">
+ <div t-att-foo="'bar'"/>
+ </t>
+ <t t-name="fixed-variable">
+ <div t-att-foo="value"/>
+ </t>
+
+ <t t-name="tuple-literal">
+ <div t-att="['foo', 'bar']"/>
+ </t>
+ <t t-name="tuple-variable">
+ <div t-att="att"/>
+ </t>
+
+ <t t-name="format-literal">
+ <div t-attf-foo="bar"/>
+ </t>
+ <t t-name="format-value">
+ <div t-attf-foo="b#{value}r"/>
+ </t>
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test-call.xml b/addons/web/static/lib/qweb/qweb-test-call.xml
new file mode 100644
index 00000000000..5d8f0019f7c
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-call.xml
@@ -0,0 +1,30 @@
+<templates>
+ <t t-name="basic-callee">ok</t>
+ <t t-name="callee-printsbody"><t t-esc="0"/></t>
+ <t t-name="callee-uses-foo"><t t-esc="foo"/></t>
+ <t t-name="callee-sets-foo"><t t-set="foo" t-value="'ok'"/></t>
+
+ <t t-name="basic-caller">
+ <t t-call="basic-callee"/>
+ </t>
+ <t t-name="with-unused-body">
+ <t t-call="basic-callee">WHEEE</t>
+ </t>
+ <t t-name="with-unused-setbody">
+ <t t-call="basic-callee">
+ <t t-set="qux" t-value="3"/>
+ </t>
+ </t>
+ <t t-name="with-used-body">
+ <t t-call="callee-printsbody">ok</t>
+ </t>
+ <t t-name="with-used-setbody">
+ <t t-call="callee-uses-foo">
+ <t t-set="foo" t-value="'ok'"/>
+ </t>
+ </t>
+ <t t-name="in-context-import">
+ <t t-call="callee-sets-foo" t-import='*'/>
+ <t t-esc="foo"/>
+ </t>
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test-conditionals.xml b/addons/web/static/lib/qweb/qweb-test-conditionals.xml
new file mode 100644
index 00000000000..43d16578bfc
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-conditionals.xml
@@ -0,0 +1,59 @@
+<templates>
+ <t t-name="literal-conditional">
+ <t t-if="true">ok</t>
+ </t>
+ <t t-name="boolean-value-conditional">
+ <t t-if="value">ok</t>
+ </t>
+ <t t-name="boolean-value-conditional-false">
+ <t t-if="value">fail</t>
+ </t>
+
+ <t t-name="negify">
+ <t t-if="!false">ok</t>
+ </t>
+ <t t-name="equality">
+ <t t-if="1 == 1">ok</t>
+ </t>
+ <t t-name="difference">
+ <t t-if="1 != 2">ok</t>
+ </t>
+ <t t-name="and">
+ <t t-if="true and true">ok</t>
+ </t>
+ <t t-name="and-js">
+ <t t-if="true &amp;&amp; true">ok</t>
+ </t>
+ <t t-name="or">
+ <t t-if="false or true">ok</t>
+ </t>
+ <t t-name="or-js">
+ <t t-if="false || true">ok</t>
+ </t>
+
+ <t t-name="greater">
+ <t t-if="2 gt 1">ok</t>
+ </t>
+ <t t-name="greater-js">
+ <t t-if="2 &gt; 1">ok</t>
+ </t>
+ <t t-name="lower">
+ <t t-if="1 lt 2">ok</t>
+ </t>
+ <t t-name="lower-js">
+ <t t-if="1 &lt; 2">ok</t>
+ </t>
+
+ <t t-name="greater-or-equal">
+ <t t-if="2 gte 1">o</t><t t-if="2 gte 2">k</t>
+ </t>
+ <t t-name="greater-or-equal-js">
+ <t t-if="2 &gt;= 1">o</t><t t-if="2 &gt;= 2">k</t>
+ </t>
+ <t t-name="lower-or-equal">
+ <t t-if="1 lte 2">o</t><t t-if="2 lte 2">k</t>
+ </t>
+ <t t-name="lower-or-equal-js">
+ <t t-if="1 &lt;= 2">o</t><t t-if="2 &lt;= 2">k</t>
+ </t>
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test-extend.xml b/addons/web/static/lib/qweb/qweb-test-extend.xml
new file mode 100644
index 00000000000..44fda920e43
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-extend.xml
@@ -0,0 +1,32 @@
+<templates>
+<t t-name="jquery-extend">
+ <ul><li>one</li></ul>
+</t>
+<t t-extend="jquery-extend">
+ <t t-jquery="ul" t-operation="append"><li>3</li></t>
+</t>
+<t t-extend="jquery-extend">
+ <t t-jquery="ul li:first-child" t-operation="replace"><li>2</li></t>
+</t>
+<t t-extend="jquery-extend">
+ <t t-jquery="ul" t-operation="prepend"><li>1</li></t>
+ <t t-jquery="ul" t-operation="before"><hr/></t>
+ <t t-jquery="ul" t-operation="after"><hr/></t>
+</t>
+<t t-extend="jquery-extend">
+ <t t-jquery="ul">
+ this.attr('class', 'main');
+ </t>
+</t>
+<t t-extend="jquery-extend">
+ <t t-jquery="hr:eq(1)" t-operation="replace"><footer></footer></t>
+</t>
+<t t-extend="jquery-extend">
+ <t t-jquery="footer" t-operation="inner"><b>END</b></t>
+</t>
+
+<t t-name="jquery-extend-clone" t-extend="jquery-extend">
+ <t t-jquery="ul" t-operation="append"><li>CLONED TEMPLATE</li></t>
+</t>
+
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test-foreach.xml b/addons/web/static/lib/qweb/qweb-test-foreach.xml
new file mode 100644
index 00000000000..80749882aaf
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-foreach.xml
@@ -0,0 +1,17 @@
+<templates>
+ <t t-name="repetition-text-content" t-foreach="seq">*</t>
+ <t t-name="repetition-dom-content" t-foreach="seq"><b/></t>
+ <b t-name="repetition-self" t-foreach="seq"/>
+
+ <t t-name="scope-self" t-foreach="seq" t-esc="seq"/>
+ <t t-name="scope-value" t-foreach="seq" t-esc="seq_value"/>
+ <t t-name="scope-index" t-foreach="seq" t-esc="seq_index"/>
+ <t t-name="scope-first" t-foreach="seq"><t t-esc="seq_first"/> </t>
+ <t t-name="scope-last" t-foreach="seq"><t t-esc="seq_last"/> </t>
+ <t t-name="scope-parity" t-foreach="seq"><t t-esc="seq_parity"/> </t>
+ <t t-name="scope-size" t-foreach="seq"><t t-esc="seq_size"/> </t>
+
+ <t t-name="aliasing" t-foreach="seq" t-as="item" t-esc="item"/>
+ <t t-name="loopvars-aliasing"
+ t-foreach="seq" t-as="item"><t t-esc="item_parity"/> </t>
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test-output.xml b/addons/web/static/lib/qweb/qweb-test-output.xml
new file mode 100644
index 00000000000..2660e519273
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-output.xml
@@ -0,0 +1,51 @@
+<templates>
+ <!-- esc, evaluates and returns @t-esc after having xml-escaped it -->
+ <t t-name="esc-literal">
+ <t t-esc="'ok'"/>
+ </t>
+ <t t-name="esc-variable">
+ <t t-esc="ok"/>
+ </t>
+ <t t-name="esc-toescape">
+ <t t-esc="ok"/>
+ </t>
+
+ <!-- escf, same as t-esc, but @t-escf is a format string -->
+ <t t-name="escf-noformat-literal">
+ <t t-escf="ok"/>
+ </t>
+ <t t-name="escf-simpleformat-variable">
+ <t t-escf="#{value}"/>
+ </t>
+ <t t-name="escf-format-variable">
+ <t t-escf="[#{value}]"/>
+ </t>
+ <t t-name="escf-format-variable-with-escapes">
+ <t t-escf="[#{value}]"/>
+ </t>
+
+ <!-- raw, evaluates and returns @t-raw directly (no escaping) -->
+ <t t-name="raw-literal">
+ <t t-raw="'ok'"/>
+ </t>
+ <t t-name="raw-variable">
+ <t t-raw="ok"/>
+ </t>
+ <t t-name="raw-notescaped">
+ <t t-raw="ok"/>
+ </t>
+
+ <!-- rawf, same as t-raw, but @t-rawf is a format string -->
+ <t t-name="rawf-noformat-literal">
+ <t t-escf="ok"/>
+ </t>
+ <t t-name="rawf-simpleformat-variable">
+ <t t-escf="#{value}"/>
+ </t>
+ <t t-name="rawf-format-variable">
+ <t t-escf="[#{value}]"/>
+ </t>
+ <t t-name="rawf-format-variable-notescaped">
+ <t t-rawf="[#{value}]"/>
+ </t>
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test-set.xml b/addons/web/static/lib/qweb/qweb-test-set.xml
new file mode 100644
index 00000000000..6a7b4f53d23
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test-set.xml
@@ -0,0 +1,15 @@
+<templates>
+ <t t-name="set-from-attribute-literal">
+ <t t-set="value" t-value="'ok'"/><t t-esc="value"/>
+ </t>
+ <t t-name="set-from-body-literal">
+ <t t-set="value">ok</t><t t-esc="value"/>
+ </t>
+
+ <t t-name="set-from-attribute-lookup">
+ <t t-set="stuff" t-value="value"/><t t-esc="stuff"/>
+ </t>
+ <t t-name="set-from-body-lookup">
+ <t t-set="stuff"><t t-esc="value"/></t><t t-esc="stuff"/>
+ </t>
+</templates>
diff --git a/addons/web/static/lib/qweb/qweb-test.js.html b/addons/web/static/lib/qweb/qweb-test.js.html
new file mode 100644
index 00000000000..fda837497c4
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb-test.js.html
@@ -0,0 +1,271 @@
+<!doctype html>
+<html>
+<head>
+ <script src="http://code.jquery.com/jquery-1.5.2.js"></script>
+ <link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen"/>
+ <script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
+
+ <script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
+ <script type="text/javascript" src="qweb2.js"></script>
+
+ <script>
+ QWeb = new QWeb2.Engine();
+ function trim(s) {
+ return s.replace(/(^\s+|\s+$)/g, '');
+ }
+ function render(template, context) {
+ return trim(QWeb.render(template, context));
+ }
+ $(document).ready(function() {
+ module("Basic output tests", {
+ setup: function () {
+ QWeb.add_template('qweb-test-output.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+
+ test("Basic escaped output", function () {
+ equals(render('esc-literal', {}), "ok", "Render a literal string");
+ equals(render('esc-variable', {ok: 'ok'}), "ok", "Render a string variable");
+ equals(render('esc-toescape', {ok: '<ok>'}), "&lt;ok&gt;", "Render a string with data to escape");
+ });
+ test("Formatted escaped output", function () {
+ equals(render('escf-noformat-literal', {}), "ok", "Render a literal string");
+ equals(render('escf-simpleformat-variable', {value: 'ok'}), "ok",
+ "Only render an interpolated variable");
+ equals(render('escf-format-variable', {value: 'ok'}), "[ok]",
+ "Actually formatted variable");
+ equals(render('escf-format-variable-with-escapes', {value: '<ok>'}), '[&lt;ok&gt;]',
+ "Render a formatted string with data to escape");
+ });
+ test("Basic unescaped output", function () {
+ equals(render('raw-literal', {}), "ok", "Render a literal string");
+ equals(render('raw-variable', {ok: 'ok'}), "ok", "Render a string variable");
+ equals(render('raw-notescaped', {ok: '<ok>'}), "<ok>", "Render a string with data not escaped");
+ });
+ test("Formatted unescaped output", function () {
+ equals(render('rawf-noformat-literal', {}), "ok", "Render a literal string");
+ equals(render('rawf-simpleformat-variable', {value: 'ok'}), "ok",
+ "Only render an interpolated variable");
+ equals(render('rawf-format-variable', {value: 'ok'}), "[ok]",
+ "Actually formatted variable");
+ equals(render('rawf-format-variable-notescaped', {value: '<ok>'}), '[<ok>]',
+ "Render a formatted string with data not escaped");
+ });
+
+ module("Context-setting tests", {
+ setup: function () {
+ QWeb.add_template('qweb-test-set.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+ test("Set literal value", function () {
+ equals(render('set-from-attribute-literal', {}), "ok",
+ "Set a literal value via @t-value");
+ equals(render('set-from-body-literal', {}), "ok",
+ "Set a literal value via @t-set body");
+ });
+ test("Set value looked up from context", function () {
+ equals(render('set-from-attribute-lookup', {value: 'ok'}), "ok",
+ "Set a value looked up in context via @t-value");
+ equals(render('set-from-body-lookup', {value: 'ok'}), 'ok',
+ "Set a value looked up in context via @t-set body and @t-esc");
+ });
+
+ module("Conditionals", {
+ setup: function () {
+ QWeb.add_template('qweb-test-conditionals.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+ test('Basic (single boolean) conditionals', function () {
+ equals(render('literal-conditional', {}), 'ok',
+ "Test on a literal value");
+ equals(render('boolean-value-conditional', {value: true}), 'ok',
+ "Test on a truthy variable value");
+ equals(render('boolean-value-conditional-false', {value: false}), '',
+ "Test on a falsy variable value");
+ });
+ test('Boolean expressions in conditionals', function () {
+ equals(render('negify', {}), 'ok',
+ "Negative");
+ equals(render('equality', {}), 'ok',
+ "Equality");
+ equals(render('difference', {}), 'ok',
+ "Difference");
+ equals(render('and', {}), 'ok',
+ "Boolean and");
+ equals(render('and-js', {}), 'ok',
+ "Boolean and via manually escaped JS operator");
+ equals(render('or', {}), 'ok',
+ "Boolean or");
+ equals(render('or-js', {}), 'ok',
+ "Boolean or using JS operator");
+ });
+ test('Comparison boolean tests in conditionals', function () {
+ equals(render('greater', {}), 'ok',
+ "Greater");
+ equals(render('greater-js', {}), 'ok',
+ "Greater, JS operator");
+ equals(render('lower', {}), 'ok',
+ "Lower");
+ equals(render('lower-js', {}), 'ok',
+ "Lower, JS operator");
+ equals(render('greater-or-equal', {}), 'ok',
+ "Greater or Equal");
+ equals(render('greater-or-equal-js', {}), 'ok',
+ "Greater or Equal, JS operator");
+ equals(render('lower-or-equal', {}), 'ok',
+ "Lower or Equal");
+ equals(render('lower-or-equal-js', {}), 'ok',
+ "Lower or Equal, JS operator");
+ });
+
+ module("Attributes manipulation", {
+ setup: function () {
+ QWeb.add_template('qweb-test-attributes.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+ test('Fixed-name attributes', function () {
+ equals(render('fixed-literal', {}), '<div foo="bar"/>',
+ "Fixed name and literal attribute value");
+ equals(render('fixed-variable', {value: 'ok'}), '<div foo="ok"/>',
+ "Fixed name and variable attribute value");
+ });
+ test('Tuple-based attributes', function () {
+ equals(render('tuple-literal', {}), '<div foo="bar"/>',
+ "Tuple-based literal attributes");
+ equals(render('tuple-variable', {att: ['foo', 'bar']}), '<div foo="bar"/>',
+ "Tuple-based variable attributes");
+ });
+ test('Fixed name, formatted value attributes', function () {
+ equals(render('format-literal', {}), '<div foo="bar"/>',
+ "Literal format");
+ equals(render('format-value', {value:'a'}), '<div foo="bar"/>',
+ "Valued format");
+ });
+
+ module("Template calling (including)", {
+ setup: function () {
+ QWeb.add_template('qweb-test-call.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+ test('Trivial call invocation', function () {
+ equals(render('basic-caller', {}), 'ok',
+ "Direct call of a second template");
+ });
+ test('Call invocation with body', function () {
+ equals(render('with-unused-body', {}), 'ok',
+ "Call of a second template with body unused");
+ equals(render('with-unused-setbody', {}), 'ok',
+ "Call of a second template with body directives unused");
+ });
+ test('Call invocation with body (used by callee)', function () {
+ equals(render('with-used-body', {}), 'ok',
+ "Call of a second template with body used");
+ });
+ test('Call invocation with parameters set (in body)', function () {
+ equals(render('with-used-setbody', {}), 'ok',
+ "Call of a second template with parameters");
+ });
+ test('Call invocation in-context (via import)', function () {
+ equals(render('in-context-import', {}), 'ok',
+ "Call with t-import (calls in current context)");
+ });
+
+ module("Foreach", {
+ setup: function () {
+ QWeb.add_template('qweb-test-foreach.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+ var seq = [4,3,2,1,0];
+ test('Basic foreach repetition', function () {
+ equals(QWeb.render('repetition-text-content', {seq:seq}), '*****',
+ "Repetition of text content via foreach");
+ equals(QWeb.render('repetition-dom-content', {seq:seq}), '<b/><b/><b/><b/><b/>',
+ "Repetition of node content via foreach");
+ equals(QWeb.render('repetition-self', {seq:seq}), '<b/><b/><b/><b/><b/>',
+ "A node with a foreach repeats itself");
+ });
+ test("Foreach scope content", function () {
+ equals(QWeb.render('scope-self', {seq:seq}), '43210',
+ "each value of the sequence is available via the sequence name");
+ equals(QWeb.render('scope-value', {seq:seq}), '43210',
+ "each value of the sequence is also via the _value");
+ equals(QWeb.render('scope-index', {seq:seq}), '01234',
+ "the current 0-based index is available via _index");
+ equals(QWeb.render('scope-first', {seq:seq}), 'true false false false false ',
+ "_first says whether the current item is the first of the sequence");
+ equals(QWeb.render('scope-last', {seq:seq}), 'false false false false true ',
+ "_last says whether the current item is the last of the sequence");
+ equals(QWeb.render('scope-parity', {seq:seq}), 'even odd even odd even ',
+ "the parity (odd/even) of the current row is available via _parity");
+ equals(QWeb.render('scope-size', {seq:seq}), '5 5 5 5 5 ',
+ "the total length of the sequence is available through _size");
+ });
+ test('Name aliasing via t-as', function () {
+ equals(QWeb.render('aliasing', {seq:seq}), '43210',
+ "the inner value can be re-bound via t-as");
+ equals(QWeb.render('loopvars-aliasing', {seq:seq}), 'even odd even odd even ',
+ "inner loop variables should be rebound as well");
+ });
+
+ module("Template inheritance tests", {
+ setup: function () {
+ QWeb.add_template('qweb-test-extend.xml');
+ },
+ teardown: function () {
+ QWeb.templates = [];
+ QWeb.tag = {};
+ QWeb.att = {};
+ }
+ });
+
+ test("jQuery extend", function () {
+ equals(render('jquery-extend', {}), '<hr/><ul class="main"><li>1</li><li>2</li><li>3</li></ul><footer><b>END</b></footer>',
+ "Extend template with jQuery");
+ equals(render('jquery-extend-clone', {}), '<ul><li>one</li><li>CLONED TEMPLATE</li></ul>',
+ "Clone template");
+ });
+ });
+ </script>
+
+</head>
+<body>
+<h1 id="qunit-header">QWeb test suite</h1>
+
+<h2 id="qunit-banner"></h2>
+
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">test markup, will be hidden</div>
+</body>
+</html>
diff --git a/addons/web/static/lib/qweb/qweb.js b/addons/web/static/lib/qweb/qweb.js
new file mode 100644
index 00000000000..46728f1dcf7
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb.js
@@ -0,0 +1,413 @@
+// vim:set et fdm=syntax fdl=0 fdc=3 fdn=2:
+//---------------------------------------------------------
+// QWeb javascript
+//---------------------------------------------------------
+
+/*
+ TODO
+
+ String parsing
+ if (window.DOMParser) {
+ parser=new DOMParser();
+ xmlDoc=parser.parseFromString(text,"text/xml");
+ } else {
+ xmlDoc=new ActiveXObject("Msxml2.DOMDocument.4.0");
+ xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
+ Which versions to try, it's confusing...
+ xmlDoc.async="false";
+ xmlDoc.async=false;
+ xmlDoc.preserveWhiteSpace=true;
+ xmlDoc.load("f.xml");
+ xmlDoc.loadXML(text); ?
+ }
+
+ Support space in IE by reparsing the responseText
+ xmlhttp.responseXML.loadXML(xmlhttp.responseText); ?
+
+ Preprocess: (nice optimization)
+ preprocess by flattening all non t- element to a TEXT_NODE.
+ count the number of "\n" in text nodes to give an aproximate LINE NUMBER on elements for error reporting
+ if from IE HTMLDOM use if(a[i].specified) to avoid 88 empty attributes per element during the preprocess,
+
+ implement t-trim 'left' 'right' 'both', is it needed ? inner=render_trim(l_inner.join(), t_att)
+
+ Ruby/python: to backport from javascript to python/ruby render_node to use regexp, factorize foreach %var, t-att test for tuple(attname,value)
+
+ DONE
+ we reintroduced t-att-id, no more t-esc-id because of the new convention t-att="["id","val"]"
+*/
+
+var QWeb = {
+ templates:{},
+ prefix:"t",
+ reg:new RegExp(),
+ tag:{},
+ att:{},
+ ValueException: function (value, message) {
+ this.value = value;
+ this.message = message;
+ },
+ eval_object:function(e, v) {
+ // TODO: Currently this will also replace and, or, ... in strings. Try
+ // 'hi boys and girls' != '' and 1 == 1 -- will be replaced to : 'hi boys && girls' != '' && 1 == 1
+ // try to find a solution without tokenizing
+ e = '(' + e + ')';
+ e = e.replace(/\band\b/g, " && ");
+ e = e.replace(/\bor\b/g, " || ");
+ e = e.replace(/\bgt\b/g, " > ");
+ e = e.replace(/\bgte\b/g, " >= ");
+ e = e.replace(/\blt\b/g, " < ");
+ e = e.replace(/\blte\b/g, " <= ");
+ if (v[e] != undefined) {
+ return v[e];
+ } else {
+ with (v) return eval(e);
+ }
+ },
+ eval_str:function(e, v) {
+ var r = this.eval_object(e, v);
+ r = (typeof(r) == "undefined" || r == null) ? "" : r.toString();
+ return e == "0" ? v["0"] : r;
+ },
+ eval_format:function(e, v) {
+ var m, src = e.split(/#/), r = src[0];
+ for (var i = 1; i < src.length; i++) {
+ if (m = src[i].match(/^{(.*)}(.*)/)) {
+ r += this.eval_str(m[1], v) + m[2];
+ } else {
+ r += "#" + src[i];
+ }
+ }
+ return r;
+ },
+ eval_bool:function(e, v) {
+ return !!this.eval_object(e, v);
+ },
+ trim : function(v, mode) {
+ if (!v || !mode) return v;
+ switch (mode) {
+ case 'both':
+ return v.replace(/^\s*|\s*$/g, "");
+ case "left":
+ return v.replace(/^\s*/, "");
+ case "right":
+ return v.replace(/\s*$/, "");
+ }
+ throw new QWeb.ValueException(
+ mode, "unknown trimming mode, trim mode must follow the pattern '[inner] (left|right|both)'");
+ },
+ escape_text:function(s) {
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+ },
+ escape_att:function(s) {
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
+ },
+ render_node : function(e, v, inner_trim) {
+ if (e.nodeType == 3) {
+ return inner_trim ? this.trim(e.data, inner_trim) : e.data;
+ }
+ if (e.nodeType == 1) {
+ var g_att = {};
+ var t_att = {};
+ var t_render = null;
+ var a = e.attributes;
+ for (var i = 0; i < a.length; i++) {
+ var an = a[i].name,av = a[i].value;
+ var m;
+ if (m = an.match(this.reg)) {
+ var n = m[1];
+ if (n == "eval") {
+ n = m[2].substring(1);
+ av = this.eval_str(av, v);
+ }
+ var f;
+ if (f = this.att[n]) {
+ this[f](e, t_att, g_att, v, m[2], av);
+ } else if (f = this.tag[n]) {
+ t_render = f;
+ }
+ t_att[n] = av;
+ } else {
+ g_att[an] = av;
+ }
+ }
+ if (inner_trim && !t_att["trim"]) {
+ t_att["trim"] = "inner " + inner_trim;
+ }
+ if (t_render) {
+ return this[t_render](e, t_att, g_att, v);
+ }
+ return this.render_element(e, t_att, g_att, v);
+ }
+ return "";
+ },
+ render_element:function(e, t_att, g_att, v) {
+ var inner = "", ec = e.childNodes, trim = t_att["trim"], inner_trim;
+ if (trim) {
+ if (/\binner\b/.test(trim)) {
+ inner_trim = true;
+ if (trim == 'inner') {
+ trim = "both";
+ }
+ }
+ var tm = /\b(both|left|right)\b/.exec(trim);
+ if (tm) trim = tm[1];
+ }
+ for (var i = 0; i < ec.length; i++) {
+ inner += inner_trim ? this.trim(this.render_node(ec[i], v, inner_trim ? trim : null), trim) : this.render_node(ec[i], v, inner_trim ? trim : null);
+ }
+ if (trim && !inner_trim) {
+ inner = this.trim(inner, trim);
+ }
+ if (e.tagName == this.prefix) {
+ return inner;
+ }
+ var att = "";
+ for (var an in g_att) {
+ att += " " + an + '="' + this.escape_att(g_att[an]) + '"';
+ }
+ // Some IE versions have problems with closed tags
+ var opentag = !!t_att['opentag'] && this.eval_bool(t_att["opentag"], v);
+ return inner.length || opentag ? "<" + e.tagName + att + ">" + inner + "</" + e.tagName + ">" : "<" + e.tagName + att + "/>";
+ },
+ render_att_att:function(e, t_att, g_att, v, ext, av) {
+ if (ext) {
+ var attv = this.eval_object(av, v);
+ if (attv != null) {
+ g_att[ext.substring(1)] = attv.toString();
+ }
+ } else {
+ var o = this.eval_object(av, v);
+ if (o != null) {
+ // TODO: http://bonsaiden.github.com/JavaScript-Garden/#types.typeof
+ if (o.constructor == Array && o.length > 1 && o[1] != null) {
+ g_att[o[0]] = new String(o[1]);
+ } else if (o.constructor == Object) {
+ for (var i in o) {
+ if(o[i]!=null) {
+ g_att[i] = new String(o[i]);
+ }
+ }
+ }
+ }
+ }
+ },
+ render_att_attf:function(e, t_att, g_att, v, ext, av) {
+ g_att[ext.substring(1)] = this.eval_format(av, v);
+ },
+ render_tag_raw:function(e, t_att, g_att, v) {
+ return this.eval_str(t_att["raw"], v);
+ },
+ render_tag_rawf:function(e, t_att, g_att, v) {
+ return this.eval_format(t_att["rawf"], v);
+ },
+ /*
+ * Idea: if the name of the tag != t render the tag around the value <a name="a" t-esc="label"/>
+ */
+ render_tag_esc:function(e, t_att, g_att, v) {
+ return this.escape_text(this.eval_str(t_att["esc"], v));
+ },
+ render_tag_escf:function(e, t_att, g_att, v) {
+ return this.escape_text(this.eval_format(t_att["escf"], v));
+ },
+ render_tag_if:function(e, t_att, g_att, v) {
+ return this.eval_bool(t_att["if"], v) ? this.render_element(e, t_att, g_att, v) : "";
+ },
+ render_tag_set:function(e, t_att, g_att, v) {
+ var ev = t_att["value"];
+ if (ev && ev.constructor != Function) {
+ v[t_att["set"]] = this.eval_object(ev, v);
+ } else {
+ v[t_att["set"]] = this.render_element(e, t_att, g_att, v);
+ }
+ return "";
+ },
+ render_tag_call:function(e, t_att, g_att, v) {
+ var d = v;
+ if (!t_att["import"]) {
+ d = {};
+ for (var i in v) {
+ d[i] = v[i];
+ }
+ }
+ d["0"] = this.render_element(e, t_att, g_att, d);
+ return this.render(t_att["call"], d);
+ },
+ render_tag_js:function(e, t_att, g_att, v) {
+ var dict_name = t_att["js"] || "dict";
+ v[dict_name] = v;
+ var r = this.eval_str(this.render_element(e, t_att, g_att, v), v);
+ delete(v[dict_name]);
+ return r || '';
+ },
+ /**
+ * Renders a foreach loop (@t-foreach).
+ *
+ * Adds the following elements to its context, where <code>${name}</code>
+ * is specified via <code>@t-as</code>:
+ * * <code>${name}</code> The current element itself
+ * * <code>${name}_value</code> Same as <code>${name}</code>
+ * * <code>${name}_index</code> The 0-based index of the current element
+ * * <code>${name}_first</code> Whether the current element is the first one
+ * * <code>${name}_parity</code> odd|even (as strings)
+ * * <code>${name}_all</code> The iterated collection itself
+ *
+ * If the collection being iterated is an array, also adds:
+ * * <code>${name}_last</code> Whether the current element is the last one
+ * * All members of the current object
+ *
+ * If the collection being iterated is an object, the value is actually the object's key
+ *
+ * @param e ?
+ * @param t_att attributes of the element being <code>t-foreach</code>'d
+ * @param g_att ?
+ * @param old_context the context in which the foreach is evaluated
+ */
+ render_tag_foreach:function(e, t_att, g_att, old_context) {
+ var expr = t_att["foreach"];
+ var enu = this.eval_object(expr, old_context);
+ var ru = [];
+ if (enu) {
+ var val = t_att['as'] || expr.replace(/[^a-zA-Z0-9]/g, '_');
+ var context = {};
+ for (var i in old_context) {
+ context[i] = old_context[i];
+ }
+ context[val + "_all"] = enu;
+ var val_value = val + "_value",
+ val_index = val + "_index",
+ val_first = val + "_first",
+ val_last = val + "_last",
+ val_parity = val + "_parity";
+ var size = enu.length;
+ if (size) {
+ context[val + "_size"] = size;
+ for (var j = 0; j < size; j++) {
+ var cur = enu[j];
+ context[val_value] = cur;
+ context[val_index] = j;
+ context[val_first] = j == 0;
+ context[val_last] = j + 1 == size;
+ context[val_parity] = (j % 2 == 1 ? 'odd' : 'even');
+ if (cur.constructor == Object) {
+ for (var k in cur) {
+ context[k] = cur[k];
+ }
+ }
+ context[val] = cur;
+ var r = this.render_element(e, t_att, g_att, context);
+ ru.push(r);
+ }
+ } else {
+ var index = 0;
+ for (cur in enu) {
+ context[val_value] = cur;
+ context[val_index] = index;
+ context[val_first] = index == 0;
+ context[val_parity] = (index % 2 == 1 ? 'odd' : 'even');
+ context[val] = cur;
+ ru.push(this.render_element(e, t_att, g_att, context));
+ index += 1;
+ }
+ }
+ return ru.join("");
+ } else {
+ return "qweb: foreach " + expr + " not found.";
+ }
+ },
+ hash:function() {
+ var l = [], m;
+ for (var i in this) {
+ if (m = i.match(/render_tag_(.*)/)) {
+ this.tag[m[1]] = i;
+ l.push(m[1]);
+ } else if (m = i.match(/render_att_(.*)/)) {
+ this.att[m[1]] = i;
+ l.push(m[1]);
+ }
+ }
+ l.sort(function(a, b) {
+ return a.length > b.length ? -1 : 1;
+ });
+ var s = "^" + this.prefix + "-(eval|" + l.join("|") + "|.*)(.*)$";
+ this.reg = new RegExp(s);
+ },
+ /**
+ * returns the correct XMLHttpRequest instance for the browser, or null if
+ * it was not able to build any XHR instance.
+ *
+ * @returns XMLHttpRequest|MSXML2.XMLHTTP.3.0|null
+ */
+ get_xhr:function () {
+ if (window.XMLHttpRequest) {
+ return new window.XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject('MSXML2.XMLHTTP.3.0');
+ } catch(e) {
+ return null;
+ }
+ },
+ load_xml:function(s) {
+ var xml;
+ if (s[0] == "<") {
+ /*
+ manque ca pour sarrisa
+ if(window.DOMParser){
+ mozilla
+ if(!window.DOMParser){
+ var doc = Sarissa.getDomDocument();
+ doc.loadXML(sXml);
+ return doc;
+ };
+ };
+ */
+ } else {
+ var req = this.get_xhr();
+ if (req) {
+ req.open("GET", s, false);
+ req.send(null);
+ //if ie r.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
+ xml = req.responseXML;
+ /*
+ TODO
+ if intsernetexploror
+ getdomimplmentation() for try catch
+ responseXML.getImplet
+ d=domimple()
+ d.preserverWhitespace=1
+ d.loadXML()
+
+ xml.preserverWhitespace=1
+ xml.loadXML(r.reponseText)
+ */
+ return xml;
+ }
+ }
+ },
+ add_template:function(e) {
+ // TODO: keep sources so we can implement reload()
+ this.hash();
+ if (e.constructor == String) {
+ e = this.load_xml(e);
+ }
+
+ var ec = e.documentElement ? e.documentElement.childNodes : ( e.childNodes ? e.childNodes : [] );
+
+ for (var i = 0; i < ec.length; i++) {
+ var n = ec[i];
+ if (n.nodeType == 1) {
+ var name = n.getAttribute(this.prefix + "-name");
+ this.templates[name] = n;
+ }
+ }
+ },
+ render:function(name, v) {
+ var e;
+ if (e = this.templates[name]) {
+ return this.render_node(e, v);
+ }
+ return "template " + name + " not found";
+ }
+};
+
diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js
new file mode 100644
index 00000000000..621ea39c74f
--- /dev/null
+++ b/addons/web/static/lib/qweb/qweb2.js
@@ -0,0 +1,712 @@
+// TODO: trim support
+// TODO: line number -> https://bugzilla.mozilla.org/show_bug.cgi?id=618650
+// TODO: templates orverwritten could be called by t-call="__super__" ?
+// TODO: t-set + t-value + children node == scoped variable ?
+var QWeb2 = {
+ expressions_cache: {},
+ RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
+ ACTIONS_PRECEDENCE: 'foreach,if,call,set,esc,escf,raw,rawf,js,debug,log'.split(','),
+ WORD_REPLACEMENT: {
+ 'and': '&&',
+ 'or': '||',
+ 'gt': '>',
+ 'gte': '>=',
+ 'lt': '<',
+ 'lte': '<='
+ },
+ tools: {
+ exception: function(message, context) {
+ context = context || {};
+ var prefix = 'QWeb2';
+ if (context.template) {
+ prefix += " - template['" + context.template + "']";
+ }
+ throw new Error(prefix + ": " + message);
+ },
+ warning : function(message) {
+ if (typeof(window) !== 'undefined' && window.console) {
+ window.console.warn(message);
+ }
+ },
+ trim: function(s, mode) {
+ switch (mode) {
+ case "left":
+ return s.replace(/^\s*/, "");
+ case "right":
+ return s.replace(/\s*$/, "");
+ default:
+ return s.replace(/^\s*|\s*$/g, "");
+ }
+ },
+ js_escape: function(s, noquotes) {
+ return (noquotes ? '' : "'") + s.replace(/\r?\n/g, "\\n").replace(/'/g, "\\'") + (noquotes ? '' : "'");
+ },
+ html_escape: function(s, attribute) {
+ if (s == null) {
+ return '';
+ }
+ s = String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ if (attribute) {
+ s = s.replace(/"/g, '&quot;');
+ }
+ return s;
+ },
+ gen_attribute: function(o) {
+ if (o !== null && o !== undefined) {
+ if (o.constructor === Array) {
+ if (o[1] !== null && o[1] !== undefined) {
+ return ' ' + o[0] + '="' + this.html_escape(o[1], true) + '"';
+ }
+ } else if (typeof o === 'object') {
+ var r = '';
+ for (var k in o) {
+ if (o.hasOwnProperty(k)) {
+ r += this.gen_attribute([k, o[k]]);
+ }
+ }
+ return r;
+ }
+ }
+ return '';
+ },
+ extend: function(dst, src, exclude) {
+ for (var p in src) {
+ if (src.hasOwnProperty(p) && !(exclude && this.arrayIndexOf(exclude, p) !== -1)) {
+ dst[p] = src[p];
+ }
+ }
+ return dst;
+ },
+ arrayIndexOf : function(array, item) {
+ for (var i = 0, ilen = array.length; i < ilen; i++) {
+ if (array[i] === item) {
+ return i;
+ }
+ }
+ return -1;
+ },
+ xml_node_to_string : function(node, childs_only) {
+ if (childs_only) {
+ var childs = node.childNodes, r = [];
+ for (var i = 0, ilen = childs.length; i < ilen; i++) {
+ r.push(this.xml_node_to_string(childs[i]));
+ }
+ return r.join('');
+ } else {
+ if (node.xml !== undefined) {
+ return node.xml;
+ } else {
+ return (new XMLSerializer()).serializeToString(node);
+ }
+ }
+ },
+ xpath_selectNodes : function(node, expr) {
+ if (node.selectNodes !== undefined) {
+ return node.selectNodes(expr);
+ } else {
+ var xpath = new XPathEvaluator();
+ try {
+ var result = xpath.evaluate(expr, node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
+ } catch(error) {
+ this.exception("Error with XPath expression '" + expr + "' : " + error);
+ }
+ var r = [];
+ if (result != null) {
+ var element;
+ while (element = result.iterateNext()) {
+ r.push(element);
+ }
+ }
+ return r
+ }
+ },
+ call: function(context, template, old_dict, _import, callback) {
+ var new_dict = this.extend({}, old_dict);
+ new_dict['__caller__'] = old_dict['__template__'];
+ if (callback) {
+ new_dict['__content__'] = callback(context, new_dict);
+ }
+ var r = context.engine._render(template, new_dict);
+ if (_import) {
+ if (_import === '*') {
+ this.extend(old_dict, new_dict, ['__caller__', '__template__']);
+ } else {
+ _import = _import.split(',');
+ for (var i = 0, ilen = _import.length; i < ilen; i++) {
+ var v = _import[i];
+ old_dict[v] = new_dict[v];
+ }
+ }
+ }
+ return r;
+ },
+ foreach: function(context, enu, as, old_dict, callback) {
+ if (enu != null) {
+ var size, new_dict = this.extend({}, old_dict);
+ new_dict[as + "_all"] = enu;
+ var as_value = as + "_value",
+ as_index = as + "_index",
+ as_first = as + "_first",
+ as_last = as + "_last",
+ as_parity = as + "_parity";
+ if (size = enu.length) {
+ new_dict[as + "_size"] = size;
+ for (var j = 0, jlen = enu.length; j < jlen; j++) {
+ var cur = enu[j];
+ new_dict[as_value] = cur;
+ new_dict[as_index] = j;
+ new_dict[as_first] = j === 0;
+ new_dict[as_last] = j + 1 === size;
+ new_dict[as_parity] = (j % 2 == 1 ? 'odd' : 'even');
+ if (cur.constructor === Object) {
+ this.extend(new_dict, cur);
+ }
+ new_dict[as] = cur;
+ callback(context, new_dict);
+ }
+ } else if (enu.constructor == Number) {
+ var _enu = [];
+ for (var i = 0; i < enu; i++) {
+ _enu.push(i);
+ }
+ this.foreach(context, _enu, as, old_dict, callback);
+ } else {
+ var index = 0;
+ for (var k in enu) {
+ if (enu.hasOwnProperty(k)) {
+ var v = enu[k];
+ new_dict[as_value] = v;
+ new_dict[as_index] = index;
+ new_dict[as_first] = index === 0;
+ new_dict[as_parity] = (j % 2 == 1 ? 'odd' : 'even');
+ new_dict[as] = k;
+ callback(context, new_dict);
+ index += 1;
+ }
+ }
+ }
+ } else {
+ this.exception("No enumerator given to foreach", context);
+ }
+ }
+ }
+};
+
+QWeb2.Engine = (function() {
+ function Engine() {
+ // TODO: handle prefix at template level : t-prefix="x"
+ this.prefix = 't';
+ this.debug = false;
+ this.templates_resources = []; // TODO: implement this.reload()
+ this.templates = {};
+ this.compiled_templates = {};
+ this.extend_templates = {};
+ this.default_dict = {};
+ this.tools = QWeb2.tools;
+ this.jQuery = window.jQuery;
+ this.reserved_words = QWeb2.RESERVED_WORDS.slice(0);
+ this.actions_precedence = QWeb2.ACTIONS_PRECEDENCE.slice(0);
+ this.word_replacement = QWeb2.tools.extend({}, QWeb2.WORD_REPLACEMENT);
+ for (var i = 0; i < arguments.length; i++) {
+ this.add_template(arguments[i]);
+ }
+ }
+
+ QWeb2.tools.extend(Engine.prototype, {
+ add_template : function(template) {
+ this.templates_resources.push(template);
+ if (template.constructor === String) {
+ template = this.load_xml(template);
+ }
+ var ec = (template.documentElement && template.documentElement.childNodes) || template.childNodes || [];
+ for (var i = 0; i < ec.length; i++) {
+ var node = ec[i];
+ if (node.nodeType === 1) {
+ if (node.nodeName == 'parsererror') {
+ return this.tools.exception(node.innerText);
+ }
+ var name = node.getAttribute(this.prefix + '-name');
+ var extend = node.getAttribute(this.prefix + '-extend');
+ if (name && extend) {
+ // Clone template and extend it
+ if (!this.templates[extend]) {
+ return this.tools.exception("Can't clone undefined template " + extend);
+ }
+ this.templates[name] = this.templates[extend].cloneNode(true);
+ extend = name;
+ name = undefined;
+ }
+ if (name) {
+ this.templates[name] = node;
+ } else if (extend) {
+ delete(this.compiled_templates[extend]);
+ if (this.extend_templates[extend]) {
+ this.extend_templates[extend].push(node);
+ } else {
+ this.extend_templates[extend] = [node];
+ }
+ }
+ }
+ }
+ return true;
+ },
+ load_xml : function(s) {
+ s = s.replace(/^\s*|\s*$/g, '');
+ if (this.tools.trim(s)[0] === '<') {
+ return this.load_xml_string(s);
+ } else {
+ var req = this.get_xhr();
+ if (req) {
+ // TODO: third parameter is async : https://developer.mozilla.org/en/XMLHttpRequest#open()
+ // do an on_ready in QWeb2{} that could be passed to add_template
+ if (this.debug) {
+ s += '?debug=' + (new Date()).getTime(); // TODO fme: do it properly in case there's already url parameters
+ }
+ req.open('GET', s, false);
+ req.send(null);
+ if (req.responseXML) {
+ if (req.responseXML.documentElement.nodeName == "parsererror") {
+ return this.tools.exception(req.responseXML.documentElement.childNodes[0].nodeValue);
+ }
+ return req.responseXML;
+ } else {
+ return this.load_xml_string(req.responseText);
+ }
+ }
+ }
+ },
+ load_xml_string : function(s) {
+ if (window.DOMParser) {
+ var dp = new DOMParser();
+ var r = dp.parseFromString(s, "text/xml");
+ if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') {
+ return this.tools.exception(r.body.innerText);
+ }
+ return r;
+ }
+ var xDoc;
+ try {
+ // new ActiveXObject("Msxml2.DOMDocument.4.0");
+ xDoc = new ActiveXObject("MSXML2.DOMDocument");
+ } catch (e) {
+ return this.tools.exception("Could not find a DOM Parser");
+ }
+ xDoc.async = false;
+ xDoc.preserveWhiteSpace = true;
+ xDoc.loadXML(s);
+ return xDoc;
+ },
+ has_template : function(template) {
+ return !!this.templates[template];
+ },
+ get_xhr : function() {
+ if (window.XMLHttpRequest) {
+ return new window.XMLHttpRequest();
+ }
+ try {
+ return new ActiveXObject('MSXML2.XMLHTTP.3.0');
+ } catch (e) {
+ return null;
+ }
+ },
+ compile : function(node) {
+ var e = new QWeb2.Element(this, node);
+ var template = node.getAttribute(this.prefix + '-name');
+ return " /* 'this' refers to Qweb2.Engine instance */\n" +
+ " var context = { engine : this, template : " + (this.tools.js_escape(template)) + " };\n" +
+ " dict = dict || {};\n" +
+ " dict['__template__'] = '" + template + "';\n" +
+ " var r = [];\n" +
+ " /* START TEMPLATE */ try {\n" +
+ (e.compile()) + "\n" +
+ " /* END OF TEMPLATE */ } catch(error) {\n" +
+ " if (console && console.exception) console.exception(error);\n" +
+ " context.engine.tools.exception('Runtime Error: ' + error, context);\n" +
+ " }\n" +
+ " return r.join('');";
+ },
+ render : function(template, dict) {
+ var ndict = QWeb2.tools.extend({}, this.default_dict);
+ QWeb2.tools.extend(ndict, dict);
+ /*if (this.debug && window['console'] !== undefined) {
+ console.time("QWeb render template " + template);
+ }*/
+ var r = this._render(template, ndict);
+ /*if (this.debug && window['console'] !== undefined) {
+ console.timeEnd("QWeb render template " + template);
+ }*/
+ return r;
+ },
+ _render : function(template, dict) {
+ if (this.compiled_templates[template]) {
+ return this.compiled_templates[template].apply(this, [dict || {}]);
+ } else if (this.templates[template]) {
+ var ext;
+ if (ext = this.extend_templates[template]) {
+ var extend_node;
+ while (extend_node = ext.shift()) {
+ this.extend(template, extend_node);
+ }
+ }
+ var code = this.compile(this.templates[template]), tcompiled;
+ try {
+ tcompiled = new Function(['dict'], code);
+ } catch (error) {
+ if (this.debug && window.console) {
+ console.log(code);
+ }
+ this.tools.exception("Error evaluating template: " + error, { template: name });
+ }
+ if (!tcompiled) {
+ this.tools.exception("Error evaluating template: (IE?)" + error, { template: name });
+ }
+ this.compiled_templates[template] = tcompiled;
+ return this.render(template, dict);
+ } else {
+ return this.tools.exception("Template '" + template + "' not found");
+ }
+ },
+ extend : function(template, extend_node) {
+ if (!this.jQuery) {
+ return this.tools.exception("Can't extend template " + template + " without jQuery");
+ }
+ for (var i = 0, ilen = extend_node.childNodes.length; i < ilen; i++) {
+ var child = extend_node.childNodes[i];
+ if (child.nodeType === 1) {
+ var xpath = child.getAttribute(this.prefix + '-xpath'),
+ jquery = child.getAttribute(this.prefix + '-jquery'),
+ operation = child.getAttribute(this.prefix + '-operation'),
+ target,
+ error_msg = "Error while extending template '" + template;
+ if (jquery) {
+ target = this.jQuery(jquery, this.templates[template]);
+ } else if (xpath) {
+ // NOTE: due to the XPath implementation, extending a template will only work once
+ // when using XPath because XPathResult won't match objects with other constructor than 'Element'
+ // As jQuery will create HTMLElements, xpath will ignore them then causing problems when a
+ // template has already been extended. XPath selectors will probably be removed in QWeb.
+ target = this.jQuery(this.tools.xpath_selectNodes(this.templates[template], xpath));
+ } else {
+ this.tools.exception(error_msg + "No expression given");
+ }
+ error_msg += "' (expression='" + (jquery || xpath) + "') : ";
+ var inner = this.tools.xml_node_to_string(child, true);
+ if (operation) {
+ var allowed_operations = "append,prepend,before,after,replace,inner".split(',');
+ if (this.tools.arrayIndexOf(allowed_operations, operation) == -1) {
+ this.tools.exception(error_msg + "Invalid operation : '" + operation + "'");
+ }
+ operation = {'replace' : 'replaceWith', 'inner' : 'html'}[operation] || operation;
+ target[operation](this.jQuery(inner));
+ } else {
+ try {
+ var f = new Function(['$'], inner);
+ } catch(error) {
+ return this.tools.exception("Parse " + error_msg + error);
+ }
+ try {
+ f.apply(target, [this.jQuery]);
+ } catch(error) {
+ return this.tools.exception("Runtime " + error_msg + error);
+ }
+ }
+ }
+ }
+ }
+ });
+ return Engine;
+})();
+
+QWeb2.Element = (function() {
+ function Element(engine, node) {
+ this.engine = engine;
+ this.node = node;
+ this.tag = node.tagName;
+ this.actions = {};
+ this.actions_done = [];
+ this.attributes = {};
+ this.children = [];
+ this._top = [];
+ this._bottom = [];
+ this._indent = 1;
+ this.process_children = true;
+ var childs = this.node.childNodes;
+ if (childs) {
+ for (var i = 0, ilen = childs.length; i < ilen; i++) {
+ this.children.push(new QWeb2.Element(this.engine, childs[i]));
+ }
+ }
+ var attrs = this.node.attributes;
+ if (attrs) {
+ for (var j = 0, jlen = attrs.length; j < jlen; j++) {
+ var attr = attrs[j];
+ var name = attr.name;
+ var m = name.match(new RegExp("^" + this.engine.prefix + "-(.+)"));
+ if (m) {
+ name = m[1];
+ if (name === 'name') {
+ continue;
+ }
+ this.actions[name] = attr.value;
+ } else {
+ this.attributes[name] = attr.value;
+ }
+ }
+ }
+ }
+
+ QWeb2.tools.extend(Element.prototype, {
+ compile : function() {
+ var r = [],
+ instring = false,
+ lines = this._compile().split('\n');
+ for (var i = 0, ilen = lines.length; i < ilen; i++) {
+ var m, line = lines[i];
+ if (m = line.match(/^(\s*)\/\/@string=(.*)/)) {
+ if (instring) {
+ if (this.engine.debug) {
+ // Split string lines in indented r.push arguments
+ r.push((m[2].indexOf("\\n") != -1 ? "',\n\t" + m[1] + "'" : '') + m[2]);
+ } else {
+ r.push(m[2]);
+ }
+ } else {
+ r.push(m[1] + "r.push('" + m[2]);
+ instring = true;
+ }
+ } else {
+ if (instring) {
+ r.push("');\n");
+ }
+ instring = false;
+ r.push(line + '\n');
+ }
+ }
+ return r.join('');
+ },
+ _compile : function() {
+ switch (this.node.nodeType) {
+ case 3:
+ case 4:
+ this.top_string(this.node.data);
+ break;
+ case 1:
+ this.compile_element();
+ }
+ var r = this._top.join('');
+ if (this.process_children) {
+ for (var i = 0, ilen = this.children.length; i < ilen; i++) {
+ var child = this.children[i];
+ child._indent = this._indent;
+ r += child._compile();
+ }
+ }
+ r += this._bottom.join('');
+ return r;
+ },
+ format_expression : function(e) {
+ /* Naive format expression builder. Replace reserved words and variables to dict[variable]
+ * Does not handle spaces before dot yet, and causes problems for anonymous functions. Use t-js="" for that */
+ if (QWeb2.expressions_cache[e]) {
+ return QWeb2.expressions_cache[e];
+ }
+ var chars = e.split(''),
+ instring = '',
+ invar = '',
+ invar_pos = 0,
+ r = '';
+ chars.push(' ');
+ for (var i = 0, ilen = chars.length; i < ilen; i++) {
+ var c = chars[i];
+ if (instring.length) {
+ if (c === instring && chars[i - 1] !== "\\") {
+ instring = '';
+ }
+ } else if (c === '"' || c === "'") {
+ instring = c;
+ } else if (c.match(/[a-zA-Z_\$]/) && !invar.length) {
+ invar = c;
+ invar_pos = i;
+ continue;
+ } else if (c.match(/\W/) && invar.length) {
+ // TODO: Should check for possible spaces before dot
+ if (chars[invar_pos - 1] !== '.' && QWeb2.tools.arrayIndexOf(this.engine.reserved_words, invar) < 0) {
+ invar = this.engine.word_replacement[invar] || ("dict['" + invar + "']");
+ }
+ r += invar;
+ invar = '';
+ } else if (invar.length) {
+ invar += c;
+ continue;
+ }
+ r += c;
+ }
+ r = r.slice(0, -1);
+ QWeb2.expressions_cache[e] = r;
+ return r;
+ },
+ string_interpolation : function(s) {
+ if (!s) {
+ return "''";
+ }
+ var regex = /^{(.*)}(.*)/,
+ src = s.split(/#/),
+ r = [];
+ for (var i = 0, ilen = src.length; i < ilen; i++) {
+ var val = src[i],
+ m = val.match(regex);
+ if (m) {
+ r.push("(" + this.format_expression(m[1]) + ")");
+ if (m[2]) {
+ r.push(this.engine.tools.js_escape(m[2]));
+ }
+ } else if (!(i === 0 && val === '')) {
+ r.push(this.engine.tools.js_escape((i === 0 ? '' : '#') + val));
+ }
+ }
+ return r.join(' + ');
+ },
+ indent : function() {
+ return this._indent++;
+ },
+ dedent : function() {
+ if (this._indent !== 0) {
+ return this._indent--;
+ }
+ },
+ get_indent : function() {
+ return new Array(this._indent + 1).join("\t");
+ },
+ top : function(s) {
+ return this._top.push(this.get_indent() + s + '\n');
+ },
+ top_string : function(s) {
+ return this._top.push(this.get_indent() + "//@string=" + this.engine.tools.js_escape(s, true) + '\n');
+ },
+ bottom : function(s) {
+ return this._bottom.unshift(this.get_indent() + s + '\n');
+ },
+ bottom_string : function(s) {
+ return this._bottom.unshift(this.get_indent() + "//@string=" + this.engine.tools.js_escape(s, true) + '\n');
+ },
+ compile_element : function() {
+ for (var i = 0, ilen = this.engine.actions_precedence.length; i < ilen; i++) {
+ var a = this.engine.actions_precedence[i];
+ if (a in this.actions) {
+ var value = this.actions[a];
+ var key = 'compile_action_' + a;
+ if (this[key]) {
+ this[key](value);
+ } else if (this.engine[key]) {
+ this.engine[key].call(this, value);
+ } else {
+ this.engine.tools.exception("No handler method for action '" + a + "'");
+ }
+ }
+ }
+ if (this.tag !== this.engine.prefix) {
+ var tag = "<" + this.tag;
+ for (var a in this.attributes) {
+ tag += this.engine.tools.gen_attribute([a, this.attributes[a]]);
+ }
+ this.top_string(tag);
+ if (this.actions.att) {
+ this.top("r.push(context.engine.tools.gen_attribute(" + (this.format_expression(this.actions.att)) + "));");
+ }
+ for (var a in this.actions) {
+ var v = this.actions[a];
+ var m = a.match(/att-(.+)/);
+ if (m) {
+ this.top("r.push(context.engine.tools.gen_attribute(['" + m[1] + "', (" + (this.format_expression(v)) + ")]));");
+ }
+ var m = a.match(/attf-(.+)/);
+ if (m) {
+ this.top("r.push(context.engine.tools.gen_attribute(['" + m[1] + "', (" + (this.string_interpolation(v)) + ")]));");
+ }
+ }
+ if (this.children.length || this.actions.opentag === 'true') {
+ this.top_string(">");
+ this.bottom_string("</" + this.tag + ">");
+ } else {
+ this.top_string("/>");
+ }
+ }
+ },
+ compile_action_if : function(value) {
+ this.top("if (" + (this.format_expression(value)) + ") {");
+ this.bottom("}");
+ this.indent();
+ },
+ compile_action_foreach : function(value) {
+ var as = this.actions['as'] || value.replace(/[^a-zA-Z0-9]/g, '_');
+ //TODO: exception if t-as not valid
+ this.top("context.engine.tools.foreach(context, " + (this.format_expression(value)) + ", " + (this.engine.tools.js_escape(as)) + ", dict, function(context, dict) {");
+ this.bottom("});");
+ this.indent();
+ },
+ compile_action_call : function(value) {
+ var _import = this.actions['import'] || '';
+ if (this.children.length === 0) {
+ return this.top("r.push(context.engine.tools.call(context, " + (this.engine.tools.js_escape(value)) + ", dict, " + (this.engine.tools.js_escape(_import)) + "));");
+ } else {
+ this.top("r.push(context.engine.tools.call(context, " + (this.engine.tools.js_escape(value)) + ", dict, " + (this.engine.tools.js_escape(_import)) + ", function(context, dict) {");
+ this.bottom("}));");
+ this.indent();
+ this.top("var r = [];");
+ return this.bottom("return r.join('');");
+ }
+ },
+ compile_action_set : function(value) {
+ var variable = this.format_expression(value);
+ if (this.actions['value']) {
+ if (this.children.length) {
+ this.engine.tools.warning("@set with @value plus node chidren found. Children are ignored.");
+ }
+ this.top(variable + " = (" + (this.format_expression(this.actions['value'])) + ");");
+ this.process_children = false;
+ } else {
+ if (this.children.length === 0) {
+ this.top(variable + " = '';");
+ } else if (this.children.length === 1 && this.children[0].node.nodeType === 3) {
+ this.top(variable + " = " + (this.engine.tools.js_escape(this.children[0].node.data)) + ";");
+ this.process_children = false;
+ } else {
+ this.top(variable + " = (function(dict) {");
+ this.bottom("})(dict);");
+ this.indent();
+ this.top("var r = [];");
+ this.bottom("return r.join('');");
+ }
+ }
+ },
+ compile_action_esc : function(value) {
+ this.top("r.push(context.engine.tools.html_escape(" + (this.format_expression(value)) + "));");
+ },
+ compile_action_escf : function(value) {
+ this.top("r.push(context.engine.tools.html_escape(" + (this.string_interpolation(value)) + "));");
+ },
+ compile_action_raw : function(value) {
+ this.top("r.push(" + (this.format_expression(value)) + ");");
+ },
+ compile_action_rawf : function(value) {
+ this.top("r.push(" + (this.string_interpolation(value)) + ");");
+ },
+ compile_action_js : function(value) {
+ this.top("(function(" + value + ") {");
+ this.bottom("})(dict);");
+ this.indent();
+ var lines = this.engine.tools.xml_node_to_string(this.node, true).split(/\r?\n/);
+ for (var i = 0, ilen = lines.length; i < ilen; i++) {
+ this.top(lines[i]);
+ }
+ this.process_children = false;
+ },
+ compile_action_debug : function(value) {
+ this.top("debugger;");
+ },
+ compile_action_log : function(value) {
+ this.top("console.log(" + this.format_expression(value) + "});");
+ }
+ });
+ return Element;
+})();
diff --git a/addons/web/static/lib/underscore/underscore.js b/addons/web/static/lib/underscore/underscore.js
new file mode 100644
index 00000000000..4f56013259b
--- /dev/null
+++ b/addons/web/static/lib/underscore/underscore.js
@@ -0,0 +1,839 @@
+// Underscore.js 1.1.7
+// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+
+(function() {
+
+ // Baseline setup
+ // --------------
+
+ // Establish the root object, `window` in the browser, or `global` on the server.
+ var root = this;
+
+ // Save the previous value of the `_` variable.
+ var previousUnderscore = root._;
+
+ // Establish the object that gets returned to break out of a loop iteration.
+ var breaker = {};
+
+ // Save bytes in the minified (but not gzipped) version:
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
+
+ // Create quick reference variables for speed access to core prototypes.
+ var slice = ArrayProto.slice,
+ unshift = ArrayProto.unshift,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;
+
+ // All **ECMAScript 5** native function implementations that we hope to use
+ // are declared here.
+ var
+ nativeForEach = ArrayProto.forEach,
+ nativeMap = ArrayProto.map,
+ nativeReduce = ArrayProto.reduce,
+ nativeReduceRight = ArrayProto.reduceRight,
+ nativeFilter = ArrayProto.filter,
+ nativeEvery = ArrayProto.every,
+ nativeSome = ArrayProto.some,
+ nativeIndexOf = ArrayProto.indexOf,
+ nativeLastIndexOf = ArrayProto.lastIndexOf,
+ nativeIsArray = Array.isArray,
+ nativeKeys = Object.keys,
+ nativeBind = FuncProto.bind;
+
+ // Create a safe reference to the Underscore object for use below.
+ var _ = function(obj) { return new wrapper(obj); };
+
+ // Export the Underscore object for **CommonJS**, with backwards-compatibility
+ // for the old `require()` API. If we're not in CommonJS, add `_` to the
+ // global object.
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = _;
+ _._ = _;
+ } else {
+ // Exported as a string, for Closure Compiler "advanced" mode.
+ root['_'] = _;
+ }
+
+ // Current version.
+ _.VERSION = '1.1.7';
+
+ // Collection Functions
+ // --------------------
+
+ // The cornerstone, an `each` implementation, aka `forEach`.
+ // Handles objects with the built-in `forEach`, arrays, and raw objects.
+ // Delegates to **ECMAScript 5**'s native `forEach` if available.
+ var each = _.each = _.forEach = function(obj, iterator, context) {
+ if (obj == null) return;
+ if (nativeForEach && obj.forEach === nativeForEach) {
+ obj.forEach(iterator, context);
+ } else if (obj.length === +obj.length) {
+ for (var i = 0, l = obj.length; i < l; i++) {
+ if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
+ }
+ } else {
+ for (var key in obj) {
+ if (hasOwnProperty.call(obj, key)) {
+ if (iterator.call(context, obj[key], key, obj) === breaker) return;
+ }
+ }
+ }
+ };
+
+ // Return the results of applying the iterator to each element.
+ // Delegates to **ECMAScript 5**'s native `map` if available.
+ _.map = function(obj, iterator, context) {
+ var results = [];
+ if (obj == null) return results;
+ if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
+ each(obj, function(value, index, list) {
+ results[results.length] = iterator.call(context, value, index, list);
+ });
+ return results;
+ };
+
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
+ // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
+ _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
+ var initial = memo !== void 0;
+ if (obj == null) obj = [];
+ if (nativeReduce && obj.reduce === nativeReduce) {
+ if (context) iterator = _.bind(iterator, context);
+ return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+ }
+ each(obj, function(value, index, list) {
+ if (!initial) {
+ memo = value;
+ initial = true;
+ } else {
+ memo = iterator.call(context, memo, value, index, list);
+ }
+ });
+ if (!initial) throw new TypeError("Reduce of empty array with no initial value");
+ return memo;
+ };
+
+ // The right-associative version of reduce, also known as `foldr`.
+ // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
+ _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
+ if (obj == null) obj = [];
+ if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+ if (context) iterator = _.bind(iterator, context);
+ return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ }
+ var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
+ return _.reduce(reversed, iterator, memo, context);
+ };
+
+ // Return the first value which passes a truth test. Aliased as `detect`.
+ _.find = _.detect = function(obj, iterator, context) {
+ var result;
+ any(obj, function(value, index, list) {
+ if (iterator.call(context, value, index, list)) {
+ result = value;
+ return true;
+ }
+ });
+ return result;
+ };
+
+ // Return all the elements that pass a truth test.
+ // Delegates to **ECMAScript 5**'s native `filter` if available.
+ // Aliased as `select`.
+ _.filter = _.select = function(obj, iterator, context) {
+ var results = [];
+ if (obj == null) return results;
+ if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
+ each(obj, function(value, index, list) {
+ if (iterator.call(context, value, index, list)) results[results.length] = value;
+ });
+ return results;
+ };
+
+ // Return all the elements for which a truth test fails.
+ _.reject = function(obj, iterator, context) {
+ var results = [];
+ if (obj == null) return results;
+ each(obj, function(value, index, list) {
+ if (!iterator.call(context, value, index, list)) results[results.length] = value;
+ });
+ return results;
+ };
+
+ // Determine whether all of the elements match a truth test.
+ // Delegates to **ECMAScript 5**'s native `every` if available.
+ // Aliased as `all`.
+ _.every = _.all = function(obj, iterator, context) {
+ var result = true;
+ if (obj == null) return result;
+ if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
+ each(obj, function(value, index, list) {
+ if (!(result = result && iterator.call(context, value, index, list))) return breaker;
+ });
+ return result;
+ };
+
+ // Determine if at least one element in the object matches a truth test.
+ // Delegates to **ECMAScript 5**'s native `some` if available.
+ // Aliased as `any`.
+ var any = _.some = _.any = function(obj, iterator, context) {
+ iterator = iterator || _.identity;
+ var result = false;
+ if (obj == null) return result;
+ if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
+ each(obj, function(value, index, list) {
+ if (result |= iterator.call(context, value, index, list)) return breaker;
+ });
+ return !!result;
+ };
+
+ // Determine if a given value is included in the array or object using `===`.
+ // Aliased as `contains`.
+ _.include = _.contains = function(obj, target) {
+ var found = false;
+ if (obj == null) return found;
+ if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
+ any(obj, function(value) {
+ if (found = value === target) return true;
+ });
+ return found;
+ };
+
+ // Invoke a method (with arguments) on every item in a collection.
+ _.invoke = function(obj, method) {
+ var args = slice.call(arguments, 2);
+ return _.map(obj, function(value) {
+ return (method.call ? method || value : value[method]).apply(value, args);
+ });
+ };
+
+ // Convenience version of a common use case of `map`: fetching a property.
+ _.pluck = function(obj, key) {
+ return _.map(obj, function(value){ return value[key]; });
+ };
+
+ // Return the maximum element or (element-based computation).
+ _.max = function(obj, iterator, context) {
+ if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
+ var result = {computed : -Infinity};
+ each(obj, function(value, index, list) {
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
+ computed >= result.computed && (result = {value : value, computed : computed});
+ });
+ return result.value;
+ };
+
+ // Return the minimum element (or element-based computation).
+ _.min = function(obj, iterator, context) {
+ if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
+ var result = {computed : Infinity};
+ each(obj, function(value, index, list) {
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
+ computed < result.computed && (result = {value : value, computed : computed});
+ });
+ return result.value;
+ };
+
+ // Sort the object's values by a criterion produced by an iterator.
+ _.sortBy = function(obj, iterator, context) {
+ return _.pluck(_.map(obj, function(value, index, list) {
+ return {
+ value : value,
+ criteria : iterator.call(context, value, index, list)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }), 'value');
+ };
+
+ // Groups the object's values by a criterion produced by an iterator
+ _.groupBy = function(obj, iterator) {
+ var result = {};
+ each(obj, function(value, index) {
+ var key = iterator(value, index);
+ (result[key] || (result[key] = [])).push(value);
+ });
+ return result;
+ };
+
+ // Use a comparator function to figure out at what index an object should
+ // be inserted so as to maintain order. Uses binary search.
+ _.sortedIndex = function(array, obj, iterator) {
+ iterator || (iterator = _.identity);
+ var low = 0, high = array.length;
+ while (low < high) {
+ var mid = (low + high) >> 1;
+ iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
+ }
+ return low;
+ };
+
+ // Safely convert anything iterable into a real, live array.
+ _.toArray = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) return iterable.toArray();
+ if (_.isArray(iterable)) return slice.call(iterable);
+ if (_.isArguments(iterable)) return slice.call(iterable);
+ return _.values(iterable);
+ };
+
+ // Return the number of elements in an object.
+ _.size = function(obj) {
+ return _.toArray(obj).length;
+ };
+
+ // Array Functions
+ // ---------------
+
+ // Get the first element of an array. Passing **n** will return the first N
+ // values in the array. Aliased as `head`. The **guard** check allows it to work
+ // with `_.map`.
+ _.first = _.head = function(array, n, guard) {
+ return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
+ };
+
+ // Returns everything but the first entry of the array. Aliased as `tail`.
+ // Especially useful on the arguments object. Passing an **index** will return
+ // the rest of the values in the array from that index onward. The **guard**
+ // check allows it to work with `_.map`.
+ _.rest = _.tail = function(array, index, guard) {
+ return slice.call(array, (index == null) || guard ? 1 : index);
+ };
+
+ // Get the last element of an array.
+ _.last = function(array) {
+ return array[array.length - 1];
+ };
+
+ // Trim out all falsy values from an array.
+ _.compact = function(array) {
+ return _.filter(array, function(value){ return !!value; });
+ };
+
+ // Return a completely flattened version of an array.
+ _.flatten = function(array) {
+ return _.reduce(array, function(memo, value) {
+ if (_.isArray(value)) return memo.concat(_.flatten(value));
+ memo[memo.length] = value;
+ return memo;
+ }, []);
+ };
+
+ // Return a version of the array that does not contain the specified value(s).
+ _.without = function(array) {
+ return _.difference(array, slice.call(arguments, 1));
+ };
+
+ // Produce a duplicate-free version of the array. If the array has already
+ // been sorted, you have the option of using a faster algorithm.
+ // Aliased as `unique`.
+ _.uniq = _.unique = function(array, isSorted) {
+ return _.reduce(array, function(memo, el, i) {
+ if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
+ return memo;
+ }, []);
+ };
+
+ // Produce an array that contains the union: each distinct element from all of
+ // the passed-in arrays.
+ _.union = function() {
+ return _.uniq(_.flatten(arguments));
+ };
+
+ // Produce an array that contains every item shared between all the
+ // passed-in arrays. (Aliased as "intersect" for back-compat.)
+ _.intersection = _.intersect = function(array) {
+ var rest = slice.call(arguments, 1);
+ return _.filter(_.uniq(array), function(item) {
+ return _.every(rest, function(other) {
+ return _.indexOf(other, item) >= 0;
+ });
+ });
+ };
+
+ // Take the difference between one array and another.
+ // Only the elements present in just the first array will remain.
+ _.difference = function(array, other) {
+ return _.filter(array, function(value){ return !_.include(other, value); });
+ };
+
+ // Zip together multiple lists into a single array -- elements that share
+ // an index go together.
+ _.zip = function() {
+ var args = slice.call(arguments);
+ var length = _.max(_.pluck(args, 'length'));
+ var results = new Array(length);
+ for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
+ return results;
+ };
+
+ // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
+ // we need this function. Return the position of the first occurrence of an
+ // item in an array, or -1 if the item is not included in the array.
+ // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+ // If the array is large and already in sort order, pass `true`
+ // for **isSorted** to use binary search.
+ _.indexOf = function(array, item, isSorted) {
+ if (array == null) return -1;
+ var i, l;
+ if (isSorted) {
+ i = _.sortedIndex(array, item);
+ return array[i] === item ? i : -1;
+ }
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
+ for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
+ return -1;
+ };
+
+
+ // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
+ _.lastIndexOf = function(array, item) {
+ if (array == null) return -1;
+ if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
+ var i = array.length;
+ while (i--) if (array[i] === item) return i;
+ return -1;
+ };
+
+ // Generate an integer Array containing an arithmetic progression. A port of
+ // the native Python `range()` function. See
+ // [the Python documentation](http://docs.python.org/library/functions.html#range).
+ _.range = function(start, stop, step) {
+ if (arguments.length <= 1) {
+ stop = start || 0;
+ start = 0;
+ }
+ step = arguments[2] || 1;
+
+ var len = Math.max(Math.ceil((stop - start) / step), 0);
+ var idx = 0;
+ var range = new Array(len);
+
+ while(idx < len) {
+ range[idx++] = start;
+ start += step;
+ }
+
+ return range;
+ };
+
+ // Function (ahem) Functions
+ // ------------------
+
+ // Create a function bound to a given object (assigning `this`, and arguments,
+ // optionally). Binding with arguments is also known as `curry`.
+ // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
+ // We check for `func.bind` first, to fail fast when `func` is undefined.
+ _.bind = function(func, obj) {
+ if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+ var args = slice.call(arguments, 2);
+ return function() {
+ return func.apply(obj, args.concat(slice.call(arguments)));
+ };
+ };
+
+ // Bind all of an object's methods to that object. Useful for ensuring that
+ // all callbacks defined on an object belong to it.
+ _.bindAll = function(obj) {
+ var funcs = slice.call(arguments, 1);
+ if (funcs.length == 0) funcs = _.functions(obj);
+ each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+ return obj;
+ };
+
+ // Memoize an expensive function by storing its results.
+ _.memoize = function(func, hasher) {
+ var memo = {};
+ hasher || (hasher = _.identity);
+ return function() {
+ var key = hasher.apply(this, arguments);
+ return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+ };
+ };
+
+ // Delays a function for the given number of milliseconds, and then calls
+ // it with the arguments supplied.
+ _.delay = function(func, wait) {
+ var args = slice.call(arguments, 2);
+ return setTimeout(function(){ return func.apply(func, args); }, wait);
+ };
+
+ // Defers a function, scheduling it to run after the current call stack has
+ // cleared.
+ _.defer = function(func) {
+ return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
+ };
+
+ // Internal function used to implement `_.throttle` and `_.debounce`.
+ var limit = function(func, wait, debounce) {
+ var timeout;
+ return function() {
+ var context = this, args = arguments;
+ var throttler = function() {
+ timeout = null;
+ func.apply(context, args);
+ };
+ if (debounce) clearTimeout(timeout);
+ if (debounce || !timeout) timeout = setTimeout(throttler, wait);
+ };
+ };
+
+ // Returns a function, that, when invoked, will only be triggered at most once
+ // during a given window of time.
+ _.throttle = function(func, wait) {
+ return limit(func, wait, false);
+ };
+
+ // Returns a function, that, as long as it continues to be invoked, will not
+ // be triggered. The function will be called after it stops being called for
+ // N milliseconds.
+ _.debounce = function(func, wait) {
+ return limit(func, wait, true);
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = function(func) {
+ var ran = false, memo;
+ return function() {
+ if (ran) return memo;
+ ran = true;
+ return memo = func.apply(this, arguments);
+ };
+ };
+
+ // Returns the first function passed as an argument to the second,
+ // allowing you to adjust arguments, run code before and after, and
+ // conditionally execute the original function.
+ _.wrap = function(func, wrapper) {
+ return function() {
+ var args = [func].concat(slice.call(arguments));
+ return wrapper.apply(this, args);
+ };
+ };
+
+ // Returns a function that is the composition of a list of functions, each
+ // consuming the return value of the function that follows.
+ _.compose = function() {
+ var funcs = slice.call(arguments);
+ return function() {
+ var args = slice.call(arguments);
+ for (var i = funcs.length - 1; i >= 0; i--) {
+ args = [funcs[i].apply(this, args)];
+ }
+ return args[0];
+ };
+ };
+
+ // Returns a function that will only be executed after being called N times.
+ _.after = function(times, func) {
+ return function() {
+ if (--times < 1) { return func.apply(this, arguments); }
+ };
+ };
+
+
+ // Object Functions
+ // ----------------
+
+ // Retrieve the names of an object's properties.
+ // Delegates to **ECMAScript 5**'s native `Object.keys`
+ _.keys = nativeKeys || function(obj) {
+ if (obj !== Object(obj)) throw new TypeError('Invalid object');
+ var keys = [];
+ for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
+ return keys;
+ };
+
+ // Retrieve the values of an object's properties.
+ _.values = function(obj) {
+ return _.map(obj, _.identity);
+ };
+
+ // Return a sorted list of the function names available on the object.
+ // Aliased as `methods`
+ _.functions = _.methods = function(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (_.isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+ };
+
+ // Extend a given object with all the properties in passed-in object(s).
+ _.extend = function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ for (var prop in source) {
+ if (source[prop] !== void 0) obj[prop] = source[prop];
+ }
+ });
+ return obj;
+ };
+
+ // Fill in a given object with default properties.
+ _.defaults = function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ for (var prop in source) {
+ if (obj[prop] == null) obj[prop] = source[prop];
+ }
+ });
+ return obj;
+ };
+
+ // Create a (shallow-cloned) duplicate of an object.
+ _.clone = function(obj) {
+ return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+ };
+
+ // Invokes interceptor with the obj, and then returns obj.
+ // The primary purpose of this method is to "tap into" a method chain, in
+ // order to perform operations on intermediate results within the chain.
+ _.tap = function(obj, interceptor) {
+ interceptor(obj);
+ return obj;
+ };
+
+ // Perform a deep comparison to check if two objects are equal.
+ _.isEqual = function(a, b) {
+ // Check object identity.
+ if (a === b) return true;
+ // Different types?
+ var atype = typeof(a), btype = typeof(b);
+ if (atype != btype) return false;
+ // Basic equality test (watch out for coercions).
+ if (a == b) return true;
+ // One is falsy and the other truthy.
+ if ((!a && b) || (a && !b)) return false;
+ // Unwrap any wrapped objects.
+ if (a._chain) a = a._wrapped;
+ if (b._chain) b = b._wrapped;
+ // One of them implements an isEqual()?
+ if (a.isEqual) return a.isEqual(b);
+ if (b.isEqual) return b.isEqual(a);
+ // Check dates' integer values.
+ if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
+ // Both are NaN?
+ if (_.isNaN(a) && _.isNaN(b)) return false;
+ // Compare regular expressions.
+ if (_.isRegExp(a) && _.isRegExp(b))
+ return a.source === b.source &&
+ a.global === b.global &&
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline;
+ // If a is not an object by this point, we can't handle it.
+ if (atype !== 'object') return false;
+ // Check for different array lengths before comparing contents.
+ if (a.length && (a.length !== b.length)) return false;
+ // Nothing else worked, deep compare the contents.
+ var aKeys = _.keys(a), bKeys = _.keys(b);
+ // Different object sizes?
+ if (aKeys.length != bKeys.length) return false;
+ // Recursive comparison of contents.
+ for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
+ return true;
+ };
+
+ // Is a given array or object empty?
+ _.isEmpty = function(obj) {
+ if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+ for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
+ return true;
+ };
+
+ // Is a given value a DOM element?
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType == 1);
+ };
+
+ // Is a given value an array?
+ // Delegates to ECMA5's native Array.isArray
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) === '[object Array]';
+ };
+
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ return obj === Object(obj);
+ };
+
+ // Is a given variable an arguments object?
+ _.isArguments = function(obj) {
+ return !!(obj && hasOwnProperty.call(obj, 'callee'));
+ };
+
+ // Is a given value a function?
+ _.isFunction = function(obj) {
+ return !!(obj && obj.constructor && obj.call && obj.apply);
+ };
+
+ // Is a given value a string?
+ _.isString = function(obj) {
+ return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
+ };
+
+ // Is a given value a number?
+ _.isNumber = function(obj) {
+ return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
+ };
+
+ // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
+ // that does not equal itself.
+ _.isNaN = function(obj) {
+ return obj !== obj;
+ };
+
+ // Is a given value a boolean?
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false;
+ };
+
+ // Is a given value a date?
+ _.isDate = function(obj) {
+ return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
+ };
+
+ // Is the given value a regular expression?
+ _.isRegExp = function(obj) {
+ return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
+ };
+
+ // Is a given value equal to null?
+ _.isNull = function(obj) {
+ return obj === null;
+ };
+
+ // Is a given variable undefined?
+ _.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ // Utility Functions
+ // -----------------
+
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+ // previous owner. Returns a reference to the Underscore object.
+ _.noConflict = function() {
+ root._ = previousUnderscore;
+ return this;
+ };
+
+ // Keep the identity function around for default iterators.
+ _.identity = function(value) {
+ return value;
+ };
+
+ // Run a function **n** times.
+ _.times = function (n, iterator, context) {
+ for (var i = 0; i < n; i++) iterator.call(context, i);
+ };
+
+ // Add your own custom functions to the Underscore object, ensuring that
+ // they're correctly added to the OOP wrapper as well.
+ _.mixin = function(obj) {
+ each(_.functions(obj), function(name){
+ addToWrapper(name, _[name] = obj[name]);
+ });
+ };
+
+ // Generate a unique integer id (unique within the entire client session).
+ // Useful for temporary DOM ids.
+ var idCounter = 0;
+ _.uniqueId = function(prefix) {
+ var id = idCounter++;
+ return prefix ? prefix + id : id;
+ };
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ evaluate : /<%([\s\S]+?)%>/g,
+ interpolate : /<%=([\s\S]+?)%>/g
+ };
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ _.template = function(str, data) {
+ var c = _.templateSettings;
+ var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
+ 'with(obj||{}){__p.push(\'' +
+ str.replace(/\\/g, '\\\\')
+ .replace(/'/g, "\\'")
+ .replace(c.interpolate, function(match, code) {
+ return "'," + code.replace(/\\'/g, "'") + ",'";
+ })
+ .replace(c.evaluate || null, function(match, code) {
+ return "');" + code.replace(/\\'/g, "'")
+ .replace(/[\r\n\t]/g, ' ') + "__p.push('";
+ })
+ .replace(/\r/g, '\\r')
+ .replace(/\n/g, '\\n')
+ .replace(/\t/g, '\\t')
+ + "');}return __p.join('');";
+ var func = new Function('obj', tmpl);
+ return data ? func(data) : func;
+ };
+
+ // The OOP Wrapper
+ // ---------------
+
+ // If Underscore is called as a function, it returns a wrapped object that
+ // can be used OO-style. This wrapper holds altered versions of all the
+ // underscore functions. Wrapped objects may be chained.
+ var wrapper = function(obj) { this._wrapped = obj; };
+
+ // Expose `wrapper.prototype` as `_.prototype`
+ _.prototype = wrapper.prototype;
+
+ // Helper function to continue chaining intermediate results.
+ var result = function(obj, chain) {
+ return chain ? _(obj).chain() : obj;
+ };
+
+ // A method to easily add functions to the OOP wrapper.
+ var addToWrapper = function(name, func) {
+ wrapper.prototype[name] = function() {
+ var args = slice.call(arguments);
+ unshift.call(args, this._wrapped);
+ return result(func.apply(_, args), this._chain);
+ };
+ };
+
+ // Add all of the Underscore functions to the wrapper object.
+ _.mixin(_);
+
+ // Add all mutator Array functions to the wrapper.
+ each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ var method = ArrayProto[name];
+ wrapper.prototype[name] = function() {
+ method.apply(this._wrapped, arguments);
+ return result(this._wrapped, this._chain);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ each(['concat', 'join', 'slice'], function(name) {
+ var method = ArrayProto[name];
+ wrapper.prototype[name] = function() {
+ return result(method.apply(this._wrapped, arguments), this._chain);
+ };
+ });
+
+ // Start chaining a wrapped Underscore object.
+ wrapper.prototype.chain = function() {
+ this._chain = true;
+ return this;
+ };
+
+ // Extracts the result from a wrapped and chained object.
+ wrapper.prototype.value = function() {
+ return this._wrapped;
+ };
+
+})();
diff --git a/addons/web/static/lib/underscore/underscore.string.js b/addons/web/static/lib/underscore/underscore.string.js
new file mode 100644
index 00000000000..4da2b26ec1c
--- /dev/null
+++ b/addons/web/static/lib/underscore/underscore.string.js
@@ -0,0 +1,304 @@
+// Underscore.string
+// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
+// Underscore.strings is freely distributable under the terms of the MIT license.
+// Documentation: https://github.com/edtsech/underscore.string
+// Some code is borrowed from MooTools and Alexandru Marasteanu.
+
+// Version 1.1.4
+
+(function(){
+ // ------------------------- Baseline setup ---------------------------------
+
+ // Establish the root object, "window" in the browser, or "global" on the server.
+ var root = this;
+
+ var nativeTrim = String.prototype.trim;
+
+ function str_repeat(i, m) {
+ for (var o = []; m > 0; o[--m] = i);
+ return o.join('');
+ }
+
+ function defaultToWhiteSpace(characters){
+ if (characters) {
+ return _s.escapeRegExp(characters);
+ }
+ return '\\s';
+ }
+
+ var _s = {
+
+ isBlank: function(str){
+ return !!str.match(/^\s*$/);
+ },
+
+ capitalize : function(str) {
+ return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
+ },
+
+ chop: function(str, step){
+ step = step || str.length;
+ var arr = [];
+ for (var i = 0; i < str.length;) {
+ arr.push(str.slice(i,i + step));
+ i = i + step;
+ }
+ return arr;
+ },
+
+ clean: function(str){
+ return _s.strip(str.replace(/\s+/g, ' '));
+ },
+
+ count: function(str, substr){
+ var count = 0, index;
+ for (var i=0; i < str.length;) {
+ index = str.indexOf(substr, i);
+ index >= 0 && count++;
+ i = i + (index >= 0 ? index : 0) + substr.length;
+ }
+ return count;
+ },
+
+ chars: function(str) {
+ return str.split('');
+ },
+
+ escapeHTML: function(str) {
+ return String(str||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
+ .replace(/"/g, '&quot;').replace(/'/g, "&apos;");
+ },
+
+ unescapeHTML: function(str) {
+ return String(str||'').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
+ .replace(/&quot;/g, '"').replace(/&apos;/g, "'");
+ },
+
+ escapeRegExp: function(str){
+ // From MooTools core 1.2.4
+ return String(str||'').replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
+ },
+
+ insert: function(str, i, substr){
+ var arr = str.split('');
+ arr.splice(i, 0, substr);
+ return arr.join('');
+ },
+
+ includes: function(str, needle){
+ return str.indexOf(needle) !== -1;
+ },
+
+ join: function(sep) {
+ // TODO: Could this be faster by converting
+ // arguments to Array and using array.join(sep)?
+ sep = String(sep);
+ var str = "";
+ for (var i=1; i < arguments.length; i += 1) {
+ str += String(arguments[i]);
+ if ( i !== arguments.length-1 ) {
+ str += sep;
+ }
+ }
+ return str;
+ },
+
+ lines: function(str) {
+ return str.split("\n");
+ },
+
+// reverse: function(str){
+// return Array.prototype.reverse.apply(str.split('')).join('');
+// },
+
+ splice: function(str, i, howmany, substr){
+ var arr = str.split('');
+ arr.splice(i, howmany, substr);
+ return arr.join('');
+ },
+
+ startsWith: function(str, starts){
+ return str.length >= starts.length && str.substring(0, starts.length) === starts;
+ },
+
+ endsWith: function(str, ends){
+ return str.length >= ends.length && str.substring(str.length - ends.length) === ends;
+ },
+
+ succ: function(str){
+ var arr = str.split('');
+ arr.splice(str.length-1, 1, String.fromCharCode(str.charCodeAt(str.length-1) + 1));
+ return arr.join('');
+ },
+
+ titleize: function(str){
+ var arr = str.split(' '),
+ word;
+ for (var i=0; i < arr.length; i++) {
+ word = arr[i].split('');
+ if(typeof word[0] !== 'undefined') word[0] = word[0].toUpperCase();
+ i+1 === arr.length ? arr[i] = word.join('') : arr[i] = word.join('') + ' ';
+ }
+ return arr.join('');
+ },
+
+ camelize: function(str){
+ return _s.trim(str).replace(/(\-|_|\s)+(.)?/g, function(match, separator, chr) {
+ return chr ? chr.toUpperCase() : '';
+ });
+ },
+
+ underscored: function(str){
+ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-|\s+/g, '_').toLowerCase();
+ },
+
+ dasherize: function(str){
+ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1-$2').replace(/^([A-Z]+)/, '-$1').replace(/\_|\s+/g, '-').toLowerCase();
+ },
+
+ trim: function(str, characters){
+ if (!characters && nativeTrim) {
+ return nativeTrim.call(str);
+ }
+ characters = defaultToWhiteSpace(characters);
+ return str.replace(new RegExp('\^[' + characters + ']+|[' + characters + ']+$', 'g'), '');
+ },
+
+ ltrim: function(str, characters){
+ characters = defaultToWhiteSpace(characters);
+ return str.replace(new RegExp('\^[' + characters + ']+', 'g'), '');
+ },
+
+ rtrim: function(str, characters){
+ characters = defaultToWhiteSpace(characters);
+ return str.replace(new RegExp('[' + characters + ']+$', 'g'), '');
+ },
+
+ truncate: function(str, length, truncateStr){
+ truncateStr = truncateStr || '...';
+ return str.slice(0,length) + truncateStr;
+ },
+
+ words: function(str, delimiter) {
+ delimiter = delimiter || " ";
+ return str.split(delimiter);
+ },
+
+
+ pad: function(str, length, padStr, type) {
+
+ var padding = '';
+ var padlen = 0;
+
+ if (!padStr) { padStr = ' '; }
+ else if (padStr.length > 1) { padStr = padStr[0]; }
+ switch(type) {
+ case "right":
+ padlen = (length - str.length);
+ padding = str_repeat(padStr, padlen);
+ str = str+padding;
+ break;
+ case "both":
+ padlen = (length - str.length);
+ padding = {
+ 'left' : str_repeat(padStr, Math.ceil(padlen/2)),
+ 'right': str_repeat(padStr, Math.floor(padlen/2))
+ };
+ str = padding.left+str+padding.right;
+ break;
+ default: // "left"
+ padlen = (length - str.length);
+ padding = str_repeat(padStr, padlen);;
+ str = padding+str;
+ }
+ return str;
+ },
+
+ lpad: function(str, length, padStr) {
+ return _s.pad(str, length, padStr);
+ },
+
+ rpad: function(str, length, padStr) {
+ return _s.pad(str, length, padStr, 'right');
+ },
+
+ lrpad: function(str, length, padStr) {
+ return _s.pad(str, length, padStr, 'both');
+ },
+
+
+ /**
+ * Credits for this function goes to
+ * http://www.diveintojavascript.com/projects/sprintf-for-javascript
+ *
+ * Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
+ * All rights reserved.
+ * */
+ sprintf: function(){
+
+ var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = '';
+ while (f) {
+ if (m = /^[^\x25]+/.exec(f)) {
+ o.push(m[0]);
+ }
+ else if (m = /^\x25{2}/.exec(f)) {
+ o.push('%');
+ }
+ else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
+ if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) {
+ throw('Too few arguments.');
+ }
+ if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) {
+ throw('Expecting number but found ' + typeof(a));
+ }
+ switch (m[7]) {
+ case 'b': a = a.toString(2); break;
+ case 'c': a = String.fromCharCode(a); break;
+ case 'd': a = parseInt(a); break;
+ case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
+ case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
+ case 'o': a = a.toString(8); break;
+ case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
+ case 'u': a = Math.abs(a); break;
+ case 'x': a = a.toString(16); break;
+ case 'X': a = a.toString(16).toUpperCase(); break;
+ }
+ a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a);
+ c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
+ x = m[5] - String(a).length - s.length;
+ p = m[5] ? str_repeat(c, x) : '';
+ o.push(s + (m[4] ? a + p : p + a));
+ }
+ else {
+ throw('Huh ?!');
+ }
+ f = f.substring(m[0].length);
+ }
+ return o.join('');
+ }
+ }
+
+ // Aliases
+
+ _s.strip = _s.trim;
+ _s.lstrip = _s.ltrim;
+ _s.rstrip = _s.rtrim;
+ _s.center = _s.lrpad
+ _s.ljust = _s.lpad
+ _s.rjust = _s.rpad
+
+ // CommonJS module is defined
+ if (typeof window === 'undefined' && typeof module !== 'undefined') {
+ // Export module
+ module.exports = _s;
+
+ // Integrate with Underscore.js
+ } else if (typeof root._ !== 'undefined') {
+ root._.mixin(_s);
+
+ // Or define it
+ } else {
+ root._ = _s;
+ }
+
+}());
diff --git a/addons/web/static/src/css/base-ie7.css b/addons/web/static/src/css/base-ie7.css
new file mode 100644
index 00000000000..35599dbdd4b
--- /dev/null
+++ b/addons/web/static/src/css/base-ie7.css
@@ -0,0 +1,4 @@
+
+.openerp .menu span {
+ min-width: 0px;
+}
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
new file mode 100644
index 00000000000..cc8b596e6f5
--- /dev/null
+++ b/addons/web/static/src/css/base.css
@@ -0,0 +1,1317 @@
+/* TODO: separate openerp web client page css from openerp views css */
+body.openerp {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ min-width: 1000px;
+ overflow-y: scroll;
+ font-size: 80%;
+}
+
+body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, .openerp button, .openerp .ui-widget {
+ font-family: Ubuntu, Helvetica, sans-serif;
+}
+
+.oe_box {
+ border: 1px solid #aaf;
+ padding: 2px;
+ margin: 2px;
+}
+
+#oe_header h2 {
+ margin: 2px 0;
+}
+
+#oe_errors pre {
+ margin: 0;
+}
+
+.openerp .oe-number {
+ text-align: right !important;
+}
+.openerp .oe_hide {
+ display: none !important;
+}
+
+/* STATES */
+.openerp .on_logged,
+.openerp .db_options_row {
+ display: none;
+}
+
+/* Loading */
+.openerp .loading {
+ display: none;
+ z-index: 100;
+ position: fixed;
+ top: 0;
+ right: 50%;
+ padding: 4px 12px;
+ background: #A61300;
+ color: white;
+ text-align: center;
+ border: 1px solid #900;
+ border-top: none;
+ -moz-border-radius-bottomright: 8px;
+ -moz-border-radius-bottomleft: 8px;
+ border-bottom-right-radius: 8px;
+ border-bottom-left-radius: 8px;
+}
+.openerp .oe_notification {
+ z-index: 1001;
+ display: none;
+}
+.openerp .oe_notification * {
+ color: white;
+}
+
+/* Login */
+.openerp .login {
+ display: none;
+}
+.openerp .login form {
+ float: left;
+ width: 420px;
+ margin-left: 40px;
+ margin-bottom: 60px;
+}
+.openerp .login fieldset {
+ padding-bottom: 5px;
+ min-width: 100px;
+ margin-top: 60px;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+}
+.openerp .login fieldset legend {
+ padding: 4px;
+}
+.openerp .login .oe_box2 {
+ padding: 5px 5px 20px 5px;
+}
+.openerp .login .oe_box2 table {
+ width: 100%;
+ border:none;
+}
+.openerp .login .oe_box2 td {
+ padding: 3px;
+ text-align: right;
+}
+.openerp .login .oe_box2 td input,
+.openerp .login .oe_box2 td select {
+ width: 100%;
+}
+.openerp .login .oe_box2 td.oe_remember {
+ text-align:left;
+}
+.openerp .login .oe_box2 td.oe_remember input {
+ width: inherit;
+}
+.openerp .login .oe_login_right_pane {
+ padding:70px 35px 5px 10px;
+ min-width: 200px;
+ margin-left: 500px;
+}
+.openerp .login .login_error_message {
+ display: none;
+ background-color: #9A0404;
+ border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ color: white;
+ font-size: 16px;
+ font-weight: bold;
+ padding: 5px;
+ margin-top: 5px;
+ text-align: center;
+}
+.openerp .login.login_invalid .login_error_message {
+ display: block;
+}
+
+.openerp.login-mode .login-container {
+ height: 100%;
+}
+.openerp.login-mode .login {
+ display: block;
+}
+.openerp.login-mode .menu,
+.openerp.login-mode .secondary_menu,
+.openerp.login-mode .oe-application,
+.openerp.login-mode .db_options_row {
+ display: none;
+}
+
+/* Database */
+.openerp.database_block .db_options_row {
+ height: 100%;
+ display: table-row;
+}
+
+.openerp.database_block .menu,
+.openerp.database_block .secondary_menu,
+.openerp.database_block .oe-application,
+.openerp.database_block .login-container {
+ display: none;
+}
+
+.db_container {
+ width: 15%;
+ background: #666666;
+}
+
+ul.db_options li {
+ padding: 5px 0 10px 5px;
+ background: #949292; /* Old browsers */
+ background: -moz-linear-gradient(top, #949292 30%, #6d6b6b 95%, #282828 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(30%,#949292), color-stop(95%,#6d6b6b), color-stop(100%,#282828)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* W3C */
+ /* for ie9 */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */
+ border: none;
+ /* overriding jquery ui */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ display: block;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1px;
+ color: #EEEEEE;
+ cursor: pointer;
+ width: 196px;
+ font-size: 12px;
+}
+
+.db_option_table {
+ border: 1px solid #5A5858;
+ padding: 5px;
+ -moz-border-radius: 10px;
+}
+
+table.db_option_table input.required {
+ background-color: #D2D2FF !important;
+}
+
+.db_option_table input[type="text"], .db_option_table input[type="password"], .db_option_table select {
+ width: 300px;
+}
+
+.option_string {
+ font-weight: bold;
+ color: #555;
+ width: 100%;
+ text-align: center;
+ padding: 10px 0;
+ font-size: large;
+}
+
+label.error {
+ float: none;
+ color: red;
+ padding-left: .5em;
+ vertical-align: top;
+}
+
+/* Main*/
+.openerp .main_table {
+ width: 100%;
+ height: 100%;
+ background: #f0eeee;
+}
+
+/* Menu */
+.openerp .sf-menu {
+ margin-bottom: 0;
+}
+/*
+.sf-menu a {
+ padding: 5px 5px;
+}
+*/
+
+.openerp .menu {
+ height: 34px;
+ background: #cc4e45; /* Old browsers */
+ background: -moz-linear-gradient(top, #cc4e45 0%, #b52d20 8%, #7a211a 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cc4e45), color-stop(8%,#b52d20), color-stop(100%,#7a211a)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CC4E45', endColorstr='#7A211A',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */
+}
+.openerp .menu td {
+ text-align: center;
+ padding:0;
+}
+.openerp .menu a {
+ display:block;
+ min-width: 60px;
+ height: 20px;
+ margin: 3px 2px;
+ padding: 0 8px;
+
+ background: #bd5e54; /* Old browsers */
+ background: -moz-linear-gradient(top, #bd5e54 0%, #90322a 60%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bd5e54), color-stop(60%,#90322a)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
+
+ border: 1px solid #6E2A24;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+
+ color: #eee;
+ text-shadow: #222 0 1px 0;
+ text-decoration: none;
+ text-transform: uppercase;
+ line-height: 20px;
+ font-weight: bold;
+ font-size: 85%;
+
+ white-space: nowrap;
+}
+.openerp .menu a:hover,
+.openerp .menu a:focus,
+.openerp .menu a.active {
+ background: #c6c6c6; /* Old browsers */
+ background: -moz-linear-gradient(top, #c6c6c6 0%, #5c5c5c 7%, #969595 86%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#c6c6c6), color-stop(7%,#5c5c5c), color-stop(86%,#969595)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C6C6C6', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* W3C */
+ /* for ie */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', endColorstr='#969595',GradientType=0 ); /* IE6-9 */
+
+ color: #fff;
+}
+.openerp .oe-application-container {
+ height: 100%;
+}
+/* Secondary Menu */
+.openerp .secondary_menu {
+ width: 200px;
+ min-width: 200px;
+ border-right: 1px solid #3C3C3C;
+ border-bottom: 1px solid #5A5858;
+ background: #5A5858;
+ vertical-align: top;
+ height: 100%;
+}
+.openerp .secondary_menu .menu_content {
+ padding: 0;
+ border: none;
+ background: none;
+ overflow: hidden;
+}
+.openerp .secondary_menu h3 {
+ padding: 0 0 2px;
+ background: #949292; /* Old browsers */
+ background: -moz-linear-gradient(top, #949292 0%, #6d6b6b 87%, #282828 99%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#949292), color-stop(87%,#6d6b6b), color-stop(99%,#282828)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* W3C */
+ /* for ie9 */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */
+ border: none;
+ /* overriding jquery ui */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+}
+.openerp .secondary_menu h4 {
+ padding: 0 0 2px 10px;
+ border: none;
+ background: none;
+}
+.openerp .secondary_menu h3 span, .openerp .secondary_menu h4 span {
+ left: 0 !important;
+}
+.openerp .secondary_menu a {
+ display: block;
+ height: 20px;
+ padding: 0 5px;
+ line-height: 20px;
+ white-space: nowrap;
+ color: white;
+ text-decoration: none;
+ text-shadow: 0 1px 0 #333;
+}
+.openerp .secondary_menu a.leaf:hover,
+.openerp .secondary_menu a.leaf:active,
+.openerp .secondary_menu a.leaf.active,
+.openerp .secondary_menu h4:hover,
+.openerp .secondary_menu h4:active,
+.openerp .secondary_menu h4.active {
+ background: #ffffff; /* Old browsers */
+ background: -moz-linear-gradient(top, #ffffff 0%, #d8d8d8 11%, #afafaf 86%, #333333 91%, #5a5858 96%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(11%,#d8d8d8), color-stop(86%,#afafaf), color-stop(91%,#333333), color-stop(96%,#5a5858)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#5A5858',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */
+ /* overriding jquery ui */
+ -moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; border-top-right-radius: 0;
+ color: #3f3d3d;
+ text-shadow: #fff 0 1px 0;
+ border: none !important;
+}
+
+.openerp .secondary_menu h4:hover a,
+.openerp .secondary_menu h4:active a,
+.openerp .secondary_menu h4.active a {
+ color: #3f3d3d;
+ text-shadow: #fff 0 1px 0;
+ border: none !important;
+}
+.openerp div.submenu_accordion div.menu_content a span {
+ padding-left: 20px;
+}
+
+/* Header */
+.openerp .header {
+ height: 65px;
+ background: url("/web/static/src/img/header-background.png") repeat-x scroll left top transparent;
+ color: #FFFFFF;
+ letter-spacing: 0.5px;
+ text-shadow: 0 1px 0 #333333;
+}
+.openerp .company_logo_link {
+ display: block;
+ float: left;
+ height: 63px;
+ width: 200px;
+ border: 1px solid white;
+ border-right-color: black;
+ border-bottom-color: black;
+ background: #FFFFFF;
+ background: -moz-linear-gradient(top, #FFFFFF 0%, #CECECE 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(100%,#CECECE));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#CECECE',GradientType=0 );
+}
+.openerp .company_logo {
+ margin-top: 7px;
+ margin-left: 10px;
+ display: block;
+ background: url(/web/static/src/img/logo.png);
+ width:180px;
+ height:46px;
+}
+.openerp .header_title {
+ float: left;
+ font-size: 100%;
+ margin: 0;
+ padding: 4px 10px;
+ text-shadow: 0 1px 0 #111111;
+}
+.openerp .header_title small {
+ color: #ccc;
+ font-size: 90%;
+ font-weight: normal;
+}
+.openerp .header_corner {
+ float: right;
+}
+.openerp .header_corner .block {
+ float: left;
+ height: 34px;
+ line-height: 34px;
+ /*background: url(../images/top-sep-a.png) no-repeat;*/
+ border-left: 1px solid #6a6a6a;
+ background: #828282;
+ background: -moz-linear-gradient(top, #828282 0%, #4D4D4D 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#828282), color-stop(100%,#4D4D4D));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#828282', endColorstr='#4D4D4D',GradientType=0 );
+}
+.openerp .header_corner .block a {
+ display: block;
+ color: white;
+ text-decoration: none;
+ padding: 0 10px;
+}
+.openerp .header_corner .block a:hover {
+ background: #929292;
+ background: -moz-linear-gradient(top, #929292 0%, #4D4D4D 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#929292), color-stop(100%,#4D4D4D));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#929292', endColorstr='#4D4D4D',GradientType=0 );
+}
+.openerp .header_corner ul.block {
+ /*float: left;*/
+ list-style: none;
+ height: 34px;
+ margin: 0;
+ padding: 0 0 0 2px;
+ /*background: url(../images/top-sep-a.png) no-repeat;*/
+ line-height: 33px;
+ /*font-size: 1em;*/
+ /*text-transform: uppercase;*/
+}
+.openerp .header_corner ul.block li {
+ float: left;
+}
+.openerp .header_corner ul.block li a {
+ padding: 0 5px;
+ position: relative;
+ line-height: 32px;
+}
+.openerp .header_corner ul.block li a img {
+ vertical-align: middle;
+}
+.openerp .header_corner ul.block li a small {
+ position: absolute;
+ right: 0;
+ top: 5px;
+ padding: 1px 4px 2px;
+ background: rgba(0, 0, 0, 0.75);
+ border-radius: 7px;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+ line-height: 1em;
+ font-weight: bold;
+}
+
+/* Footer */
+.openerp div.oe_footer {
+ background: none repeat scroll 0 0 #CCCCCC;
+ overflow: hidden;
+ padding: 5px 0;
+ position: relative;
+ -moz-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.4);
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.4);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.4);
+}
+.openerp div.oe_footer p.oe_footer_powered {
+ left: 50%;
+ margin: 0;
+ padding: 0 15px;
+ color: #666666;
+ font-weight: bold;
+ font-size: 0.8em;
+ text-align: center;
+}
+.openerp div.oe_footer p.oe_footer_powered a {
+ text-decoration: none;
+ color: #666666;
+}
+
+/* Main Application */
+.openerp .oe-main-content,
+.openerp .oe-application {
+ padding: 0;
+ height: 100%;
+}
+
+.openerp h2.oe_view_title {
+ font-size: 175%;
+ font-weight: normal;
+ margin: 2px 0;
+ color: #252424;
+ text-shadow: white 0 1px 0;
+}
+
+/* View Manager */
+.openerp .oe_vm_switch {
+ float: right;
+}
+
+/* SearchView */
+.openerp .filter_label, .openerp .filter_icon {
+ border: 1px solid #666;
+ border-left-width: 0;
+ background: #F0F0F0;
+ background: -moz-linear-gradient(top, #F0F0F0 0%, #C0C0C0 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#C0C0C0));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#C0C0C0',GradientType=0 );
+}
+.openerp .filter_label:hover, .openerp .filter_icon:hover {
+ background: #F0F0F0;
+ background: -moz-linear-gradient(top, #F0F0F0 0%, #A1A7CE 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#A1A7CE));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#A1A7CE',GradientType=0 );
+}
+.openerp .filter_label:active, .openerp .filter_icon:active {
+ background: #AAAAAA;
+ background: -moz-linear-gradient(top, #999999 0%, #EEEEEE 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#999999), color-stop(100%,#EEEEEE));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#999999', endColorstr='#EEEEEE',GradientType=0 );
+}
+.openerp .filter_label.enabled, .openerp .filter_icon.enabled {
+ background: #AAAAAA;
+}
+.openerp .filter_icon {
+ height: 22px;
+ padding: 1px 2px 0 2px;
+ margin: 0;
+ vertical-align: bottom;
+}
+.openerp .filter_label {
+ font-weight: bold;
+ text-transform: uppercase;
+ text-shadow: #EEE 0 1px 0;
+ color: #4C4C4C;
+ white-space: nowrap;
+ min-height: 40px;
+ min-width: 75px;
+ padding: 2px 4px;
+ margin: 0;
+}
+.openerp .filter_label_group {
+ padding-right: 0.4em;
+ white-space: nowrap;
+}
+.openerp .filter_label_group button:first-child {
+ border-left: 1px solid #666;
+ -webkit-border-top-left-radius: 7px;
+ -webkit-border-bottom-left-radius: 7px;
+ -moz-border-radius-topleft: 7px;
+ -moz-border-radius-bottomleft: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+}
+.openerp .filter_label_group button:last-child {
+ -webkit-border-top-right-radius: 7px;
+ -webkit-border-bottom-right-radius: 7px;
+ -moz-border-radius-topright: 7px;
+ -moz-border-radius-bottomright: 7px;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+}
+
+.openerp .searchview_group_string {
+ display: block;
+ color: #7D7979;
+ font-weight: bold;
+ padding: 2px 0 2px 10px;
+ margin-top: 4px;
+ text-decoration: none;
+}
+.openerp .searchview_group_string:hover {
+ background-color: #ccc;
+}
+.openerp .searchview_group.folded .searchview_group_string {
+ background: url("/web/static/src/img/ui/group-folded.png") no-repeat scroll 0 50%;
+}
+.openerp .searchview_group.folded .searchview_group_content {
+ display: none;
+}
+.openerp .searchview_group.expanded .searchview_group_string {
+ background: url("/web/static/src/img/ui/group-expanded.png") no-repeat scroll 0 50%;
+}
+.openerp .searchview_group.expanded .searchview_group_content {
+ display: block;
+}
+.openerp .searchview_group_content {
+ padding-left: 10px;
+}
+
+.openerp .searchview_extended_group {
+ padding: 3px;
+ margin: 2px;
+}
+
+.openerp .searchview_extended_group .oe_adv_filters_and {
+ border-bottom: 1px solid #8E8E8E;
+ text-align: center;
+ margin-top: -10px;
+}
+.openerp .searchview_extended_group .oe_adv_filters_and span {
+ background: #F0EEEE;
+ position: relative;
+ top: 0.5em;
+ padding: 0 1em 0 1em;
+ color: #8E8E8E;
+}
+
+.openerp .searchview_extended_group.last_group .oe_adv_filters_and {
+ display: none;
+}
+
+.openerp .oe_search-view-custom-filter-btn span {
+ background: url(/web/static/src/img/icons/gtk-add.png) repeat-y;
+ padding-left: 18px;
+}
+
+.openerp .searchview_extended_add_proposition span {
+ font-size: 0.9em;
+ background: url(/web/static/src/img/icons/gtk-add.png) repeat-y;
+ padding-left: 18px;
+}
+
+.openerp .searchview_extended_delete_group {
+ float:right;
+ display: none;
+}
+
+.openerp .searchview_extended_delete_prop {
+ text-decoration: none;
+}
+
+.openerp .searchview_extended_delete_group span,
+.openerp .searchview_extended_delete_prop span {
+ font-size: 0.9em;
+ background: url(/web/static/src/img/icons/gtk-close.png) repeat-y;
+ padding-left: 18px;
+}
+/* List */
+.openerp .oe-listview table {
+ clear: right;
+ width: 100%;
+ border-spacing: 0;
+ border: 1px solid silver;
+}
+
+.openerp .oe-listview thead table {
+ width: 100%;
+ border: none;
+}
+.openerp .oe-listview tr.odd {
+ background-color: #f3f3f3;
+}
+.openerp .oe-listview tbody tr:hover {
+ background-color: #ecebf2;
+}
+.openerp .oe-listview tbody tr:hover {
+ background-color: #eae9f0;
+}
+.openerp .oe-listview thead table tr,
+.openerp .oe-listview thead table tr:hover {
+ background: none;
+}
+
+.openerp .oe-listview td,
+.openerp .oe-listview th {
+ vertical-align: middle;
+ text-align: left;
+}
+.openerp .oe-listview td.oe-record-delete {
+ text-align: right;
+}
+.openerp .oe-listview th.oe-sortable {
+ cursor: pointer;
+}
+.openerp .oe-listview th.oe-sortable .ui-icon {
+ height: 1em;
+ display: inline;
+ display: inline-block;
+}
+
+.openerp .oe-listview .oe-field-cell {
+ cursor: pointer;
+}
+.openerp .oe-listview .oe-field-cell button {
+ padding: 0;
+ border: none;
+ background: none;
+ width: 100%;
+}
+.openerp .oe-listview .oe-field-cell button:active {
+ opacity: 0.5;
+}
+.openerp .oe-listview .oe-field-cell button img {
+ cursor: pointer;
+}
+.openerp .oe-listview .oe-field-cell button img:hover {
+ opacity: 0.75;
+}
+
+.openerp .oe-listview th.oe-actions {
+ text-align: left;
+ white-space: nowrap;
+}
+.openerp .oe-listview th.oe-list-pager {
+ text-align: right;
+ white-space: nowrap;
+}
+.openerp .oe-list-pager .oe-pager-state {
+ cursor: pointer;
+}
+
+.openerp .oe-listview .oe-group-name {
+ padding-right: 1em;
+}
+.openerp .oe-listview .oe-group-name,
+.openerp .oe-listview .oe-group-pagination {
+ white-space: nowrap;
+}
+
+.openerp .oe-listview tfoot td {
+ padding: 3px 3px 0;
+}
+.openerp .oe-listview .oe-list-footer {
+ text-align: center;
+ white-space: nowrap;
+}
+.openerp .oe-listview .oe-list-footer span {
+ margin: 0 1em;
+}
+
+/** list rounded corners
+
+ rounded corners are a pain on tables: need to round not only table, but
+ also on the first and last children of the first and last row
+ */
+.openerp .oe-listview table.oe-listview-content {
+ -webkit-border-radius: 7px;
+ -moz-border-radius: 7px;
+ border-radius: 7px;
+}
+.openerp .oe-listview table.oe-listview-content thead tr:first-child th:first-child {
+ -webkit-border-top-left-radius: 7px;
+ -moz-border-radius-topleft: 7px;
+ border-top-left-radius: 7px;
+}
+.openerp .oe-listview table.oe-listview-content thead tr:first-child th:last-child {
+ -webkit-border-top-right-radius: 7px;
+ -moz-border-radius-topright: 7px;
+ border-top-right-radius: 7px;
+}
+.openerp .oe-listview table.oe-listview-content tfoot td:first-child,
+.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child th:first-child {
+ -webkit-border-bottom-left-radius: 7px;
+ -moz-border-radius-bottomleft: 7px;
+ border-bottom-left-radius: 7px;
+}
+.openerp .oe-listview table.oe-listview-content tfoot td:last-child,
+.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child td:last-child {
+ -webkit-border-bottom-right-radius: 7px;
+ -moz-border-radius-bottomright: 7px;
+ border-bottom-right-radius: 7px;
+}
+
+/* Notebook */
+.openerp .oe_form_notebook {
+ padding: 0;
+ background: none;
+ border-width: 0;
+}
+.openerp .oe_form_notebook ul.ui-tabs-nav {
+ padding-left: 0;
+ background: transparent;
+ border-width: 0 0 1px 0;
+ border-radius: 0;
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ line-height: 0.5em;
+}
+.openerp .oe_form_notebook ul.ui-tabs-nav li {
+ font-weight: bold;
+}
+.openerp .oe_form_notebook .ui-tabs-panel {
+ background: #f9f9f9;
+ border-width: 0 1px 1px 1px;
+}
+.openerp .oe_form_notebook .ui-tabs-selected {
+ background: #f9f9f9;
+}
+
+/* Form */
+.openerp table.oe_frame td {
+ color: #4c4c4c;
+}
+.openerp td.oe_form_frame_cell {
+ padding: 2px;
+}
+.openerp td.oe_form_frame_cell.oe_form_group {
+ padding: 0;
+}
+.openerp .required.error {
+ border: 1px solid #900;
+}
+.openerp .oe_form_buttons, .openerp .oe_list_buttons {
+ float: left;
+}
+.openerp .oe_form_pager, .openerp .oe_list_pager {
+ float: right;
+}
+
+.openerp label.oe_label_help, .openerp label.oe_label {
+ display: block;
+}
+.openerp label.oe_label_help {
+ cursor: help;
+}
+.openerp label.oe_label,
+.openerp label.oe_label_help {
+ text-align: right;
+ margin: 3px 0 0 10px;
+}
+.openerp label.oe_label_help span {
+ font-size: 80%;
+ color: darkgreen;
+ vertical-align:top;
+ position: relative;
+ top: -4px;
+ padding: 0 2px;
+}
+
+/* Inputs */
+.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms textarea {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 0 2px 0 2px;
+ border: 1px solid #999;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: white;
+ min-width: 90px;
+ color: #1f1f1f;
+}
+.openerp .oe_forms textarea {
+ resize:vertical;
+}
+.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .button {
+ height: 22px;
+}
+.openerp .oe_forms input.field_datetime {
+ min-width: 11em;
+}
+.openerp .oe_forms .button {
+ color: #4c4c4c;
+ white-space: nowrap;
+}
+.openerp .oe_forms .button span {
+ position: relative;
+ vertical-align: top;
+}
+.openerp img.ui-datepicker-trigger {
+ margin-left: -20px;
+ vertical-align: middle;
+ cursor: pointer;
+ position: relative;
+ top: -1px;
+}
+.openerp img.oe_field_translate {
+ margin-left: -21px;
+ vertical-align: top;
+ cursor: pointer;
+ position: relative;
+ top: 4px;
+}
+.openerp .oe_trad_field.touched {
+ border: 1px solid green !important;
+}
+
+/* http://www.quirksmode.org/dom/inputfile.html
+ * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
+ */
+.openerp .oe-binary-file-set {
+ overflow: hidden;
+ position: relative;
+}
+.openerp input.oe-binary-file {
+ z-index: 2;
+ line-height: 0;
+ font-size: 50px;
+ position: absolute;
+ /* Should be adjusted for all browsers */
+ top: -2px;
+ left: -700px;
+ opacity: 0;
+ filter: alpha(opacity = 0);
+ -ms-filter: "alpha(opacity=0)";
+ margin: 0;
+ padding:0;
+}
+
+/* Widgets */
+.openerp .separator {
+ border: 0 solid #666;
+}
+.openerp .separator.horizontal {
+ font-weight: bold;
+ border-bottom-width: 1px;
+ margin: 3px 4px 3px 1px;
+ height: 15px;
+}
+.openerp .oe_form_frame_cell.oe_form_separator_vertical {
+ border-left: 1px solid #666;
+}
+.openerp td.required input, .openerp td.required select {
+ background-color: #D2D2FF !important;
+}
+.openerp td.invalid input, .openerp td.invalid select, .openerp td.invalid textarea {
+ background-color: #F66 !important;
+ border: 1px solid #D00 !important;
+}
+.openerp div.oe-progressbar span {
+ position: absolute;
+ margin-left: 10px;
+ margin-top: 5px;
+ font-weight: bold;
+}
+
+/* jQuery UI override */
+.openerp .ui-widget {
+ font-size: 1em;
+}
+.openerp .oe_form_field_progressbar .ui-progressbar {
+ height: 22px;
+ font-size: 10px;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ border: 1px solid #999;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: white;
+ min-width: 90px;
+}
+
+/* Sidebar */
+.openerp .view-manager-main-table {
+ margin: 0;
+ width:100%;
+ border-collapse:collapse;
+ height:100%;
+}
+
+.openerp .view-manager-main-table tbody {
+ vertical-align: top;
+}
+
+.openerp .view-manager-main-content {
+ width: 100%;
+ padding: 6px;
+}
+
+.openerp .view-manager-main-sidebar {
+ width: 180px;
+ padding: 0;
+ margin: 0;
+}
+
+.openerp .sidebar-main-div {
+ height: 100%;
+ border-left: 1px solid #D2CFCF;
+}
+
+.openerp .sidebar-content {
+ padding: 0;
+ margin: 0;
+ width: 180px;
+ height: 100%;
+ font-size: 0.9em;
+}
+
+.openerp .closed-sidebar .sidebar-content {
+ width: 22px;
+}
+
+.openerp .closed-sidebar .sidebar-content {
+ display: none;
+}
+
+.openerp .sidebar-main-div a {
+ color: #555;
+ text-decoration: none;
+}
+
+.openerp .sidebar-main-div a:hover {
+ color: black;
+}
+
+.openerp .oe-sidebar-attachments-toolbar {
+ margin: 4px 0 0 4px;
+}
+.openerp .oe-sidebar-attachments-items {
+ clear: both;
+ padding-top: 5px !important;
+}
+.openerp .oe-sidebar-attachments-items li {
+ position: relative;
+ padding: 0 0 3px 10px !important;
+}
+.openerp .oe-sidebar-attachments-items li:hover {
+ background: #ddd;
+}
+.openerp .oe-sidebar-attachments-link {
+ display: block;
+ margin-right: 15px;
+ overflow: hidden;
+}
+.openerp .oe-sidebar-attachment-delete {
+ position: absolute;
+ right: 2px;
+ top: 1px;
+ overflow: hidden;
+ width: 15px;
+ height: 15px;
+ padding: 1px;
+ border-radius: 7px;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+}
+.openerp .oe-sidebar-attachment-delete:hover {
+ background-color: white;
+}
+
+.openerp .view-manager-main-sidebar h2 {
+ margin:0;
+ font-size: 1.15em;
+ color: #8E8E8E;
+ text-shadow: white 0 1px 0;
+ padding-left: 10px;
+ padding-right: 21px;
+ height: 21px;
+
+ background: #ffffff; /* Old browsers */
+ background: -moz-linear-gradient(top, #ffffff 0%, #ebe9e9 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ebe9e9)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EBE9E9',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
+
+ border: 1px solid #D2CFCF;
+ border-right-width: 0;
+ border-left-width: 0;
+}
+
+.openerp .view-manager-main-sidebar ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ display: block;
+}
+
+.openerp .view-manager-main-sidebar li {
+ display: block;
+ padding: 3px 3px 3px 10px;
+}
+
+.openerp .toggle-sidebar {
+ cursor: pointer;
+ border: 1px solid #D2CFCF;
+ display: block;
+ background: url(/web/static/src/img/toggle-a-bg.png);
+ width: 21px;
+ height: 21px;
+ z-index: 10;
+}
+.openerp .open-sidebar .toggle-sidebar {
+ margin-left: 158px;
+ background-position: 21px 0;
+ position: absolute;
+}
+.openerp .closed-sidebar .toggle-sidebar {
+ border-left: none;
+}
+.openerp li.oe_sidebar_print {
+ padding-left: 20px;
+ background: 1px 3px url(/web/static/src/img/icons/gtk-print.png) no-repeat;
+}
+
+.openerp.kitten-mode-activated .main_table {
+ background: url(http://placekitten.com/g/1500/800) repeat;
+}
+
+.openerp.kitten-mode-activated .header {
+ background: url(http://placekitten.com/g/211/65) repeat;
+}
+
+.openerp.kitten-mode-activated .secondary_menu {
+ background: url(http://placekitten.com/g/212/100) repeat;
+}
+
+.openerp.kitten-mode-activated .menu {
+ background: #828282;
+ background: -moz-linear-gradient(top, #828282 0%, #4D4D4D 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#828282), color-stop(100%,#4D4D4D));
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#828282', endColorstr='#4D4D4D',GradientType=0 );
+}
+.openerp.kitten-mode-activated .menu a {
+ background: none;
+}
+.openerp.kitten-mode-activated .menu span {
+ background: none;
+}
+.openerp.kitten-mode-activated .sidebar-content li a,
+.openerp.kitten-mode-activated .oe-application .view-manager-main-content h2.oe_view_title,
+.openerp.kitten-mode-activated .oe-application .view-manager-main-content a.searchview_group_string,
+.openerp.kitten-mode-activated .oe-application .view-manager-main-content label {
+ color: white;
+}
+.openerp.kitten-mode-activated .menu,
+.openerp.kitten-mode-activated .header_corner,
+.openerp.kitten-mode-activated .header_title,
+.openerp.kitten-mode-activated .secondary_menu div,
+.openerp.kitten-mode-activated .oe-application,
+.openerp.kitten-mode-activated .oe_footer,
+.openerp.kitten-mode-activated .loading,
+.openerp.kitten-mode-activated .ui-dialog {
+ opacity:0.8;
+ filter:alpha(opacity=80);
+}
+.openerp.kitten-mode-activated .header .company_logo {
+ background: url(http://placekitten.com/g/180/46);
+}
+.openerp.kitten-mode-activated .loading {
+ background: #828282;
+ border-color: #828282;
+}
+
+.openerp .oe-m2o {
+ padding-right: 20px;
+ white-space: nowrap;
+}
+.openerp .oe_forms .oe-m2o input[type="text"] {
+ padding-right: 20px;
+}
+.openerp .oe-m2o-drop-down-button {
+ margin-left: -23px;
+}
+.openerp .oe-m2o-drop-down-button img,
+.openerp .oe-m2o-cm-button img {
+ margin-bottom: -4px;
+ cursor: pointer;
+}
+.openerp .oe-m2o-cm-button img {
+ margin-left: 4px;
+}
+.openerp .oe-m2o-disabled-cm {
+ color: grey;
+}
+.parent_top {
+ vertical-align: text-top;
+}
+
+.openerp .oe-dialog-warning p {
+ padding-left: 1em;
+ font-size: 1.2em;
+ font-weight: bold;
+}
+
+.openerp .dhx_mini_calendar {
+ -moz-box-shadow: none;
+ -khtml-box-shadow: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.openerp .oe-treeview-table {
+ width: 100%;
+}
+.treeview-tr, .treeview-td {
+ cursor: pointer;
+ vertical-align: top;
+ text-align: left;
+}
+.treeview-tr span, .treeview-td span {
+ display: block;
+}
+.treeview-tr:first-of-type {
+ background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat;
+}
+.oe-open .treeview-tr:first-of-type {
+ background-image: url(/web/static/src/img/collapse.gif);
+}
+.treeview-tr:first-of-type span,
+.treeview-td:first-of-type span {
+ margin-left: 16px;
+}
+
+.treeview-header {
+ text-align: left;
+ vertical-align: top;
+}
+/* Shortcuts*/
+.oe-shortcut-toggle {
+ height: 20px;
+ padding: 0;
+ width: 24px;
+ cursor: pointer;
+ display: block;
+ background: url(/web/static/src/img/add-shortcut.png) no-repeat bottom;
+ float: left;
+}
+.oe-shortcut-remove{
+ background: url(/web/static/src/img/remove-shortcut.png) no-repeat bottom;
+}
+/* ================ */
+.oe-shortcuts {
+ position: absolute;
+
+ margin: 0;
+ padding: 6px 15px;
+ top: 37px;
+ left: 197px;
+ right: 0;
+ height: 17px;
+ line-height: 1.2;
+}
+.oe-shortcuts ul {
+ display: block;
+ overflow: hidden;
+ list-style: none;
+ white-space: nowrap;
+ padding: 0;
+ margin: 0;
+}
+.oe-shortcuts li {
+ cursor: pointer;
+ display: -moz-inline-stack;
+ display: inline-block;
+ display: inline; /*IE7 */
+ color: #fff;
+ text-align: center;
+ border-left: 1px solid #909090;
+ padding: 4px;
+ font-size: 90%;
+ font-weight: normal;
+}
+.oe-shortcuts li:first-child {
+ border-left: none;
+ padding-left: 0;
+}
+
+ul.oe-arrow-list {
+ padding-left: 0.5em;
+ margin: 0;
+}
+ul.oe-arrow-list li {
+ display: inline-block;
+ margin-left: -0.5em;
+}
+ul.oe-arrow-list li span {
+ vertical-align: top;
+ display: inline-block;
+ border-width:1em;
+ border-style:solid;
+ border-color: white;
+ line-height:0em;
+}
+ul.oe-arrow-list .oe-arrow-list-before {
+ border-left-color: rgba(0,0,0,0);
+ border-right-width:0;
+}
+ul.oe-arrow-list .oe-arrow-list-after {
+ border-color: rgba(0,0,0,0);
+ border-left-color: white;
+ border-right-width:0;
+}
+ul.oe-arrow-list li.oe-arrow-list-selected span {
+ border-color: #CFCCCC;
+}
+ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-before {
+ border-left-color: rgba(0,0,0,0);
+}
+ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
+ border-color: rgba(0,0,0,0);
+ border-left-color: #CFCCCC;
+}
diff --git a/addons/web/static/src/css/data_export.css b/addons/web/static/src/css/data_export.css
new file mode 100644
index 00000000000..149fcea81e6
--- /dev/null
+++ b/addons/web/static/src/css/data_export.css
@@ -0,0 +1,84 @@
+.openerp .oe-export {
+ width: 100%;
+}
+.openerp .oe_export_row tr{
+ background-color: #FFFFFF;
+ font-size: 0.8em;
+ height: 22px;
+}
+
+.openerp tr.ui-selected td {
+ background-color: #CCCCCC;
+}
+
+.openerp .oe_export_requiredfield {
+ background-color: #D2D2FF;
+}
+
+.openerp .oe_export_readonlyfield{
+ background-color: #999999;
+}
+
+.openerp .oe_export_row:hover{
+ background-color: #F3F3F3;
+}
+
+.openerp .oe_export_fields_selector_left {
+ width: 50%;
+}
+
+.openerp div#left_field_panel {
+ overflow: scroll;
+ width: 100%;
+ height: 400px;
+ border: solid #999999 1px;
+}
+.openerp div#left_field_panel table {
+ width: 100%;
+}
+
+.openerp .oe_export_fields_selector_center {
+ text-align: center;
+}
+.openerp .oe_export_fields_selector_center button {
+ white-space: nowrap;
+}
+
+.openerp .oe_export_fields_selector_right {
+ width: 45%;
+ height: 400px;
+}
+
+.openerp .oe_export_fields_selector_right select{
+ width: 100%;
+ height: 100%;
+}
+
+.openerp .oe_export_tree_header{
+ border: 0.5px solid #E3E3E3;
+ text-align: left;
+ white-space: nowrap;
+ padding: 4px 5px;
+ background: url(/web/static/src/img/header.gif);
+}
+
+
+.openerp table.tree_grid{
+ border: 1px solid #E3E3E3;
+ text-align: left;
+ white-space: nowrap;
+ background-color:#E3E3E3;
+ border-collapse: collapse;
+ width: 100%;
+}
+
+.openerp table.tree_grid a:hover {
+ color: blue;
+ border: none;
+}
+
+.openerp table.tree_grid a {
+ color: #5F5C5C;
+ border: none;
+ display: block;
+}
diff --git a/addons/web/static/src/img/accessories-archiver.png b/addons/web/static/src/img/accessories-archiver.png
new file mode 100644
index 00000000000..8bcbe4566bc
--- /dev/null
+++ b/addons/web/static/src/img/accessories-archiver.png
Binary files differ
diff --git a/addons/web/static/src/img/add-shortcut.png b/addons/web/static/src/img/add-shortcut.png
new file mode 100644
index 00000000000..bcc0a09eb45
--- /dev/null
+++ b/addons/web/static/src/img/add-shortcut.png
Binary files differ
diff --git a/addons/web/static/src/img/attachments-close.png b/addons/web/static/src/img/attachments-close.png
new file mode 100644
index 00000000000..14d645534b8
--- /dev/null
+++ b/addons/web/static/src/img/attachments-close.png
Binary files differ
diff --git a/addons/web/static/src/img/collapse.gif b/addons/web/static/src/img/collapse.gif
new file mode 100644
index 00000000000..759e72ebcfe
--- /dev/null
+++ b/addons/web/static/src/img/collapse.gif
Binary files differ
diff --git a/addons/web/static/src/img/db.png b/addons/web/static/src/img/db.png
new file mode 100644
index 00000000000..83e42df26b3
--- /dev/null
+++ b/addons/web/static/src/img/db.png
Binary files differ
diff --git a/addons/web/static/src/img/down-arrow.png b/addons/web/static/src/img/down-arrow.png
new file mode 100644
index 00000000000..b1288e52682
--- /dev/null
+++ b/addons/web/static/src/img/down-arrow.png
Binary files differ
diff --git a/addons/web/static/src/img/expand.gif b/addons/web/static/src/img/expand.gif
new file mode 100644
index 00000000000..ca98d0b5f2b
--- /dev/null
+++ b/addons/web/static/src/img/expand.gif
Binary files differ
diff --git a/addons/web/static/src/img/favicon.ico b/addons/web/static/src/img/favicon.ico
new file mode 100644
index 00000000000..a323cc21c00
--- /dev/null
+++ b/addons/web/static/src/img/favicon.ico
Binary files differ
diff --git a/addons/web/static/src/img/header-about.png b/addons/web/static/src/img/header-about.png
new file mode 100644
index 00000000000..b53e9a86ebe
--- /dev/null
+++ b/addons/web/static/src/img/header-about.png
Binary files differ
diff --git a/addons/web/static/src/img/header-background.png b/addons/web/static/src/img/header-background.png
new file mode 100644
index 00000000000..774b3954124
--- /dev/null
+++ b/addons/web/static/src/img/header-background.png
Binary files differ
diff --git a/addons/web/static/src/img/header-help.png b/addons/web/static/src/img/header-help.png
new file mode 100644
index 00000000000..19e9906fdef
--- /dev/null
+++ b/addons/web/static/src/img/header-help.png
Binary files differ
diff --git a/addons/web/static/src/img/header-home.png b/addons/web/static/src/img/header-home.png
new file mode 100644
index 00000000000..fd96742d15a
--- /dev/null
+++ b/addons/web/static/src/img/header-home.png
Binary files differ
diff --git a/addons/web/static/src/img/header-preferences.png b/addons/web/static/src/img/header-preferences.png
new file mode 100644
index 00000000000..6c978b49f55
--- /dev/null
+++ b/addons/web/static/src/img/header-preferences.png
Binary files differ
diff --git a/addons/web/static/src/img/header-requests.png b/addons/web/static/src/img/header-requests.png
new file mode 100644
index 00000000000..6577e7e6448
--- /dev/null
+++ b/addons/web/static/src/img/header-requests.png
Binary files differ
diff --git a/addons/web/static/src/img/header.gif b/addons/web/static/src/img/header.gif
new file mode 100644
index 00000000000..f40bd9c0f6a
--- /dev/null
+++ b/addons/web/static/src/img/header.gif
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ABOUT.png b/addons/web/static/src/img/icons/STOCK_ABOUT.png
new file mode 100644
index 00000000000..1b430a35758
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ABOUT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ADD.png b/addons/web/static/src/img/icons/STOCK_ADD.png
new file mode 100644
index 00000000000..70612c181c6
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ADD.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_APPLY.png b/addons/web/static/src/img/icons/STOCK_APPLY.png
new file mode 100644
index 00000000000..116f2e433bb
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_APPLY.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_BOLD.png b/addons/web/static/src/img/icons/STOCK_BOLD.png
new file mode 100644
index 00000000000..408f25aa20b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_BOLD.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CANCEL.png b/addons/web/static/src/img/icons/STOCK_CANCEL.png
new file mode 100644
index 00000000000..8cf6273281b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CANCEL.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CDROM.png b/addons/web/static/src/img/icons/STOCK_CDROM.png
new file mode 100644
index 00000000000..27e8edd8a0b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CDROM.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CLEAR.png b/addons/web/static/src/img/icons/STOCK_CLEAR.png
new file mode 100644
index 00000000000..b2874fb84fa
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CLEAR.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CLOSE.png b/addons/web/static/src/img/icons/STOCK_CLOSE.png
new file mode 100644
index 00000000000..4966974e178
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CLOSE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_COLOR_PICKER.png b/addons/web/static/src/img/icons/STOCK_COLOR_PICKER.png
new file mode 100644
index 00000000000..232d54f8f3b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_COLOR_PICKER.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CONNECT.png b/addons/web/static/src/img/icons/STOCK_CONNECT.png
new file mode 100644
index 00000000000..c820b54abcc
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CONNECT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CONVERT.png b/addons/web/static/src/img/icons/STOCK_CONVERT.png
new file mode 100644
index 00000000000..6288b964cc0
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CONVERT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_COPY.png b/addons/web/static/src/img/icons/STOCK_COPY.png
new file mode 100644
index 00000000000..3d68da606d2
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_COPY.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_CUT.png b/addons/web/static/src/img/icons/STOCK_CUT.png
new file mode 100644
index 00000000000..96681d26968
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_CUT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DELETE.png b/addons/web/static/src/img/icons/STOCK_DELETE.png
new file mode 100644
index 00000000000..879d6fd1cbe
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DELETE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DIALOG_AUTHENTICATION.png b/addons/web/static/src/img/icons/STOCK_DIALOG_AUTHENTICATION.png
new file mode 100644
index 00000000000..eb411112f83
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DIALOG_AUTHENTICATION.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DIALOG_ERROR.png b/addons/web/static/src/img/icons/STOCK_DIALOG_ERROR.png
new file mode 100644
index 00000000000..e97bc43504b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DIALOG_ERROR.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DIALOG_INFO.png b/addons/web/static/src/img/icons/STOCK_DIALOG_INFO.png
new file mode 100644
index 00000000000..ed46c3ecdb3
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DIALOG_INFO.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DIALOG_QUESTION.png b/addons/web/static/src/img/icons/STOCK_DIALOG_QUESTION.png
new file mode 100644
index 00000000000..ef68f43f43f
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DIALOG_QUESTION.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DIALOG_WARNING.png b/addons/web/static/src/img/icons/STOCK_DIALOG_WARNING.png
new file mode 100644
index 00000000000..65a4d2c7220
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DIALOG_WARNING.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DIRECTORY.png b/addons/web/static/src/img/icons/STOCK_DIRECTORY.png
new file mode 100644
index 00000000000..8e41b7878a9
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DIRECTORY.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DISCONNECT.png b/addons/web/static/src/img/icons/STOCK_DISCONNECT.png
new file mode 100644
index 00000000000..fd188701fc2
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DISCONNECT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DND.png b/addons/web/static/src/img/icons/STOCK_DND.png
new file mode 100644
index 00000000000..bf3b8068397
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DND.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_DND_MULTIPLE.png b/addons/web/static/src/img/icons/STOCK_DND_MULTIPLE.png
new file mode 100644
index 00000000000..aa4c65ad5b1
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_DND_MULTIPLE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_EDIT.png b/addons/web/static/src/img/icons/STOCK_EDIT.png
new file mode 100644
index 00000000000..53b7d0855ed
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_EDIT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_EXECUTE.png b/addons/web/static/src/img/icons/STOCK_EXECUTE.png
new file mode 100644
index 00000000000..eddc0f86b25
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_EXECUTE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_FILE.png b/addons/web/static/src/img/icons/STOCK_FILE.png
new file mode 100644
index 00000000000..fa157156bcc
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_FILE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_FIND.png b/addons/web/static/src/img/icons/STOCK_FIND.png
new file mode 100644
index 00000000000..7a23b0125b5
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_FIND.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_FIND_AND_REPLACE.png b/addons/web/static/src/img/icons/STOCK_FIND_AND_REPLACE.png
new file mode 100644
index 00000000000..b8d8eeec1b2
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_FIND_AND_REPLACE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_FLOPPY.png b/addons/web/static/src/img/icons/STOCK_FLOPPY.png
new file mode 100644
index 00000000000..7d8209cfb6f
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_FLOPPY.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_FULLSCREEN.png b/addons/web/static/src/img/icons/STOCK_FULLSCREEN.png
new file mode 100644
index 00000000000..8ddc31e7481
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_FULLSCREEN.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GOTO_BOTTOM.png b/addons/web/static/src/img/icons/STOCK_GOTO_BOTTOM.png
new file mode 100644
index 00000000000..be52840dee1
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GOTO_BOTTOM.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GOTO_FIRST.png b/addons/web/static/src/img/icons/STOCK_GOTO_FIRST.png
new file mode 100644
index 00000000000..3d00e36d696
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GOTO_FIRST.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GOTO_LAST.png b/addons/web/static/src/img/icons/STOCK_GOTO_LAST.png
new file mode 100644
index 00000000000..2028226996d
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GOTO_LAST.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GOTO_TOP.png b/addons/web/static/src/img/icons/STOCK_GOTO_TOP.png
new file mode 100644
index 00000000000..227a91e5157
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GOTO_TOP.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GO_BACK.png b/addons/web/static/src/img/icons/STOCK_GO_BACK.png
new file mode 100644
index 00000000000..568117dc170
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GO_BACK.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GO_DOWN.png b/addons/web/static/src/img/icons/STOCK_GO_DOWN.png
new file mode 100644
index 00000000000..5677cffe6a3
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GO_DOWN.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GO_FORWARD.png b/addons/web/static/src/img/icons/STOCK_GO_FORWARD.png
new file mode 100644
index 00000000000..fa89d31b734
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GO_FORWARD.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_GO_UP.png b/addons/web/static/src/img/icons/STOCK_GO_UP.png
new file mode 100644
index 00000000000..84f96fdfca2
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_GO_UP.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_HARDDISK.png b/addons/web/static/src/img/icons/STOCK_HARDDISK.png
new file mode 100644
index 00000000000..73e5ef0a82e
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_HARDDISK.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_HELP.png b/addons/web/static/src/img/icons/STOCK_HELP.png
new file mode 100644
index 00000000000..f8e17009dd6
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_HELP.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_HOME.png b/addons/web/static/src/img/icons/STOCK_HOME.png
new file mode 100644
index 00000000000..9d3d50d0fcb
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_HOME.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_INDENT.png b/addons/web/static/src/img/icons/STOCK_INDENT.png
new file mode 100644
index 00000000000..19f2669447d
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_INDENT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_INDEX.png b/addons/web/static/src/img/icons/STOCK_INDEX.png
new file mode 100644
index 00000000000..0b63cc25fa8
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_INDEX.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_INFO.png b/addons/web/static/src/img/icons/STOCK_INFO.png
new file mode 100644
index 00000000000..272019f5c99
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_INFO.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ITALIC.png b/addons/web/static/src/img/icons/STOCK_ITALIC.png
new file mode 100644
index 00000000000..26c57226a31
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ITALIC.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_JUMP_TO.png b/addons/web/static/src/img/icons/STOCK_JUMP_TO.png
new file mode 100644
index 00000000000..82d7896bdac
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_JUMP_TO.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_JUSTIFY_CENTER.png b/addons/web/static/src/img/icons/STOCK_JUSTIFY_CENTER.png
new file mode 100644
index 00000000000..d5f514298eb
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_JUSTIFY_CENTER.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_JUSTIFY_FILL.png b/addons/web/static/src/img/icons/STOCK_JUSTIFY_FILL.png
new file mode 100644
index 00000000000..5e2f5c73f30
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_JUSTIFY_FILL.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_JUSTIFY_LEFT.png b/addons/web/static/src/img/icons/STOCK_JUSTIFY_LEFT.png
new file mode 100644
index 00000000000..ecb76b117eb
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_JUSTIFY_LEFT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_JUSTIFY_RIGHT.png b/addons/web/static/src/img/icons/STOCK_JUSTIFY_RIGHT.png
new file mode 100644
index 00000000000..3cd4d161420
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_JUSTIFY_RIGHT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_LEAVE_FULLSCREEN.png b/addons/web/static/src/img/icons/STOCK_LEAVE_FULLSCREEN.png
new file mode 100644
index 00000000000..15bc8ab7d7b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_LEAVE_FULLSCREEN.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_FORWARD.png b/addons/web/static/src/img/icons/STOCK_MEDIA_FORWARD.png
new file mode 100644
index 00000000000..e5e198fbb79
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_FORWARD.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_NEXT.png b/addons/web/static/src/img/icons/STOCK_MEDIA_NEXT.png
new file mode 100644
index 00000000000..e0aa2431cf0
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_NEXT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_PAUSE.png b/addons/web/static/src/img/icons/STOCK_MEDIA_PAUSE.png
new file mode 100644
index 00000000000..6721994eb8d
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_PAUSE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_PLAY.png b/addons/web/static/src/img/icons/STOCK_MEDIA_PLAY.png
new file mode 100644
index 00000000000..b0832712c81
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_PLAY.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_PREVIOUS.png b/addons/web/static/src/img/icons/STOCK_MEDIA_PREVIOUS.png
new file mode 100644
index 00000000000..756899e0bc1
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_PREVIOUS.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_RECORD.png b/addons/web/static/src/img/icons/STOCK_MEDIA_RECORD.png
new file mode 100644
index 00000000000..904974c81e5
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_RECORD.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_REWIND.png b/addons/web/static/src/img/icons/STOCK_MEDIA_REWIND.png
new file mode 100644
index 00000000000..9c22d9e2778
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_REWIND.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MEDIA_STOP.png b/addons/web/static/src/img/icons/STOCK_MEDIA_STOP.png
new file mode 100644
index 00000000000..128cc2313ec
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MEDIA_STOP.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_MISSING_IMAGE.png b/addons/web/static/src/img/icons/STOCK_MISSING_IMAGE.png
new file mode 100644
index 00000000000..cc69ed33e4b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_MISSING_IMAGE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_NETWORK.png b/addons/web/static/src/img/icons/STOCK_NETWORK.png
new file mode 100644
index 00000000000..df94a515fec
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_NETWORK.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_NEW.png b/addons/web/static/src/img/icons/STOCK_NEW.png
new file mode 100644
index 00000000000..04a290fac7d
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_NEW.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_NO.png b/addons/web/static/src/img/icons/STOCK_NO.png
new file mode 100644
index 00000000000..047ddcd9289
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_NO.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_OK.png b/addons/web/static/src/img/icons/STOCK_OK.png
new file mode 100644
index 00000000000..7755b8769f0
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_OK.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_OPEN.png b/addons/web/static/src/img/icons/STOCK_OPEN.png
new file mode 100644
index 00000000000..9cdd8c66770
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_OPEN.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_PASTE.png b/addons/web/static/src/img/icons/STOCK_PASTE.png
new file mode 100644
index 00000000000..840f26c8b38
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_PASTE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_PREFERENCES.png b/addons/web/static/src/img/icons/STOCK_PREFERENCES.png
new file mode 100644
index 00000000000..9ba17a0ab20
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_PREFERENCES.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_PRINT.png b/addons/web/static/src/img/icons/STOCK_PRINT.png
new file mode 100644
index 00000000000..be0ed4efb44
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_PRINT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_PRINT_PREVIEW.png b/addons/web/static/src/img/icons/STOCK_PRINT_PREVIEW.png
new file mode 100644
index 00000000000..ab15fcbd307
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_PRINT_PREVIEW.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_PROPERTIES.png b/addons/web/static/src/img/icons/STOCK_PROPERTIES.png
new file mode 100644
index 00000000000..894415ec1ce
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_PROPERTIES.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_QUIT.png b/addons/web/static/src/img/icons/STOCK_QUIT.png
new file mode 100644
index 00000000000..50b5144660b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_QUIT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_REDO.png b/addons/web/static/src/img/icons/STOCK_REDO.png
new file mode 100644
index 00000000000..54055b3966d
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_REDO.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_REFRESH.png b/addons/web/static/src/img/icons/STOCK_REFRESH.png
new file mode 100644
index 00000000000..7474728b4c0
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_REFRESH.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_REMOVE.png b/addons/web/static/src/img/icons/STOCK_REMOVE.png
new file mode 100644
index 00000000000..c2b6e915f77
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_REMOVE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_REVERT_TO_SAVED.png b/addons/web/static/src/img/icons/STOCK_REVERT_TO_SAVED.png
new file mode 100644
index 00000000000..eaf54584edf
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_REVERT_TO_SAVED.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SAVE.png b/addons/web/static/src/img/icons/STOCK_SAVE.png
new file mode 100644
index 00000000000..c61836548a7
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SAVE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SAVE_AS.png b/addons/web/static/src/img/icons/STOCK_SAVE_AS.png
new file mode 100644
index 00000000000..1831e4e0a4b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SAVE_AS.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SELECT_COLOR.png b/addons/web/static/src/img/icons/STOCK_SELECT_COLOR.png
new file mode 100644
index 00000000000..12b015df107
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SELECT_COLOR.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SELECT_FONT.png b/addons/web/static/src/img/icons/STOCK_SELECT_FONT.png
new file mode 100644
index 00000000000..66e606313a5
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SELECT_FONT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SORT_ASCENDING.png b/addons/web/static/src/img/icons/STOCK_SORT_ASCENDING.png
new file mode 100644
index 00000000000..a648fa0d359
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SORT_ASCENDING.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SORT_DESCENDING.png b/addons/web/static/src/img/icons/STOCK_SORT_DESCENDING.png
new file mode 100644
index 00000000000..a90b588d797
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SORT_DESCENDING.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_SPELL_CHECK.png b/addons/web/static/src/img/icons/STOCK_SPELL_CHECK.png
new file mode 100644
index 00000000000..698f7c24a43
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_SPELL_CHECK.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_STOP.png b/addons/web/static/src/img/icons/STOCK_STOP.png
new file mode 100644
index 00000000000..2ee93ed6415
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_STOP.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_STRIKETHROUGH.png b/addons/web/static/src/img/icons/STOCK_STRIKETHROUGH.png
new file mode 100644
index 00000000000..1c11f214622
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_STRIKETHROUGH.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_UNDELETE.png b/addons/web/static/src/img/icons/STOCK_UNDELETE.png
new file mode 100644
index 00000000000..c44b940c03b
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_UNDELETE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_UNDERLINE.png b/addons/web/static/src/img/icons/STOCK_UNDERLINE.png
new file mode 100644
index 00000000000..7dbb5d7e60a
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_UNDERLINE.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_UNDO.png b/addons/web/static/src/img/icons/STOCK_UNDO.png
new file mode 100644
index 00000000000..7a50de0c61e
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_UNDO.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_UNINDENT.png b/addons/web/static/src/img/icons/STOCK_UNINDENT.png
new file mode 100644
index 00000000000..8ace914c1bd
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_UNINDENT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_YES.png b/addons/web/static/src/img/icons/STOCK_YES.png
new file mode 100644
index 00000000000..01fb373c251
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_YES.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ZOOM_100.png b/addons/web/static/src/img/icons/STOCK_ZOOM_100.png
new file mode 100644
index 00000000000..5193406b787
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ZOOM_100.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ZOOM_FIT.png b/addons/web/static/src/img/icons/STOCK_ZOOM_FIT.png
new file mode 100644
index 00000000000..1e70e619466
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ZOOM_FIT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ZOOM_IN.png b/addons/web/static/src/img/icons/STOCK_ZOOM_IN.png
new file mode 100644
index 00000000000..29e50e45d4a
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ZOOM_IN.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/STOCK_ZOOM_OUT.png b/addons/web/static/src/img/icons/STOCK_ZOOM_OUT.png
new file mode 100644
index 00000000000..0da5ee7ec13
--- /dev/null
+++ b/addons/web/static/src/img/icons/STOCK_ZOOM_OUT.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/color-picker.png b/addons/web/static/src/img/icons/color-picker.png
new file mode 100644
index 00000000000..765294c6bdd
--- /dev/null
+++ b/addons/web/static/src/img/icons/color-picker.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-about.png b/addons/web/static/src/img/icons/gtk-about.png
new file mode 100644
index 00000000000..1b430a35758
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-about.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-add.png b/addons/web/static/src/img/icons/gtk-add.png
new file mode 100644
index 00000000000..70612c181c6
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-add.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-apply.png b/addons/web/static/src/img/icons/gtk-apply.png
new file mode 100644
index 00000000000..116f2e433bb
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-apply.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-bold.png b/addons/web/static/src/img/icons/gtk-bold.png
new file mode 100644
index 00000000000..408f25aa20b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-bold.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-cancel.png b/addons/web/static/src/img/icons/gtk-cancel.png
new file mode 100644
index 00000000000..8cf6273281b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-cancel.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-cdrom.png b/addons/web/static/src/img/icons/gtk-cdrom.png
new file mode 100644
index 00000000000..27e8edd8a0b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-cdrom.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-clear.png b/addons/web/static/src/img/icons/gtk-clear.png
new file mode 100644
index 00000000000..b2874fb84fa
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-clear.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-close.png b/addons/web/static/src/img/icons/gtk-close.png
new file mode 100644
index 00000000000..4966974e178
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-close.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-color-picker.png b/addons/web/static/src/img/icons/gtk-color-picker.png
new file mode 100644
index 00000000000..232d54f8f3b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-color-picker.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-connect.png b/addons/web/static/src/img/icons/gtk-connect.png
new file mode 100644
index 00000000000..c820b54abcc
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-connect.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-convert.png b/addons/web/static/src/img/icons/gtk-convert.png
new file mode 100644
index 00000000000..6288b964cc0
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-convert.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-copy.png b/addons/web/static/src/img/icons/gtk-copy.png
new file mode 100644
index 00000000000..3d68da606d2
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-copy.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-cut.png b/addons/web/static/src/img/icons/gtk-cut.png
new file mode 100644
index 00000000000..96681d26968
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-cut.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-delete.png b/addons/web/static/src/img/icons/gtk-delete.png
new file mode 100644
index 00000000000..879d6fd1cbe
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-delete.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dialog-authentication.png b/addons/web/static/src/img/icons/gtk-dialog-authentication.png
new file mode 100644
index 00000000000..eb411112f83
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dialog-authentication.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dialog-error.png b/addons/web/static/src/img/icons/gtk-dialog-error.png
new file mode 100644
index 00000000000..e97bc43504b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dialog-error.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dialog-info.png b/addons/web/static/src/img/icons/gtk-dialog-info.png
new file mode 100644
index 00000000000..ed46c3ecdb3
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dialog-info.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dialog-question.png b/addons/web/static/src/img/icons/gtk-dialog-question.png
new file mode 100644
index 00000000000..ef68f43f43f
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dialog-question.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dialog-warning.png b/addons/web/static/src/img/icons/gtk-dialog-warning.png
new file mode 100644
index 00000000000..65a4d2c7220
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dialog-warning.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-directory-remote.png b/addons/web/static/src/img/icons/gtk-directory-remote.png
new file mode 100644
index 00000000000..34e737d7c07
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-directory-remote.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-directory.png b/addons/web/static/src/img/icons/gtk-directory.png
new file mode 100644
index 00000000000..8e41b7878a9
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-directory.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-disconnect.png b/addons/web/static/src/img/icons/gtk-disconnect.png
new file mode 100644
index 00000000000..fd188701fc2
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-disconnect.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dnd-multiple.png b/addons/web/static/src/img/icons/gtk-dnd-multiple.png
new file mode 100644
index 00000000000..aa4c65ad5b1
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dnd-multiple.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-dnd.png b/addons/web/static/src/img/icons/gtk-dnd.png
new file mode 100644
index 00000000000..bf3b8068397
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-dnd.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-edit.png b/addons/web/static/src/img/icons/gtk-edit.png
new file mode 100644
index 00000000000..53b7d0855ed
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-edit.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-execute.png b/addons/web/static/src/img/icons/gtk-execute.png
new file mode 100644
index 00000000000..eddc0f86b25
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-execute.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-file.png b/addons/web/static/src/img/icons/gtk-file.png
new file mode 100644
index 00000000000..fa157156bcc
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-file.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-find-and-replace.png b/addons/web/static/src/img/icons/gtk-find-and-replace.png
new file mode 100644
index 00000000000..b8d8eeec1b2
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-find-and-replace.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-find.png b/addons/web/static/src/img/icons/gtk-find.png
new file mode 100644
index 00000000000..7a23b0125b5
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-find.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-floppy.png b/addons/web/static/src/img/icons/gtk-floppy.png
new file mode 100644
index 00000000000..7d8209cfb6f
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-floppy.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-fullscreen.png b/addons/web/static/src/img/icons/gtk-fullscreen.png
new file mode 100644
index 00000000000..8ddc31e7481
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-fullscreen.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-go-back.png b/addons/web/static/src/img/icons/gtk-go-back.png
new file mode 100644
index 00000000000..568117dc170
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-go-back.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-go-down.png b/addons/web/static/src/img/icons/gtk-go-down.png
new file mode 100644
index 00000000000..5677cffe6a3
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-go-down.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-go-forward.png b/addons/web/static/src/img/icons/gtk-go-forward.png
new file mode 100644
index 00000000000..fa89d31b734
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-go-forward.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-go-up.png b/addons/web/static/src/img/icons/gtk-go-up.png
new file mode 100644
index 00000000000..84f96fdfca2
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-go-up.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-goto-bottom.png b/addons/web/static/src/img/icons/gtk-goto-bottom.png
new file mode 100644
index 00000000000..be52840dee1
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-goto-bottom.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-goto-first.png b/addons/web/static/src/img/icons/gtk-goto-first.png
new file mode 100644
index 00000000000..3d00e36d696
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-goto-first.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-goto-last.png b/addons/web/static/src/img/icons/gtk-goto-last.png
new file mode 100644
index 00000000000..2028226996d
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-goto-last.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-goto-top.png b/addons/web/static/src/img/icons/gtk-goto-top.png
new file mode 100644
index 00000000000..227a91e5157
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-goto-top.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-harddisk.png b/addons/web/static/src/img/icons/gtk-harddisk.png
new file mode 100644
index 00000000000..73e5ef0a82e
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-harddisk.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-help.png b/addons/web/static/src/img/icons/gtk-help.png
new file mode 100644
index 00000000000..f8e17009dd6
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-help.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-home.png b/addons/web/static/src/img/icons/gtk-home.png
new file mode 100644
index 00000000000..9d3d50d0fcb
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-home.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-indent.png b/addons/web/static/src/img/icons/gtk-indent.png
new file mode 100644
index 00000000000..19f2669447d
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-indent.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-index.png b/addons/web/static/src/img/icons/gtk-index.png
new file mode 100644
index 00000000000..0b63cc25fa8
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-index.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-info.png b/addons/web/static/src/img/icons/gtk-info.png
new file mode 100644
index 00000000000..272019f5c99
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-info.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-italic.png b/addons/web/static/src/img/icons/gtk-italic.png
new file mode 100644
index 00000000000..26c57226a31
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-italic.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-jump-to.png b/addons/web/static/src/img/icons/gtk-jump-to.png
new file mode 100644
index 00000000000..82d7896bdac
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-jump-to.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-justify-center.png b/addons/web/static/src/img/icons/gtk-justify-center.png
new file mode 100644
index 00000000000..d5f514298eb
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-justify-center.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-justify-fill.png b/addons/web/static/src/img/icons/gtk-justify-fill.png
new file mode 100644
index 00000000000..5e2f5c73f30
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-justify-fill.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-justify-left.png b/addons/web/static/src/img/icons/gtk-justify-left.png
new file mode 100644
index 00000000000..ecb76b117eb
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-justify-left.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-justify-right.png b/addons/web/static/src/img/icons/gtk-justify-right.png
new file mode 100644
index 00000000000..3cd4d161420
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-justify-right.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-leave-fullscreen.png b/addons/web/static/src/img/icons/gtk-leave-fullscreen.png
new file mode 100644
index 00000000000..15bc8ab7d7b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-leave-fullscreen.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-forward.png b/addons/web/static/src/img/icons/gtk-media-forward.png
new file mode 100644
index 00000000000..e5e198fbb79
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-forward.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-next.png b/addons/web/static/src/img/icons/gtk-media-next.png
new file mode 100644
index 00000000000..e0aa2431cf0
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-next.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-pause.png b/addons/web/static/src/img/icons/gtk-media-pause.png
new file mode 100644
index 00000000000..6721994eb8d
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-pause.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-play.png b/addons/web/static/src/img/icons/gtk-media-play.png
new file mode 100644
index 00000000000..b0832712c81
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-play.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-previous.png b/addons/web/static/src/img/icons/gtk-media-previous.png
new file mode 100644
index 00000000000..756899e0bc1
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-previous.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-record.png b/addons/web/static/src/img/icons/gtk-media-record.png
new file mode 100644
index 00000000000..904974c81e5
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-record.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-rewind.png b/addons/web/static/src/img/icons/gtk-media-rewind.png
new file mode 100644
index 00000000000..9c22d9e2778
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-rewind.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-media-stop.png b/addons/web/static/src/img/icons/gtk-media-stop.png
new file mode 100644
index 00000000000..128cc2313ec
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-media-stop.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-missing-image.png b/addons/web/static/src/img/icons/gtk-missing-image.png
new file mode 100644
index 00000000000..cc69ed33e4b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-missing-image.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-network.png b/addons/web/static/src/img/icons/gtk-network.png
new file mode 100644
index 00000000000..df94a515fec
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-network.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-new.png b/addons/web/static/src/img/icons/gtk-new.png
new file mode 100644
index 00000000000..04a290fac7d
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-new.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-no.png b/addons/web/static/src/img/icons/gtk-no.png
new file mode 100644
index 00000000000..047ddcd9289
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-no.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-ok.png b/addons/web/static/src/img/icons/gtk-ok.png
new file mode 100644
index 00000000000..7755b8769f0
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-ok.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-open.png b/addons/web/static/src/img/icons/gtk-open.png
new file mode 100644
index 00000000000..9cdd8c66770
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-open.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-paste-v.png b/addons/web/static/src/img/icons/gtk-paste-v.png
new file mode 100644
index 00000000000..76ec896f70e
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-paste-v.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-paste.png b/addons/web/static/src/img/icons/gtk-paste.png
new file mode 100644
index 00000000000..840f26c8b38
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-paste.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-preferences.png b/addons/web/static/src/img/icons/gtk-preferences.png
new file mode 100644
index 00000000000..9ba17a0ab20
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-preferences.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-print-preview.png b/addons/web/static/src/img/icons/gtk-print-preview.png
new file mode 100644
index 00000000000..ab15fcbd307
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-print-preview.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-print.png b/addons/web/static/src/img/icons/gtk-print.png
new file mode 100644
index 00000000000..be0ed4efb44
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-print.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-properties.png b/addons/web/static/src/img/icons/gtk-properties.png
new file mode 100644
index 00000000000..894415ec1ce
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-properties.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-quit.png b/addons/web/static/src/img/icons/gtk-quit.png
new file mode 100644
index 00000000000..50b5144660b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-quit.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-redo.png b/addons/web/static/src/img/icons/gtk-redo.png
new file mode 100644
index 00000000000..54055b3966d
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-redo.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-refresh.png b/addons/web/static/src/img/icons/gtk-refresh.png
new file mode 100644
index 00000000000..7474728b4c0
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-refresh.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-remove.png b/addons/web/static/src/img/icons/gtk-remove.png
new file mode 100644
index 00000000000..c2b6e915f77
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-remove.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-revert-to-saved.png b/addons/web/static/src/img/icons/gtk-revert-to-saved.png
new file mode 100644
index 00000000000..eaf54584edf
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-revert-to-saved.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-save-as.png b/addons/web/static/src/img/icons/gtk-save-as.png
new file mode 100644
index 00000000000..1831e4e0a4b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-save-as.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-save.png b/addons/web/static/src/img/icons/gtk-save.png
new file mode 100644
index 00000000000..c61836548a7
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-save.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-select-color.png b/addons/web/static/src/img/icons/gtk-select-color.png
new file mode 100644
index 00000000000..12b015df107
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-select-color.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-select-font.png b/addons/web/static/src/img/icons/gtk-select-font.png
new file mode 100644
index 00000000000..66e606313a5
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-select-font.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-sort-ascending.png b/addons/web/static/src/img/icons/gtk-sort-ascending.png
new file mode 100644
index 00000000000..a648fa0d359
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-sort-ascending.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-sort-descending.png b/addons/web/static/src/img/icons/gtk-sort-descending.png
new file mode 100644
index 00000000000..a90b588d797
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-sort-descending.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-spell-check.png b/addons/web/static/src/img/icons/gtk-spell-check.png
new file mode 100644
index 00000000000..698f7c24a43
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-spell-check.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-stop.png b/addons/web/static/src/img/icons/gtk-stop.png
new file mode 100644
index 00000000000..2ee93ed6415
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-stop.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-strikethrough.png b/addons/web/static/src/img/icons/gtk-strikethrough.png
new file mode 100644
index 00000000000..1c11f214622
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-strikethrough.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-undelete.png b/addons/web/static/src/img/icons/gtk-undelete.png
new file mode 100644
index 00000000000..c44b940c03b
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-undelete.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-underline.png b/addons/web/static/src/img/icons/gtk-underline.png
new file mode 100644
index 00000000000..7dbb5d7e60a
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-underline.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-undo.png b/addons/web/static/src/img/icons/gtk-undo.png
new file mode 100644
index 00000000000..7a50de0c61e
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-undo.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-unindent.png b/addons/web/static/src/img/icons/gtk-unindent.png
new file mode 100644
index 00000000000..8ace914c1bd
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-unindent.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-yes.png b/addons/web/static/src/img/icons/gtk-yes.png
new file mode 100644
index 00000000000..01fb373c251
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-yes.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-zoom-100.png b/addons/web/static/src/img/icons/gtk-zoom-100.png
new file mode 100644
index 00000000000..5193406b787
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-zoom-100.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-zoom-fit.png b/addons/web/static/src/img/icons/gtk-zoom-fit.png
new file mode 100644
index 00000000000..1e70e619466
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-zoom-fit.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-zoom-in.png b/addons/web/static/src/img/icons/gtk-zoom-in.png
new file mode 100644
index 00000000000..29e50e45d4a
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-zoom-in.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/gtk-zoom-out.png b/addons/web/static/src/img/icons/gtk-zoom-out.png
new file mode 100644
index 00000000000..0da5ee7ec13
--- /dev/null
+++ b/addons/web/static/src/img/icons/gtk-zoom-out.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/index1.jpeg b/addons/web/static/src/img/icons/index1.jpeg
new file mode 100644
index 00000000000..f43c68d79ec
--- /dev/null
+++ b/addons/web/static/src/img/icons/index1.jpeg
Binary files differ
diff --git a/addons/web/static/src/img/icons/index2.jpeg b/addons/web/static/src/img/icons/index2.jpeg
new file mode 100644
index 00000000000..ec9d1eb6d3c
--- /dev/null
+++ b/addons/web/static/src/img/icons/index2.jpeg
Binary files differ
diff --git a/addons/web/static/src/img/icons/lead-stage-lost.png b/addons/web/static/src/img/icons/lead-stage-lost.png
new file mode 100644
index 00000000000..e1f98a26b59
--- /dev/null
+++ b/addons/web/static/src/img/icons/lead-stage-lost.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/lead-stage-pending.png b/addons/web/static/src/img/icons/lead-stage-pending.png
new file mode 100644
index 00000000000..9e9544ee178
--- /dev/null
+++ b/addons/web/static/src/img/icons/lead-stage-pending.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/lead-stage-won.png b/addons/web/static/src/img/icons/lead-stage-won.png
new file mode 100644
index 00000000000..02effd5f14c
--- /dev/null
+++ b/addons/web/static/src/img/icons/lead-stage-won.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/star-off.png b/addons/web/static/src/img/icons/star-off.png
new file mode 100644
index 00000000000..7cd0afd4f03
--- /dev/null
+++ b/addons/web/static/src/img/icons/star-off.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/star-on.png b/addons/web/static/src/img/icons/star-on.png
new file mode 100644
index 00000000000..4f2295e1395
--- /dev/null
+++ b/addons/web/static/src/img/icons/star-on.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock.png b/addons/web/static/src/img/icons/stock.png
new file mode 100644
index 00000000000..ca38181db90
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock_calendar.png b/addons/web/static/src/img/icons/stock_calendar.png
new file mode 100644
index 00000000000..99a1f3f9ef1
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock_calendar.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock_gantt.png b/addons/web/static/src/img/icons/stock_gantt.png
new file mode 100644
index 00000000000..585761b9220
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock_gantt.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock_graph.png b/addons/web/static/src/img/icons/stock_graph.png
new file mode 100644
index 00000000000..4d8310621ea
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock_graph.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock_log.png b/addons/web/static/src/img/icons/stock_log.png
new file mode 100644
index 00000000000..32af4dd6901
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock_log.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock_person.png b/addons/web/static/src/img/icons/stock_person.png
new file mode 100644
index 00000000000..202cf0ee6c5
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock_person.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/stock_translate.png b/addons/web/static/src/img/icons/stock_translate.png
new file mode 100644
index 00000000000..5ab41d49343
--- /dev/null
+++ b/addons/web/static/src/img/icons/stock_translate.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-accessories-archiver+.png b/addons/web/static/src/img/icons/terp-accessories-archiver+.png
new file mode 100644
index 00000000000..14d6d02536e
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-accessories-archiver+.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-accessories-archiver-minus.png b/addons/web/static/src/img/icons/terp-accessories-archiver-minus.png
new file mode 100644
index 00000000000..024c8f692d8
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-accessories-archiver-minus.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-accessories-archiver.png b/addons/web/static/src/img/icons/terp-accessories-archiver.png
new file mode 100644
index 00000000000..8bcbe4566bc
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-accessories-archiver.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-account.png b/addons/web/static/src/img/icons/terp-account.png
new file mode 100644
index 00000000000..30dea82a105
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-account.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-administration.png b/addons/web/static/src/img/icons/terp-administration.png
new file mode 100644
index 00000000000..ab129b2e4b3
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-administration.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-calendar.png b/addons/web/static/src/img/icons/terp-calendar.png
new file mode 100644
index 00000000000..37206565792
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-calendar.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-call-start.png b/addons/web/static/src/img/icons/terp-call-start.png
new file mode 100644
index 00000000000..602a1cdd4b8
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-call-start.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-camera_test.png b/addons/web/static/src/img/icons/terp-camera_test.png
new file mode 100644
index 00000000000..e97e0416de3
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-camera_test.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-check.png b/addons/web/static/src/img/icons/terp-check.png
new file mode 100644
index 00000000000..003b09fdeb9
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-check.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-crm.png b/addons/web/static/src/img/icons/terp-crm.png
new file mode 100644
index 00000000000..fdac61ca92d
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-crm.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-dialog-close.png b/addons/web/static/src/img/icons/terp-dialog-close.png
new file mode 100644
index 00000000000..8f51ec05fd6
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-dialog-close.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-document-new.png b/addons/web/static/src/img/icons/terp-document-new.png
new file mode 100644
index 00000000000..2815cbb403f
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-document-new.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-dolar.png b/addons/web/static/src/img/icons/terp-dolar.png
new file mode 100644
index 00000000000..bca7021c82f
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-dolar.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-dolar_ok!.png b/addons/web/static/src/img/icons/terp-dolar_ok!.png
new file mode 100644
index 00000000000..b1005aae7b9
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-dolar_ok!.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-emblem-important.png b/addons/web/static/src/img/icons/terp-emblem-important.png
new file mode 100644
index 00000000000..a8321066abb
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-emblem-important.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-face-plain.png b/addons/web/static/src/img/icons/terp-face-plain.png
new file mode 100644
index 00000000000..ea90aaa7ef4
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-face-plain.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-folder-blue.png b/addons/web/static/src/img/icons/terp-folder-blue.png
new file mode 100644
index 00000000000..addc480d49a
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-folder-blue.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-folder-green.png b/addons/web/static/src/img/icons/terp-folder-green.png
new file mode 100644
index 00000000000..206cd39603e
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-folder-green.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-folder-orange.png b/addons/web/static/src/img/icons/terp-folder-orange.png
new file mode 100644
index 00000000000..726dbd7f00e
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-folder-orange.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-folder-violet.png b/addons/web/static/src/img/icons/terp-folder-violet.png
new file mode 100644
index 00000000000..c6f5cfb87ff
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-folder-violet.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-folder-yellow.png b/addons/web/static/src/img/icons/terp-folder-yellow.png
new file mode 100644
index 00000000000..cd7295dcdd7
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-folder-yellow.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gdu-smart-failing.png b/addons/web/static/src/img/icons/terp-gdu-smart-failing.png
new file mode 100644
index 00000000000..a4448fd553e
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gdu-smart-failing.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gnome-cpu-frequency-applet+.png b/addons/web/static/src/img/icons/terp-gnome-cpu-frequency-applet+.png
new file mode 100644
index 00000000000..23e246f3be9
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gnome-cpu-frequency-applet+.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-go-home.png b/addons/web/static/src/img/icons/terp-go-home.png
new file mode 100644
index 00000000000..912256bf7a7
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-go-home.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-go-month.png b/addons/web/static/src/img/icons/terp-go-month.png
new file mode 100644
index 00000000000..cf5e305053e
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-go-month.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-go-today.png b/addons/web/static/src/img/icons/terp-go-today.png
new file mode 100644
index 00000000000..2a4dbeed49a
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-go-today.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-go-week.png b/addons/web/static/src/img/icons/terp-go-week.png
new file mode 100644
index 00000000000..b3ce6f562b2
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-go-week.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-go-year.png b/addons/web/static/src/img/icons/terp-go-year.png
new file mode 100644
index 00000000000..f45efc9dd0c
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-go-year.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-graph.png b/addons/web/static/src/img/icons/terp-graph.png
new file mode 100644
index 00000000000..30dea82a105
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-graph.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-go-back-ltr.png b/addons/web/static/src/img/icons/terp-gtk-go-back-ltr.png
new file mode 100644
index 00000000000..a76138d2e0d
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-go-back-ltr.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-go-back-rtl.png b/addons/web/static/src/img/icons/terp-gtk-go-back-rtl.png
new file mode 100644
index 00000000000..10d10b582fe
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-go-back-rtl.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-jump-to-ltr.png b/addons/web/static/src/img/icons/terp-gtk-jump-to-ltr.png
new file mode 100644
index 00000000000..fa517749d10
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-jump-to-ltr.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-jump-to-rtl.png b/addons/web/static/src/img/icons/terp-gtk-jump-to-rtl.png
new file mode 100644
index 00000000000..7b5785c4963
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-jump-to-rtl.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-media-pause.png b/addons/web/static/src/img/icons/terp-gtk-media-pause.png
new file mode 100644
index 00000000000..2896ad8e27f
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-media-pause.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-select-all.png b/addons/web/static/src/img/icons/terp-gtk-select-all.png
new file mode 100644
index 00000000000..b71a6493791
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-select-all.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-gtk-stop.png b/addons/web/static/src/img/icons/terp-gtk-stop.png
new file mode 100644
index 00000000000..5fe021e19df
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-gtk-stop.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-hr.png b/addons/web/static/src/img/icons/terp-hr.png
new file mode 100644
index 00000000000..ba0241e6362
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-hr.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-idea.png b/addons/web/static/src/img/icons/terp-idea.png
new file mode 100644
index 00000000000..fd5e2a25f14
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-idea.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-locked.png b/addons/web/static/src/img/icons/terp-locked.png
new file mode 100644
index 00000000000..cd2b4c2c9c2
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-locked.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-mail-.png b/addons/web/static/src/img/icons/terp-mail-.png
new file mode 100644
index 00000000000..cbc85e4c000
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-mail-.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-mail-forward.png b/addons/web/static/src/img/icons/terp-mail-forward.png
new file mode 100644
index 00000000000..3d4e694b6dc
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-mail-forward.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-mail-message-new.png b/addons/web/static/src/img/icons/terp-mail-message-new.png
new file mode 100644
index 00000000000..25b4d5b5d50
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-mail-message-new.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-mail-replied.png b/addons/web/static/src/img/icons/terp-mail-replied.png
new file mode 100644
index 00000000000..6615f4352cc
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-mail-replied.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-mail_delete.png b/addons/web/static/src/img/icons/terp-mail_delete.png
new file mode 100644
index 00000000000..90fb5239f02
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-mail_delete.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-marketing.png b/addons/web/static/src/img/icons/terp-marketing.png
new file mode 100644
index 00000000000..1b04b599734
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-marketing.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-mrp.png b/addons/web/static/src/img/icons/terp-mrp.png
new file mode 100644
index 00000000000..c2b4ea31ec3
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-mrp.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-partner.png b/addons/web/static/src/img/icons/terp-partner.png
new file mode 100644
index 00000000000..aab206a1d42
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-partner.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-personal+.png b/addons/web/static/src/img/icons/terp-personal+.png
new file mode 100644
index 00000000000..8afa4d7041d
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-personal+.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-personal-.png b/addons/web/static/src/img/icons/terp-personal-.png
new file mode 100644
index 00000000000..a2554df3615
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-personal-.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-personal.png b/addons/web/static/src/img/icons/terp-personal.png
new file mode 100644
index 00000000000..0890c4d0e51
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-personal.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-product.png b/addons/web/static/src/img/icons/terp-product.png
new file mode 100644
index 00000000000..99f58d95a8b
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-product.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-project.png b/addons/web/static/src/img/icons/terp-project.png
new file mode 100644
index 00000000000..cd95ae84e43
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-project.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-purchase.png b/addons/web/static/src/img/icons/terp-purchase.png
new file mode 100644
index 00000000000..1e801f57485
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-purchase.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-rating-rated.png b/addons/web/static/src/img/icons/terp-rating-rated.png
new file mode 100644
index 00000000000..9bff03fe584
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-rating-rated.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-report.png b/addons/web/static/src/img/icons/terp-report.png
new file mode 100644
index 00000000000..ada36a2de24
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-report.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-sale.png b/addons/web/static/src/img/icons/terp-sale.png
new file mode 100644
index 00000000000..ba0241e6362
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-sale.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stage.png b/addons/web/static/src/img/icons/terp-stage.png
new file mode 100644
index 00000000000..591c1594f78
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stage.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock.png b/addons/web/static/src/img/icons/terp-stock.png
new file mode 100644
index 00000000000..0365dfdb8e1
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock_align_left_24.png b/addons/web/static/src/img/icons/terp-stock_align_left_24.png
new file mode 100644
index 00000000000..844367bb1a7
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock_align_left_24.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock_effects-object-colorize.png b/addons/web/static/src/img/icons/terp-stock_effects-object-colorize.png
new file mode 100644
index 00000000000..0ffd95a740a
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock_effects-object-colorize.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock_format-default.png b/addons/web/static/src/img/icons/terp-stock_format-default.png
new file mode 100644
index 00000000000..e44b2b26be5
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock_format-default.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock_format-scientific.png b/addons/web/static/src/img/icons/terp-stock_format-scientific.png
new file mode 100644
index 00000000000..01f83950804
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock_format-scientific.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock_symbol-selection.png b/addons/web/static/src/img/icons/terp-stock_symbol-selection.png
new file mode 100644
index 00000000000..5773be57c9b
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock_symbol-selection.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-stock_zoom.png b/addons/web/static/src/img/icons/terp-stock_zoom.png
new file mode 100644
index 00000000000..e96f05e5905
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-stock_zoom.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-tools.png b/addons/web/static/src/img/icons/terp-tools.png
new file mode 100644
index 00000000000..379f7617427
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-tools.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/terp-translate.png b/addons/web/static/src/img/icons/terp-translate.png
new file mode 100644
index 00000000000..5ab41d49343
--- /dev/null
+++ b/addons/web/static/src/img/icons/terp-translate.png
Binary files differ
diff --git a/addons/web/static/src/img/iconset-d-drop.gif b/addons/web/static/src/img/iconset-d-drop.gif
new file mode 100644
index 00000000000..4907a927619
--- /dev/null
+++ b/addons/web/static/src/img/iconset-d-drop.gif
Binary files differ
diff --git a/addons/web/static/src/img/logo.png b/addons/web/static/src/img/logo.png
new file mode 100644
index 00000000000..8f1c5c6085f
--- /dev/null
+++ b/addons/web/static/src/img/logo.png
Binary files differ
diff --git a/addons/web/static/src/img/partner.png b/addons/web/static/src/img/partner.png
new file mode 100644
index 00000000000..aab206a1d42
--- /dev/null
+++ b/addons/web/static/src/img/partner.png
Binary files differ
diff --git a/addons/web/static/src/img/placeholder.png b/addons/web/static/src/img/placeholder.png
new file mode 100644
index 00000000000..25af75ee815
--- /dev/null
+++ b/addons/web/static/src/img/placeholder.png
Binary files differ
diff --git a/addons/web/static/src/img/product.png b/addons/web/static/src/img/product.png
new file mode 100644
index 00000000000..99f58d95a8b
--- /dev/null
+++ b/addons/web/static/src/img/product.png
Binary files differ
diff --git a/addons/web/static/src/img/remove-shortcut.png b/addons/web/static/src/img/remove-shortcut.png
new file mode 100644
index 00000000000..9bff03fe584
--- /dev/null
+++ b/addons/web/static/src/img/remove-shortcut.png
Binary files differ
diff --git a/addons/web/static/src/img/stock_person.png b/addons/web/static/src/img/stock_person.png
new file mode 100644
index 00000000000..202cf0ee6c5
--- /dev/null
+++ b/addons/web/static/src/img/stock_person.png
Binary files differ
diff --git a/addons/web/static/src/img/throbber.gif b/addons/web/static/src/img/throbber.gif
new file mode 100644
index 00000000000..ded8d36d486
--- /dev/null
+++ b/addons/web/static/src/img/throbber.gif
Binary files differ
diff --git a/addons/web/static/src/img/throbber2.gif b/addons/web/static/src/img/throbber2.gif
new file mode 100644
index 00000000000..5d2057ae0e7
--- /dev/null
+++ b/addons/web/static/src/img/throbber2.gif
Binary files differ
diff --git a/addons/web/static/src/img/toggle-a-bg.png b/addons/web/static/src/img/toggle-a-bg.png
new file mode 100644
index 00000000000..b9837ab233e
--- /dev/null
+++ b/addons/web/static/src/img/toggle-a-bg.png
Binary files differ
diff --git a/addons/web/static/src/img/ui/field_calendar.png b/addons/web/static/src/img/ui/field_calendar.png
new file mode 100644
index 00000000000..99a1f3f9ef1
--- /dev/null
+++ b/addons/web/static/src/img/ui/field_calendar.png
Binary files differ
diff --git a/addons/web/static/src/img/ui/group-expanded.png b/addons/web/static/src/img/ui/group-expanded.png
new file mode 100644
index 00000000000..3f16536e123
--- /dev/null
+++ b/addons/web/static/src/img/ui/group-expanded.png
Binary files differ
diff --git a/addons/web/static/src/img/ui/group-folded.png b/addons/web/static/src/img/ui/group-folded.png
new file mode 100644
index 00000000000..2909b0c268f
--- /dev/null
+++ b/addons/web/static/src/img/ui/group-folded.png
Binary files differ
diff --git a/addons/web/static/src/img/warning.png b/addons/web/static/src/img/warning.png
new file mode 100644
index 00000000000..cbfb25a89cd
--- /dev/null
+++ b/addons/web/static/src/img/warning.png
Binary files differ
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
new file mode 100644
index 00000000000..38f8eaa1e7c
--- /dev/null
+++ b/addons/web/static/src/js/boot.js
@@ -0,0 +1,69 @@
+/*---------------------------------------------------------
+ * OpenERP Web Boostrap Code
+ *---------------------------------------------------------*/
+
+/**
+ * @name openerp
+ * @namespace openerp
+ */
+(function() {
+ if (this.openerp)
+ return;
+ var session_counter = 0;
+
+ var openerp = this.openerp = {
+ // Per session namespace
+ // openerp.<module> will map to
+ // openerp.sessions.sessionname.<module> using a closure
+ sessions: {},
+ /**
+ * OpenERP instance constructor
+ *
+ * @param {Boolean} skip_init if true, skips the built-in initialization
+ */
+ init: function(skip_init) {
+ var new_instance = {
+ // links to the global openerp
+ _openerp: openerp,
+ // Only web will be loaded, the rest will be by loaded by
+ // openerp.web.Connection on the first connection
+ _modules_loaded: false,
+ // this unique id will be replaced by hostname_databasename by
+ // openerp.web.Connection on the first connection
+ _session_id: "session" + session_counter++,
+ web: {},
+ web_mobile: {}
+ };
+ openerp.sessions[new_instance._session_id] = new_instance;
+ if (!skip_init){
+ openerp.web(new_instance);
+ }
+ return new_instance;
+ }
+ };
+})();
+
+/*---------------------------------------------------------
+ * OpenERP Web web module split
+ *---------------------------------------------------------*/
+
+/**
+ * @namespace
+ */
+openerp.web = function(instance) {
+ openerp.web.core(instance);
+ if (openerp.web.dates) {
+ openerp.web.dates(instance);
+ }
+ openerp.web.formats(instance);
+ openerp.web.chrome(instance);
+ openerp.web.data(instance);
+ var files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export","view_editor"];
+ for(var i=0; i<files.length; i++) {
+ if(openerp.web[files[i]]) {
+ openerp.web[files[i]](instance);
+ }
+ }
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
new file mode 100644
index 00000000000..a04456cfaa5
--- /dev/null
+++ b/addons/web/static/src/js/chrome.js
@@ -0,0 +1,978 @@
+/*---------------------------------------------------------
+ * OpenERP Web chrome
+ *---------------------------------------------------------*/
+
+openerp.web.chrome = function(openerp) {
+var QWeb = openerp.web.qweb;
+
+openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Notification# */{
+ /**
+ * @constructs openerp.web.Notification
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ */
+ init: function(parent, element_id) {
+ this._super(parent, element_id);
+ this.$element.notify({
+ speed: 500,
+ expires: 1500
+ });
+ },
+ notify: function(title, text) {
+ this.$element.notify('create', {
+ title: title,
+ text: text
+ });
+ },
+ warn: function(title, text) {
+ this.$element.notify('create', 'oe_notification_alert', {
+ title: title,
+ text: text
+ });
+ }
+});
+
+openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# */{
+ dialog_title: "",
+ identifier_prefix: 'dialog',
+ /**
+ * @constructs openerp.web.Dialog
+ * @extends openerp.web.OldWidget
+ *
+ * @param parent
+ * @param dialog_options
+ */
+ init: function (parent, dialog_options) {
+ var self = this;
+ this._super(parent);
+ this.dialog_options = {
+ modal: true,
+ width: 'auto',
+ min_width: 0,
+ max_width: '100%',
+ height: 'auto',
+ min_height: 0,
+ max_height: '100%',
+ autoOpen: false,
+ buttons: {},
+ beforeClose: function () { self.on_close(); }
+ };
+ for (var f in this) {
+ if (f.substr(0, 10) == 'on_button_') {
+ this.dialog_options.buttons[f.substr(10)] = this[f];
+ }
+ }
+ if (dialog_options) {
+ this.set_options(dialog_options);
+ }
+ },
+ set_options: function(options) {
+ options = options || {};
+ options.width = this.get_width(options.width || this.dialog_options.width);
+ options.min_width = this.get_width(options.min_width || this.dialog_options.min_width);
+ options.max_width = this.get_width(options.max_width || this.dialog_options.max_width);
+ options.height = this.get_height(options.height || this.dialog_options.height);
+ options.min_height = this.get_height(options.min_height || this.dialog_options.min_height);
+ options.max_height = this.get_height(options.max_height || this.dialog_options.max_width);
+
+ if (options.width !== 'auto') {
+ if (options.width > options.max_width) options.width = options.max_width;
+ if (options.width < options.min_width) options.width = options.min_width;
+ }
+ if (options.height !== 'auto') {
+ if (options.height > options.max_height) options.height = options.max_height;
+ if (options.height < options.min_height) options.height = options.min_height;
+ }
+ if (!options.title && this.dialog_title) {
+ options.title = this.dialog_title;
+ }
+ _.extend(this.dialog_options, options);
+ },
+ get_width: function(val) {
+ return this.get_size(val.toString(), $(window.top).width());
+ },
+ get_height: function(val) {
+ return this.get_size(val.toString(), $(window.top).height());
+ },
+ get_size: function(val, available_size) {
+ if (val === 'auto') {
+ return val;
+ } else if (val.slice(-1) == "%") {
+ return Math.round(available_size / 100 * parseInt(val.slice(0, -1), 10));
+ } else {
+ return parseInt(val, 10);
+ }
+ },
+ start: function () {
+ this.$dialog = $('<div id="' + this.element_id + '"></div>').dialog(this.dialog_options);
+ this._super();
+ return this;
+ },
+ open: function(dialog_options) {
+ // TODO fme: bind window on resize
+ if (this.template) {
+ this.$element.html(this.render());
+ }
+ this.set_options(dialog_options);
+ this.$dialog.dialog(this.dialog_options).dialog('open');
+ return this;
+ },
+ close: function() {
+ // Closes the dialog but leave it in a state where it could be opened again.
+ this.$dialog.dialog('close');
+ },
+ on_close: function() {
+ },
+ stop: function () {
+ // Destroy widget
+ this.close();
+ this.$dialog.dialog('destroy');
+ }
+});
+
+openerp.web.CrashManager = openerp.web.Dialog.extend(/** @lends openerp.web.CrashManager# */{
+ identifier_prefix: 'dialog_crash',
+ /**
+ * @constructs opener.web.CrashManager
+ * @extends openerp.web.Dialog
+ *
+ * @param parent
+ */
+ init: function(parent) {
+ this._super(parent);
+ this.session.on_rpc_error.add(this.on_rpc_error);
+ },
+ on_button_Ok: function() {
+ this.close();
+ },
+ on_rpc_error: function(error) {
+ this.error = error;
+ if (error.data.fault_code) {
+ var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
+ if (split.length > 1) {
+ error.type = split.shift();
+ error.data.fault_code = error.data.fault_code.substr(error.type.length + 4);
+ }
+ }
+ if (error.code === 200 && error.type) {
+ this.dialog_title = "OpenERP " + _.capitalize(error.type);
+ this.template = 'DialogWarning';
+ this.open({
+ width: 'auto',
+ height: 'auto'
+ });
+ } else {
+ this.dialog_title = "OpenERP Error";
+ this.template = 'DialogTraceback';
+ this.open({
+ width: 'auto',
+ height: 'auto'
+ });
+ }
+ }
+});
+
+openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading# */{
+ /**
+ * @constructs openerp.web.Loading
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ */
+ init: function(parent, element_id) {
+ this._super(parent, element_id);
+ this.count = 0;
+ this.session.on_rpc_request.add_first(this.on_rpc_event, 1);
+ this.session.on_rpc_response.add_last(this.on_rpc_event, -1);
+ },
+ on_rpc_event : function(increment) {
+ this.count += increment;
+ if (this.count) {
+ //this.$element.html(QWeb.render("Loading", {}));
+ this.$element.html("Loading ("+this.count+")");
+ this.$element.show();
+ } else {
+ this.$element.fadeOut();
+ }
+ }
+});
+
+openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database# */{
+ /**
+ * @constructs openerp.web.Database
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ * @param option_id
+ */
+ init: function(parent, element_id, option_id) {
+ this._super(parent, element_id);
+ this.$option_id = $('#' + option_id);
+ },
+ start: function() {
+ this.$element.html(QWeb.render("Database", this));
+ this.$element.closest(".openerp")
+ .removeClass("login-mode")
+ .addClass("database_block");
+
+ var self = this;
+
+ var fetch_db = this.rpc("/web/database/get_list", {}, function(result) {
+ self.db_list = result.db_list;
+ });
+ var fetch_langs = this.rpc("/web/session/get_lang_list", {}, function(result) {
+ if (result.error) {
+ self.display_error(result);
+ return;
+ }
+ self.lang_list = result.lang_list;
+ });
+ $.when(fetch_db, fetch_langs).then(function () {self.do_create();});
+
+ this.$element.find('#db-create').click(this.do_create);
+ this.$element.find('#db-drop').click(this.do_drop);
+ this.$element.find('#db-backup').click(this.do_backup);
+ this.$element.find('#db-restore').click(this.do_restore);
+ this.$element.find('#db-change-password').click(this.do_change_password);
+ this.$element.find('#back-to-login').click(function() {
+ self.stop();
+ });
+ },
+ stop: function () {
+ this.$option_id.empty();
+
+ this.$element
+ .find('#db-create, #db-drop, #db-backup, #db-restore, #db-change-password, #back-to-login')
+ .unbind('click')
+ .end()
+ .closest(".openerp")
+ .addClass("login-mode")
+ .removeClass("database_block")
+ .end()
+ .empty();
+
+ },
+ /**
+ * Converts a .serializeArray() result into a dict. Does not bother folding
+ * multiple identical keys into an array, last key wins.
+ *
+ * @param {Array} array
+ */
+ to_object: function (array) {
+ var result = {};
+ _(array).each(function (record) {
+ result[record.name] = record.value;
+ });
+ return result;
+ },
+ /**
+ * Waits until the new database is done creating, then unblocks the UI and
+ * logs the user in as admin
+ *
+ * @param {Number} db_creation_id identifier for the db-creation operation, used to fetch the current installation progress
+ * @param {Object} info info fields for this database creation
+ * @param {String} info.db name of the database being created
+ * @param {String} info.password super-admin password for the database
+ */
+ wait_for_newdb: function (db_creation_id, info) {
+ var self = this;
+ self.rpc('/web/database/progress', {
+ id: db_creation_id,
+ password: info.password
+ }, function (result) {
+ var progress = result[0];
+ // I'd display a progress bar, but turns out the progress status
+ // the server report kind-of blows goats: it's at 0 for ~75% of
+ // the installation, then jumps to 75%, then jumps down to either
+ // 0 or ~40%, then back up to 75%, then terminates. Let's keep that
+ // mess hidden behind a not-very-useful but not overly weird
+ // message instead.
+ if (progress < 1) {
+ setTimeout(function () {
+ self.wait_for_newdb(db_creation_id, info);
+ }, 500);
+ return;
+ }
+
+ var admin = result[1][0];
+ setTimeout(function () {
+ self.stop();
+ self.widget_parent.do_login(
+ info.db, admin.login, admin.password);
+ $.unblockUI();
+ });
+ });
+ },
+ /**
+ * Displays an error dialog resulting from the various RPC communications
+ * failing over themselves
+ *
+ * @param {Object} error error description
+ * @param {String} error.title title of the error dialog
+ * @param {String} error.error message of the error dialog
+ */
+ display_error: function (error) {
+ return $('<div>').dialog({
+ modal: true,
+ title: error.title,
+ buttons: {
+ Ok: function() {
+ $(this).dialog("close");
+ }
+ }
+ }).html(error.error);
+ },
+ do_create: function() {
+ var self = this;
+ self.$option_id.html(QWeb.render("Database.CreateDB", self));
+ self.$option_id.find("form[name=create_db_form]").validate({
+ submitHandler: function (form) {
+ var fields = $(form).serializeArray();
+ $.blockUI({message:'<img src="/web/static/src/img/throbber2.gif">'});
+ self.rpc("/web/database/create", {'fields': fields}, function(result) {
+ if (result.error) {
+ $.unblockUI();
+ self.display_error(result);
+ return;
+ }
+ self.db_list.push(self.to_object(fields)['db_name']);
+ self.db_list.sort();
+ var form_obj = self.to_object(fields);
+ self.wait_for_newdb(result, {
+ password: form_obj['super_admin_pwd'],
+ db: form_obj['db_name']
+ });
+ });
+ }
+ });
+ },
+ do_drop: function() {
+ var self = this;
+ self.$option_id.html(QWeb.render("DropDB", self));
+ self.$option_id.find("form[name=drop_db_form]").validate({
+ submitHandler: function (form) {
+ var $form = $(form),
+ fields = $form.serializeArray(),
+ $db_list = $form.find('select[name=drop_db]'),
+ db = $db_list.val();
+
+ if (!confirm("Do you really want to delete the database: " + db + " ?")) {
+ return;
+ }
+ self.rpc("/web/database/drop", {'fields': fields}, function(result) {
+ if (result.error) {
+ self.display_error(result);
+ return;
+ }
+ $db_list.find(':selected').remove();
+ self.db_list.splice(_.indexOf(self.db_list, db, true), 1);
+ self.notification.notify("Dropping database", "The database '" + db + "' has been dropped");
+ });
+ }
+ });
+ },
+ do_backup: function() {
+ var self = this;
+ self.$option_id
+ .html(QWeb.render("BackupDB", self))
+ .find("form[name=backup_db_form]").validate({
+ submitHandler: function (form) {
+ $.blockUI({message:'<img src="/web/static/src/img/throbber2.gif">'});
+ self.session.get_file({
+ form: form,
+ error: function (body) {
+ var error = body.firstChild.data.split('|');
+ self.display_error({
+ title: error[0],
+ error: error[1]
+ });
+ },
+ complete: $.unblockUI
+ });
+ }
+ });
+ },
+ do_restore: function() {
+ var self = this;
+ self.$option_id.html(QWeb.render("RestoreDB", self));
+
+ self.$option_id.find("form[name=restore_db_form]").validate({
+ submitHandler: function (form) {
+ $.blockUI({message:'<img src="/web/static/src/img/throbber2.gif">'});
+ $(form).ajaxSubmit({
+ url: '/web/database/restore',
+ type: 'POST',
+ resetForm: true,
+ success: function (body) {
+ // TODO: ui manipulations
+ // note: response objects don't work, but we have the
+ // HTTP body of the response~~
+
+ // If empty body, everything went fine
+ if (!body) { return; }
+
+ if (body.indexOf('403 Forbidden') !== -1) {
+ self.display_error({
+ title: 'Access Denied',
+ error: 'Incorrect super-administrator password'
+ })
+ } else {
+ self.display_error({
+ title: 'Restore Database',
+ error: 'Could not restore the database'
+ })
+ }
+ },
+ complete: function () {
+ $.unblockUI();
+ }
+ });
+ }
+ });
+ },
+ do_change_password: function() {
+ var self = this;
+ self.$option_id.html(QWeb.render("Change_DB_Pwd", self));
+
+ self.$option_id.find("form[name=change_pwd_form]").validate({
+ messages: {
+ old_pwd: "Please enter your previous password",
+ new_pwd: "Please enter your new password",
+ confirm_pwd: {
+ required: "Please confirm your new password",
+ equalTo: "The confirmation does not match the password"
+ }
+ },
+ submitHandler: function (form) {
+ self.rpc("/web/database/change_password", {
+ 'fields': $(form).serializeArray()
+ }, function(result) {
+ if (result.error) {
+ self.display_error(result);
+ return;
+ }
+ self.notification.notify("Changed Password", "Password has been changed successfully");
+ });
+ }
+ });
+ }
+});
+
+openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
+ remember_creditentials: true,
+ /**
+ * @constructs openerp.web.Login
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ */
+ init: function(parent, element_id) {
+ this._super(parent, element_id);
+ this.has_local_storage = typeof(localStorage) != 'undefined';
+ this.selected_db = null;
+ this.selected_login = null;
+
+ if (this.has_local_storage && this.remember_creditentials) {
+ this.selected_db = localStorage.getItem('last_db_login_success');
+ this.selected_login = localStorage.getItem('last_login_login_success');
+ if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
+ this.selected_password = localStorage.getItem('last_password_login_success');
+ }
+ }
+ },
+ start: function() {
+ var self = this;
+ this.rpc("/web/database/get_list", {}, function(result) {
+ self.db_list = result.db_list;
+ self.display();
+ }, function() {
+ self.display();
+ });
+ },
+ display: function() {
+ var self = this;
+
+ this.$element.html(QWeb.render("Login", this));
+ this.database = new openerp.web.Database(
+ this, "oe_database", "oe_db_options");
+
+ this.$element.find('#oe-db-config').click(function() {
+ self.database.start();
+ });
+
+ this.$element.find("form").submit(this.on_submit);
+ },
+ on_login_invalid: function() {
+ this.$element.closest(".openerp").addClass("login-mode");
+ },
+ on_login_valid: function() {
+ this.$element.closest(".openerp").removeClass("login-mode");
+ },
+ on_submit: function(ev) {
+ ev.preventDefault();
+ var $e = this.$element;
+ var db = $e.find("form [name=db]").val();
+ var login = $e.find("form input[name=login]").val();
+ var password = $e.find("form input[name=password]").val();
+
+ this.do_login(db, login, password);
+ },
+ /**
+ * Performs actual login operation, and UI-related stuff
+ *
+ * @param {String} db database to log in
+ * @param {String} login user login
+ * @param {String} password user password
+ */
+ do_login: function (db, login, password) {
+ var self = this;
+ this.session.session_login(db, login, password, function() {
+ if(self.session.session_is_valid()) {
+ if (self.has_local_storage) {
+ if(self.remember_creditentials) {
+ localStorage.setItem('last_db_login_success', db);
+ localStorage.setItem('last_login_login_success', login);
+ if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
+ localStorage.setItem('last_password_login_success', password);
+ }
+ } else {
+ localStorage.setItem('last_db_login_success', '');
+ localStorage.setItem('last_login_login_success', '');
+ localStorage.setItem('last_password_login_success', '');
+ }
+ }
+ self.on_login_valid();
+ } else {
+ self.$element.addClass("login_invalid");
+ self.on_login_invalid();
+ }
+ });
+ },
+ do_ask_login: function(continuation) {
+ this.on_login_invalid();
+ this.$element
+ .removeClass("login_invalid");
+ this.on_login_valid.add({
+ position: "last",
+ unique: true,
+ callback: continuation || function() {}
+ });
+ },
+ on_logout: function() {
+ this.session.logout();
+ }
+});
+
+openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# */{
+ template: "Header",
+ identifier_prefix: 'oe-app-header-',
+ /**
+ * @constructs openerp.web.Header
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ */
+ init: function(parent) {
+ this._super(parent);
+ this.qs = "?" + jQuery.param.querystring();
+ this.$content = $();
+ console.debug("initializing header with id", this.element_id);
+ this.update_promise = $.Deferred().resolve();
+ },
+ start: function() {
+ this._super();
+ },
+ do_update: function () {
+ var self = this;
+ var fct = function() {
+ self.$content.remove();
+ if (!self.session.uid)
+ return;
+ var func = new openerp.web.Model(self.session, "res.users").get_func("read");
+ return func(self.session.uid, ["name", "company_id"]).pipe(function(res) {
+ self.$content = $(QWeb.render("Header-content", {widget: self, user: res}));
+ self.$content.appendTo(self.$element);
+ self.$element.find(".logout").click(self.on_logout);
+ self.$element.find("a.preferences").click(self.on_preferences);
+ self.$element.find(".about").click(self.on_about);
+ return self.shortcut_load();
+ });
+ };
+ this.update_promise = this.update_promise.pipe(fct, fct);
+ },
+ on_about: function() {
+ var self = this;
+ self.rpc("/web/webclient/version_info", {}).then(function(res) {
+ var $help = $(QWeb.render("About-Page", {version_info: res}));
+ $help.dialog({autoOpen: true,
+ modal: true, width: 960, title: "About"});
+ });
+ },
+ shortcut_load :function(){
+ var self = this,
+ sc = self.session.shortcuts,
+ shortcuts_ds = new openerp.web.DataSet(this, 'ir.ui.view_sc');
+ // TODO: better way to communicate between sections.
+ // sc.bindings, because jquery does not bind/trigger on arrays...
+ if (!sc.binding) {
+ sc.binding = {};
+ $(sc.binding).bind({
+ 'add': function (e, attrs) {
+ shortcuts_ds.create(attrs, function (out) {
+ $('<li>', {
+ 'data-shortcut-id':out.result,
+ 'data-id': attrs.res_id
+ }).text(attrs.name)
+ .appendTo(self.$element.find('.oe-shortcuts ul'));
+ attrs.id = out.result;
+ sc.push(attrs);
+ });
+ },
+ 'remove-current': function () {
+ var menu_id = self.session.active_id;
+ var $shortcut = self.$element
+ .find('.oe-shortcuts li[data-id=' + menu_id + ']');
+ var shortcut_id = $shortcut.data('shortcut-id');
+ $shortcut.remove();
+ shortcuts_ds.unlink([shortcut_id]);
+ var sc_new = _.reject(sc, function(shortcut){ return shortcut_id === shortcut.id});
+ sc.splice(0, sc.length);
+ sc.push.apply(sc, sc_new);
+ }
+ });
+ }
+ return this.rpc('/web/session/sc_list', {}, function(shortcuts) {
+ sc.splice(0, sc.length);
+ sc.push.apply(sc, shortcuts);
+
+ self.$element.find('.oe-shortcuts')
+ .html(QWeb.render('Shortcuts', {'shortcuts': shortcuts}))
+ .undelegate('li', 'click')
+
+ .delegate('li', 'click', function(e) {
+ e.stopPropagation();
+ var id = $(this).data('id');
+ self.session.active_id = id;
+ self.rpc('/web/menu/action', {'menu_id':id}, function(ir_menu_data) {
+ if (ir_menu_data.action.length){
+ self.on_action(ir_menu_data.action[0][2]);
+ }
+ });
+ });
+ });
+ },
+
+ on_action: function(action) {
+ },
+ on_preferences: function(){
+ var self = this;
+ var action_manager = new openerp.web.ActionManager(this);
+ var dataset = new openerp.web.DataSet (this,'res.users',this.context);
+ dataset.call ('action_get','',function (result){
+ self.rpc('/web/action/load', {action_id:result}, function(result){
+ action_manager.do_action(_.extend(result['result'], {
+ res_id: self.session.uid,
+ res_model: 'res.users',
+ flags: {
+ action_buttons: false,
+ search_view: false,
+ sidebar: false,
+ views_switcher: false,
+ pager: false
+ }
+ }));
+ });
+ });
+ this.dialog = new openerp.web.Dialog(this,{
+ modal: true,
+ title: 'Preferences',
+ width: 600,
+ height: 500,
+ buttons: {
+ "Change password": function(){
+ self.change_password();
+ },
+ Cancel: function(){
+ $(this).dialog('destroy');
+ },
+ Save: function(){
+ var inner_viewmanager = action_manager.inner_viewmanager;
+ inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save(function(){
+ inner_viewmanager.start();
+ });
+ $(this).dialog('destroy')
+ }
+ }
+ });
+ this.dialog.start().open();
+ action_manager.appendTo(this.dialog);
+ action_manager.render(this.dialog);
+ },
+
+ change_password :function() {
+ var self = this;
+ this.dialog = new openerp.web.Dialog(this,{
+ modal : true,
+ title : 'Change Password',
+ width : 'auto',
+ height : 'auto'
+ });
+ this.dialog.start().open();
+ this.dialog.$element.html(QWeb.render("Change_Pwd", self));
+ this.dialog.$element.find("form[name=change_password_form]").validate({
+ submitHandler: function (form) {
+ self.rpc("/web/session/change_password",{
+ 'fields': $(form).serializeArray()
+ }, function(result) {
+ if (result.error) {
+ self.display_error(result);
+ return;
+ }
+ else {
+ if (result.new_password) {
+ self.session.password = result.new_password;
+ var session = new openerp.web.Session(self.session.server, self.session.port);
+ session.start();
+ session.session_login(self.session.db, self.session.login, self.session.password)
+ }
+ }
+ self.notification.notify("Changed Password", "Password has been changed successfully");
+ self.dialog.close();
+ });
+ }
+ });
+ },
+ display_error: function (error) {
+ return $('<div>').dialog({
+ modal: true,
+ title: error.title,
+ buttons: {
+ Ok: function() {
+ $(this).dialog("close");
+ }
+ }
+ }).html(error.error);
+ },
+ on_logout: function() {
+ }
+});
+
+openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
+ /**
+ * @constructs openerp.web.Menu
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ * @param secondary_menu_id
+ */
+ init: function(parent, element_id, secondary_menu_id) {
+ this._super(parent, element_id);
+ this.secondary_menu_id = secondary_menu_id;
+ this.$secondary_menu = $("#" + secondary_menu_id).hide();
+ this.menu = false;
+ },
+ start: function() {
+ this.rpc("/web/menu/load", {}, this.on_loaded);
+ },
+ on_loaded: function(data) {
+ this.data = data;
+ this.$element.html(QWeb.render("Menu", this.data));
+ for (var i = 0; i < this.data.data.children.length; i++) {
+ var v = { menu : this.data.data.children[i] };
+ this.$secondary_menu.append(QWeb.render("Menu.secondary", v));
+ }
+ this.$secondary_menu.find("div.menu_accordion").accordion({
+ animated : false,
+ autoHeight : false,
+ icons : false
+ });
+ this.$secondary_menu.find("div.submenu_accordion").accordion({
+ animated : false,
+ autoHeight : false,
+ active: false,
+ collapsible: true,
+ header: 'h4'
+ });
+
+ this.$element.add(this.$secondary_menu).find("a").click(this.on_menu_click);
+ },
+ on_menu_click: function(ev, id) {
+ id = id || 0;
+ var $menu, $parent, $secondary;
+
+ if (id) {
+ // We can manually activate a menu with it's id (for hash url mapping)
+ $menu = this.$element.find('a[data-menu=' + id + ']');
+ if (!$menu.length) {
+ $menu = this.$secondary_menu.find('a[data-menu=' + id + ']');
+ }
+ } else {
+ $menu = $(ev.currentTarget);
+ id = $menu.data('menu');
+ }
+ if (this.$secondary_menu.has($menu).length) {
+ $secondary = $menu.parents('.menu_accordion');
+ $parent = this.$element.find('a[data-menu=' + $secondary.data('menu-parent') + ']');
+ } else {
+ $parent = $menu;
+ $secondary = this.$secondary_menu.find('.menu_accordion[data-menu-parent=' + $menu.attr('data-menu') + ']');
+ }
+
+ this.$secondary_menu.find('.menu_accordion').hide();
+ // TODO: ui-accordion : collapse submenus and expand the good one
+ $secondary.show();
+
+ if (id) {
+ this.session.active_id = id;
+ this.rpc('/web/menu/action', {'menu_id': id},
+ this.on_menu_action_loaded);
+ }
+
+ $('.active', this.$element.add(this.$secondary_menu.show())).removeClass('active');
+ $parent.addClass('active');
+ $menu.addClass('active');
+ $menu.parent('h4').addClass('active');
+
+ return !$menu.is(".leaf");
+ },
+ on_menu_action_loaded: function(data) {
+ var self = this;
+ if (data.action.length) {
+ var action = data.action[0][2];
+ self.on_action(action);
+ }
+ },
+ on_action: function(action) {
+ }
+});
+
+openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClient */{
+ /**
+ * @constructs openerp.web.WebClient
+ * @extends openerp.web.Widget
+ *
+ * @param element_id
+ */
+ init: function(element_id) {
+ this._super(null, element_id);
+ openerp.webclient = this;
+
+ QWeb.add_template("/web/static/src/xml/base.xml");
+ var params = {};
+ if(jQuery.param != undefined && jQuery.deparam(jQuery.param.querystring()).kitten != undefined) {
+ this.$element.addClass("kitten-mode-activated");
+ }
+ this.$element.html(QWeb.render("Interface", params));
+
+ this.session = new openerp.web.Session();
+ this.loading = new openerp.web.Loading(this,"oe_loading");
+ this.crashmanager = new openerp.web.CrashManager(this);
+ this.crashmanager.start();
+
+ // Do you autorize this ? will be replaced by notify() in controller
+ openerp.web.Widget.prototype.notification = new openerp.web.Notification(this, "oe_notification");
+
+
+ this.header = new openerp.web.Header(this);
+ this.login = new openerp.web.Login(this, "oe_login");
+ this.header.on_logout.add(this.login.on_logout);
+ this.header.on_action.add(this.on_menu_action);
+
+ this.session.on_session_invalid.add(this.login.do_ask_login);
+ this.session.on_session_valid.add_last(this.header.do_update);
+ this.session.on_session_invalid.add_last(this.header.do_update);
+ this.session.on_session_valid.add_last(this.on_logged);
+
+ this.menu = new openerp.web.Menu(this, "oe_menu", "oe_secondary_menu");
+ this.menu.on_action.add(this.on_menu_action);
+ },
+ start: function() {
+ this.header.appendTo($("#oe_header"));
+ this.session.start();
+ this.login.start();
+ this.menu.start();
+ console.debug("The openerp client has been initialized.");
+ },
+ on_logged: function() {
+ if(this.action_manager)
+ this.action_manager.stop();
+ this.action_manager = new openerp.web.ActionManager(this);
+ this.action_manager.appendTo($("#oe_app"));
+
+ // if using saved actions, load the action and give it to action manager
+ var parameters = jQuery.deparam(jQuery.param.querystring());
+ if (parameters["s_action"] != undefined) {
+ var key = parseInt(parameters["s_action"], 10);
+ var self = this;
+ this.rpc("/web/session/get_session_action", {key:key}, function(action) {
+ self.action_manager.do_action(action);
+ });
+ } else if (openerp._modules_loaded) { // TODO: find better option than this
+ this.load_url_state()
+ } else {
+ this.session.on_modules_loaded.add({
+ callback: $.proxy(this, 'load_url_state'),
+ unique: true,
+ position: 'last'
+ })
+ }
+ },
+ /**
+ * Loads state from URL if any, or checks if there is a home action and
+ * loads that, assuming we're at the index
+ */
+ load_url_state: function () {
+ var self = this;
+ // TODO: add actual loading if there is url state to unpack, test on window.location.hash
+
+ // not logged in
+ if (!this.session.uid) { return; }
+ var ds = new openerp.web.DataSetSearch(this, 'res.users');
+ ds.read_ids([this.session.uid], ['action_id'], function (users) {
+ var home_action = users[0].action_id;
+ if (!home_action) {
+ self.default_home();
+ return;
+ }
+ self.execute_home_action(home_action[0], ds);
+ })
+ },
+ default_home: function () {
+ },
+ /**
+ * Bundles the execution of the home action
+ *
+ * @param {Number} action action id
+ * @param {openerp.web.DataSet} dataset action executor
+ */
+ execute_home_action: function (action, dataset) {
+ var self = this;
+ this.rpc('/web/action/load', {
+ action_id: action,
+ context: dataset.get_context()
+ }, function (meh) {
+ var action = meh.result;
+ action.context = _.extend(action.context || {}, {
+ active_id: false,
+ active_ids: [false],
+ active_model: dataset.model
+ });
+ self.action_manager.do_action(action);
+ });
+ },
+ on_menu_action: function(action) {
+ this.action_manager.do_action(action);
+ },
+ do_about: function() {
+ }
+});
+
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
new file mode 100644
index 00000000000..19a915c0f78
--- /dev/null
+++ b/addons/web/static/src/js/core.js
@@ -0,0 +1,992 @@
+/*---------------------------------------------------------
+ * OpenERP Web core
+ *--------------------------------------------------------*/
+
+if (!console.debug) {
+ console.debug = console.log;
+}
+
+openerp.web.core = function(openerp) {
+openerp.web.qweb = new QWeb2.Engine();
+openerp.web.qweb.debug = (window.location.search.indexOf('?debug') !== -1);
+/**
+ * John Resig Class with factory improvement
+ */
+(function() {
+ var initializing = false,
+ fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
+ // The web Class implementation (does nothing)
+ /**
+ * Extended version of John Resig's Class pattern
+ *
+ * @class
+ */
+ openerp.web.Class = function(){};
+
+ /**
+ * Subclass an existing class
+ *
+ * @param {Object} prop class-level properties (class attributes and instance methods) to set on the new class
+ */
+ openerp.web.Class.extend = function(prop) {
+ var _super = this.prototype;
+
+ // Instantiate a web class (but only create the instance,
+ // don't run the init constructor)
+ initializing = true;
+ var prototype = new this();
+ initializing = false;
+
+ // Copy the properties over onto the new prototype
+ for (var name in prop) {
+ // Check if we're overwriting an existing function
+ prototype[name] = typeof prop[name] == "function" &&
+ typeof _super[name] == "function" &&
+ fnTest.test(prop[name]) ?
+ (function(name, fn) {
+ return function() {
+ var tmp = this._super;
+
+ // Add a new ._super() method that is the same
+ // method but on the super-class
+ this._super = _super[name];
+
+ // The method only need to be bound temporarily, so
+ // we remove it when we're done executing
+ var ret = fn.apply(this, arguments);
+ this._super = tmp;
+
+ return ret;
+ };
+ })(name, prop[name]) :
+ prop[name];
+ }
+
+ // The dummy class constructor
+ function Class() {
+ // All construction is actually done in the init method
+ if (!initializing && this.init) {
+ var ret = this.init.apply(this, arguments);
+ if (ret) { return ret; }
+ }
+ return this;
+ }
+ Class.include = function (properties) {
+ for (var name in properties) {
+ if (typeof properties[name] !== 'function'
+ || !fnTest.test(properties[name])) {
+ prototype[name] = properties[name];
+ } else if (typeof prototype[name] === 'function'
+ && prototype.hasOwnProperty(name)) {
+ prototype[name] = (function (name, fn, previous) {
+ return function () {
+ var tmp = this._super;
+ this._super = previous;
+ var ret = fn.apply(this, arguments);
+ this._super = tmp;
+ return ret;
+ }
+ })(name, properties[name], prototype[name]);
+ } else if (typeof _super[name] === 'function') {
+ prototype[name] = (function (name, fn) {
+ return function () {
+ var tmp = this._super;
+ this._super = _super[name];
+ var ret = fn.apply(this, arguments);
+ this._super = tmp;
+ return ret;
+ }
+ })(name, properties[name]);
+ }
+ }
+ };
+
+ // Populate our constructed prototype object
+ Class.prototype = prototype;
+
+ // Enforce the constructor to be what we expect
+ Class.constructor = Class;
+
+ // And make this class extendable
+ Class.extend = arguments.callee;
+
+ return Class;
+ };
+})();
+
+openerp.web.callback = function(obj, method) {
+ var callback = function() {
+ var args = Array.prototype.slice.call(arguments);
+ var r;
+ for(var i = 0; i < callback.callback_chain.length; i++) {
+ var c = callback.callback_chain[i];
+ if(c.unique) {
+ callback.callback_chain.splice(i, 1);
+ i -= 1;
+ }
+ r = c.callback.apply(c.self, c.args.concat(args));
+ // TODO special value to stop the chain
+ // openerp.web.callback_stop
+ }
+ return r;
+ };
+ callback.callback_chain = [];
+ callback.add = function(f) {
+ if(typeof(f) == 'function') {
+ f = { callback: f, args: Array.prototype.slice.call(arguments, 1) };
+ }
+ f.self = f.self || null;
+ f.args = f.args || [];
+ f.unique = !!f.unique;
+ if(f.position == 'last') {
+ callback.callback_chain.push(f);
+ } else {
+ callback.callback_chain.unshift(f);
+ }
+ return callback;
+ };
+ callback.add_first = function(f) {
+ return callback.add.apply(null,arguments);
+ };
+ callback.add_last = function(f) {
+ return callback.add({
+ callback: f,
+ args: Array.prototype.slice.call(arguments, 1),
+ position: "last"
+ });
+ };
+
+ return callback.add({
+ callback: method,
+ self:obj,
+ args:Array.prototype.slice.call(arguments, 2)
+ });
+};
+
+/**
+ * Generates an inherited class that replaces all the methods by null methods (methods
+ * that does nothing and always return undefined).
+ *
+ * @param {Class} claz
+ * @param {Object} add Additional functions to override.
+ * @return {Class}
+ */
+openerp.web.generate_null_object_class = function(claz, add) {
+ var newer = {};
+ var copy_proto = function(prototype) {
+ for (var name in prototype) {
+ if(typeof prototype[name] == "function") {
+ newer[name] = function() {};
+ }
+ }
+ if (prototype.prototype)
+ copy_proto(prototype.prototype);
+ };
+ copy_proto(claz.prototype);
+ newer.init = openerp.web.Widget.prototype.init;
+ var tmpclass = claz.extend(newer);
+ return tmpclass.extend(add || {});
+};
+
+/**
+ * web error for lookup failure
+ *
+ * @class
+ */
+openerp.web.NotFound = openerp.web.Class.extend( /** @lends openerp.web.NotFound# */ {
+});
+openerp.web.KeyNotFound = openerp.web.NotFound.extend( /** @lends openerp.web.KeyNotFound# */ {
+ /**
+ * Thrown when a key could not be found in a mapping
+ *
+ * @constructs openerp.web.KeyNotFound
+ * @extends openerp.web.NotFound
+ * @param {String} key the key which could not be found
+ */
+ init: function (key) {
+ this.key = key;
+ },
+ toString: function () {
+ return "The key " + this.key + " was not found";
+ }
+});
+openerp.web.ObjectNotFound = openerp.web.NotFound.extend( /** @lends openerp.web.ObjectNotFound# */ {
+ /**
+ * Thrown when an object path does not designate a valid class or object
+ * in the openerp hierarchy.
+ *
+ * @constructs openerp.web.ObjectNotFound
+ * @extends openerp.web.NotFound
+ * @param {String} path the invalid object path
+ */
+ init: function (path) {
+ this.path = path;
+ },
+ toString: function () {
+ return "Could not find any object of path " + this.path;
+ }
+});
+openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry# */ {
+ /**
+ * Stores a mapping of arbitrary key (strings) to object paths (as strings
+ * as well).
+ *
+ * Resolves those paths at query time in order to always fetch the correct
+ * object, even if those objects have been overloaded/replaced after the
+ * registry was created.
+ *
+ * An object path is simply a dotted name from the openerp root to the
+ * object pointed to (e.g. ``"openerp.web.Session"`` for an OpenERP
+ * session object).
+ *
+ * @constructs openerp.web.Registry
+ * @param {Object} mapping a mapping of keys to object-paths
+ */
+ init: function (mapping) {
+ this.map = mapping || {};
+ },
+ /**
+ * Retrieves the object matching the provided key string.
+ *
+ * @param {String} key the key to fetch the object for
+ * @returns {Class} the stored class, to initialize
+ *
+ * @throws {openerp.web.KeyNotFound} if the object was not in the mapping
+ * @throws {openerp.web.ObjectNotFound} if the object path was invalid
+ */
+ get_object: function (key) {
+ var path_string = this.map[key];
+ if (path_string === undefined) {
+ throw new openerp.web.KeyNotFound(key);
+ }
+
+ var object_match = openerp;
+ var path = path_string.split('.');
+ // ignore first section
+ for(var i=1; i<path.length; ++i) {
+ object_match = object_match[path[i]];
+
+ if (object_match === undefined) {
+ throw new openerp.web.ObjectNotFound(path_string);
+ }
+ }
+ return object_match;
+ },
+ /**
+ * Tries a number of keys, and returns the first object matching one of
+ * the keys.
+ *
+ * @param {Array} keys a sequence of keys to fetch the object for
+ * @returns {Class} the first class found matching an object
+ *
+ * @throws {openerp.web.KeyNotFound} if none of the keys was in the mapping
+ * @trows {openerp.web.ObjectNotFound} if a found object path was invalid
+ */
+ get_any: function (keys) {
+ for (var i=0; i<keys.length; ++i) {
+ try {
+ return this.get_object(keys[i]);
+ } catch (e) {
+ if (e instanceof openerp.web.KeyNotFound) {
+ continue;
+ }
+ throw e;
+ }
+ }
+ throw new openerp.web.KeyNotFound(keys.join(','));
+ },
+ /**
+ * Adds a new key and value to the registry.
+ *
+ * This method can be chained.
+ *
+ * @param {String} key
+ * @param {String} object_path fully qualified dotted object path
+ * @returns {openerp.web.Registry} itself
+ */
+ add: function (key, object_path) {
+ this.map[key] = object_path;
+ return this;
+ },
+ /**
+ * Creates and returns a copy of the current mapping, with the provided
+ * mapping argument added in (replacing existing keys if needed)
+ *
+ * @param {Object} [mapping={}] a mapping of keys to object-paths
+ */
+ clone: function (mapping) {
+ return new openerp.web.Registry(
+ _.extend({}, this.map, mapping || {}));
+ }
+});
+
+openerp.web.CallbackEnabled = openerp.web.Class.extend(/** @lends openerp.web.CallbackEnabled# */{
+ /**
+ * @constructs openerp.web.CallbackEnabled
+ * @extends openerp.web.Class
+ */
+ init: function() {
+ // Transform on_* method into openerp.web.callbacks
+ for (var name in this) {
+ if(typeof(this[name]) == "function") {
+ this[name].debug_name = name;
+ // bind ALL function to this not only on_and _do ?
+ if((/^on_|^do_/).test(name)) {
+ this[name] = openerp.web.callback(this, this[name]);
+ }
+ }
+ }
+ }
+});
+
+openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web.Session# */{
+ /**
+ * @constructs openerp.web.Session
+ * @extends openerp.web.CallbackEnabled
+ *
+ * @param {String} [server] JSON-RPC endpoint hostname
+ * @param {String} [port] JSON-RPC endpoint port
+ */
+ init: function(server, port) {
+ this._super();
+ this.server = (server == undefined) ? location.hostname : server;
+ this.port = (port == undefined) ? location.port : port;
+ this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp";
+ this.debug = (window.location.search.indexOf('?debug') !== -1);
+ this.session_id = false;
+ this.uid = false;
+ this.user_context= {};
+ this.db = false;
+ this.module_list = [];
+ this.module_loaded = {"web": true};
+ this.context = {};
+ this.shortcuts = [];
+ this.active_id = null;
+ },
+ start: function() {
+ this.session_restore();
+ },
+ /**
+ * Executes an RPC call, registering the provided callbacks.
+ *
+ * Registers a default error callback if none is provided, and handles
+ * setting the correct session id and session context in the parameter
+ * objects
+ *
+ * @param {String} url RPC endpoint
+ * @param {Object} params call parameters
+ * @param {Function} success_callback function to execute on RPC call success
+ * @param {Function} error_callback function to execute on RPC call failure
+ * @returns {jQuery.Deferred} jquery-provided ajax deferred
+ */
+ rpc: function(url, params, success_callback, error_callback) {
+ var self = this;
+ // Construct a JSON-RPC2 request, method is currently unused
+ params.session_id = this.session_id;
+
+ // Call using the rpc_mode
+ var deferred = $.Deferred();
+ this.rpc_ajax(url, {
+ jsonrpc: "2.0",
+ method: "call",
+ params: params,
+ id: _.uniqueId('browser-client-')
+ }).then(function () {deferred.resolve.apply(deferred, arguments);},
+ function(error) {deferred.reject(error, $.Event());});
+ return deferred.fail(function() {
+ deferred.fail(function(error, event) {
+ if (!event.isDefaultPrevented()) {
+ self.on_rpc_error(error, event);
+ }
+ });
+ }).then(success_callback, error_callback).promise();
+ },
+ /**
+ * Raw JSON-RPC call
+ *
+ * @returns {jQuery.Deferred} ajax-webd deferred object
+ */
+ rpc_ajax: function(url, payload) {
+ var self = this;
+ this.on_rpc_request();
+ // url can be an $.ajax option object
+ if (_.isString(url)) {
+ url = {
+ url: url
+ }
+ }
+ var ajax = _.extend({
+ type: "POST",
+ url: url,
+ dataType: 'json',
+ contentType: 'application/json',
+ data: JSON.stringify(payload),
+ processData: false
+ }, url);
+ var deferred = $.Deferred();
+ $.ajax(ajax).done(function(response, textStatus, jqXHR) {
+ self.on_rpc_response();
+ if (!response.error) {
+ deferred.resolve(response["result"], textStatus, jqXHR);
+ return;
+ }
+ if (response.error.data.type !== "session_invalid") {
+ deferred.reject(response.error);
+ return;
+ }
+ self.uid = false;
+ self.on_session_invalid(function() {
+ self.rpc(url, payload.params,
+ function() {
+ deferred.resolve.apply(deferred, arguments);
+ },
+ function(error, event) {
+ event.preventDefault();
+ deferred.reject.apply(deferred, arguments);
+ });
+ });
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ self.on_rpc_response();
+ var error = {
+ code: -32098,
+ message: "XmlHttpRequestError " + errorThrown,
+ data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
+ };
+ deferred.reject(error);
+ });
+ return deferred.promise();
+ },
+ on_rpc_request: function() {
+ },
+ on_rpc_response: function() {
+ },
+ on_rpc_error: function(error) {
+ },
+ /**
+ * The session is validated either by login or by restoration of a previous session
+ */
+ on_session_valid: function() {
+ if(!openerp._modules_loaded)
+ this.load_modules();
+ },
+ on_session_invalid: function(contination) {
+ },
+ session_is_valid: function() {
+ return this.uid;
+ },
+ session_login: function(db, login, password, success_callback) {
+ var self = this;
+ var params = { db: db, login: login, password: password };
+ this.rpc("/web/session/login", params, function(result) {
+ self.session_id = result.session_id;
+ self.uid = result.uid;
+ self.user_context = result.context;
+ self.db = result.db;
+ self.session_save();
+ self.on_session_valid();
+ return true;
+ }).then(success_callback);
+ },
+ /**
+ * Reloads uid and session_id from local storage, if they exist
+ */
+ session_restore: function () {
+ var self = this;
+ this.session_id = this.get_cookie('session_id');
+ return this.rpc("/web/session/get_session_info", {}).then(function(result) {
+ self.uid = result.uid;
+ self.user_context = result.context;
+ self.db = result.db;
+ if (self.uid)
+ self.on_session_valid();
+ else
+ self.on_session_invalid();
+ });
+ },
+ /**
+ * Saves the session id and uid locally
+ */
+ session_save: function () {
+ this.set_cookie('session_id', this.session_id);
+ },
+ logout: function() {
+ this.set_cookie('session_id', '');
+ this.reload_client();
+ },
+ reload_client: function() {
+ window.location.reload();
+ },
+ /**
+ * Fetches a cookie stored by an openerp session
+ *
+ * @private
+ * @param name the cookie's name
+ */
+ get_cookie: function (name) {
+ var nameEQ = this.element_id + '|' + name + '=';
+ var cookies = document.cookie.split(';');
+ for(var i=0; i<cookies.length; ++i) {
+ var cookie = cookies[i].replace(/^\s*/, '');
+ if(cookie.indexOf(nameEQ) === 0) {
+ return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
+ }
+ }
+ return null;
+ },
+ /**
+ * Create a new cookie with the provided name and value
+ *
+ * @private
+ * @param name the cookie's name
+ * @param value the cookie's value
+ * @param ttl the cookie's time to live, 1 year by default, set to -1 to delete
+ */
+ set_cookie: function (name, value, ttl) {
+ ttl = ttl || 24*60*60*365;
+ document.cookie = [
+ this.element_id + '|' + name + '=' + encodeURIComponent(JSON.stringify(value)),
+ 'max-age=' + ttl,
+ 'expires=' + new Date(new Date().getTime() + ttl*1000).toGMTString()
+ ].join(';');
+ },
+ /**
+ * Load additional web addons of that instance and init them
+ */
+ load_modules: function() {
+ var self = this;
+ this.rpc('/web/session/modules', {}, function(result) {
+ self.module_list = result;
+ var lang = self.user_context.lang;
+ var params = { mods: ["web"].concat(result), lang: lang};
+ self.rpc('/web/webclient/translations',params).then(function(transs) {
+ openerp.web._t.database.set_bundle(transs);
+ var modules = self.module_list.join(',');
+ var file_list = ["/web/static/lib/datejs/globalization/" +
+ self.user_context.lang.replace("_", "-") + ".js"
+ ];
+ if(self.debug) {
+ self.rpc('/web/webclient/csslist', {"mods": modules}, self.do_load_css);
+ self.rpc('/web/webclient/jslist', {"mods": modules}, function(files) {
+ self.do_load_js(file_list.concat(files));
+ });
+ } else {
+ self.do_load_css(["/web/webclient/css?mods="+modules]);
+ self.do_load_js(file_list.concat(["/web/webclient/js?mods="+modules]));
+ }
+ openerp._modules_loaded = true;
+ });
+ });
+ },
+ do_load_css: function (files) {
+ var self = this;
+ _.each(files, function (file) {
+ $('head').append($('<link>', {
+ 'href': file + (self.debug ? '?debug=' + (new Date().getTime()) : ''),
+ 'rel': 'stylesheet',
+ 'type': 'text/css'
+ }));
+ });
+ },
+ do_load_js: function(files) {
+ var self = this;
+ if(files.length != 0) {
+ var file = files.shift();
+ var tag = document.createElement('script');
+ tag.type = 'text/javascript';
+ tag.src = file + (this.debug ? '?debug=' + (new Date().getTime()) : '');
+ tag.onload = tag.onreadystatechange = function() {
+ if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
+ return;
+ tag.onload_done = true;
+ self.do_load_js(files);
+ };
+ $('head').append(tag);
+ self.do_load_js(files);
+ } else {
+ this.on_modules_loaded();
+ }
+ },
+ on_modules_loaded: function() {
+ for(var j=0; j<this.module_list.length; j++) {
+ var mod = this.module_list[j];
+ if(this.module_loaded[mod])
+ continue;
+ openerp[mod] = {};
+ // init module mod
+ if(openerp._openerp[mod] != undefined) {
+ openerp._openerp[mod](openerp);
+ this.module_loaded[mod] = true;
+ }
+ }
+ },
+ /**
+ * Cooperative file download implementation, for ajaxy APIs.
+ *
+ * Requires that the server side implements an httprequest correctly
+ * setting the `fileToken` cookie to the value provided as the `token`
+ * parameter. The cookie *must* be set on the `/` path and *must not* be
+ * `httpOnly`.
+ *
+ * It would probably also be a good idea for the response to use a
+ * `Content-Disposition: attachment` header, especially if the MIME is a
+ * "known" type (e.g. text/plain, or for some browsers application/json
+ *
+ * @param {Object} options
+ * @param {String} [options.url] used to dynamically create a form
+ * @param {Object} [options.data] data to add to the form submission. If can be used without a form, in which case a form is created from scratch. Otherwise, added to form data
+ * @param {HTMLFormElement} [options.form] the form to submit in order to fetch the file
+ * @param {Function} [options.success] callback in case of download success
+ * @param {Function} [options.error] callback in case of request error, provided with the error body
+ * @param {Function} [options.complete] called after both ``success`` and ``error` callbacks have executed
+ */
+ get_file: function (options) {
+ // need to detect when the file is done downloading (not used
+ // yet, but we'll need it to fix the UI e.g. with a throbber
+ // while dump is being generated), iframe load event only fires
+ // when the iframe content loads, so we need to go smarter:
+ // http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx
+ var timer, token = new Date().getTime(),
+ cookie_name = 'fileToken', cookie_length = cookie_name.length,
+ CHECK_INTERVAL = 1000, id = _.uniqueId('get_file_frame'),
+ remove_form = false;
+
+ var $form, $form_data = $('<div>');
+
+ var complete = function () {
+ if (options.complete) { options.complete(); }
+ clearTimeout(timer);
+ $form_data.remove();
+ $target.remove();
+ if (remove_form && $form) { $form.remove(); }
+ };
+ var $target = $('<iframe style="display: none;">')
+ .attr({id: id, name: id})
+ .appendTo(document.body)
+ .load(function () {
+ if (options.error) { options.error(this.contentDocument.body); }
+ complete();
+ });
+
+ if (options.form) {
+ $form = $(options.form);
+ } else {
+ remove_form = true;
+ $form = $('<form>', {
+ action: options.url,
+ method: 'POST'
+ }).appendTo(document.body);
+ }
+
+ _(_.extend({}, options.data || {},
+ {session_id: this.session_id, token: token}))
+ .each(function (value, key) {
+ $('<input type="hidden" name="' + key + '">')
+ .val(value)
+ .appendTo($form_data);
+ });
+
+ $form
+ .append($form_data)
+ .attr('target', id)
+ .get(0).submit();
+
+ var waitLoop = function () {
+ var cookies = document.cookie.split(';');
+ // setup next check
+ timer = setTimeout(waitLoop, CHECK_INTERVAL);
+ for (var i=0; i<cookies.length; ++i) {
+ var cookie = cookies[i].replace(/^\s*/, '');
+ if (!cookie.indexOf(cookie_name === 0)) { continue; }
+ var cookie_val = cookie.substring(cookie_length + 1);
+ if (parseInt(cookie_val, 10) !== token) { continue; }
+
+ // clear cookie
+ document.cookie = _.sprintf("%s=;expires=%s;path=/",
+ cookie_name, new Date().toGMTString());
+ if (options.success) { options.success(); }
+ complete();
+ return;
+ }
+ };
+ timer = setTimeout(waitLoop, CHECK_INTERVAL);
+ }
+});
+
+openerp.web.SessionAware = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.SessionAware# */{
+ /**
+ * Utility class that any class is allowed to extend to easy common manipulations.
+ *
+ * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a
+ * logging facility.
+ *
+ * @constructs openerp.web.SessionAware
+ * @extends openerp.web.CallbackEnabled
+ *
+ * @param {openerp.web.Session} session
+ */
+ init: function(session) {
+ this._super();
+ this.session = session;
+ },
+ /**
+ * Performs a JSON-RPC call
+ *
+ * @param {String} url endpoint url
+ * @param {Object} data RPC parameters
+ * @param {Function} success RPC call success callback
+ * @param {Function} error RPC call error callback
+ * @returns {jQuery.Deferred} deferred object for the RPC call
+ */
+ rpc: function(url, data, success, error) {
+ return this.session.rpc(url, data, success, error);
+ }
+});
+
+openerp.web.Widget = openerp.web.SessionAware.extend(/** @lends openerp.web.Widget# */{
+ /**
+ * The name of the QWeb template that will be used for rendering. Must be
+ * redefined in subclasses or the default render() method can not be used.
+ *
+ * @type string
+ */
+ template: null,
+ /**
+ * The prefix used to generate an id automatically. Should be redefined in
+ * subclasses. If it is not defined, a generic identifier will be used.
+ *
+ * @type string
+ */
+ identifier_prefix: 'generic-identifier-',
+ /**
+ * Construct the widget and set its parent if a parent is given.
+ *
+ * @constructs openerp.web.Widget
+ * @extends openerp.web.SessionAware
+ *
+ * @param {openerp.web.Widget} parent Binds the current instance to the given Widget instance.
+ * When that widget is destroyed by calling stop(), the current instance will be
+ * destroyed too. Can be null.
+ * @param {String} element_id Deprecated. Sets the element_id. Only useful when you want
+ * to bind the current Widget to an already existing part of the DOM, which is not compatible
+ * with the DOM insertion methods provided by the current implementation of Widget. So
+ * for new components this argument should not be provided any more.
+ */
+ init: function(parent, /** @deprecated */ element_id) {
+ this._super((parent || {}).session);
+ // if given an element_id, try to get the associated DOM element and save
+ // a reference in this.$element. Else just generate a unique identifier.
+ this.element_id = element_id;
+ this.element_id = this.element_id || _.uniqueId(this.identifier_prefix);
+ var tmp = document.getElementById(this.element_id);
+ this.$element = tmp ? $(tmp) : undefined;
+
+ this.widget_parent = parent;
+ this.widget_children = [];
+ if(parent && parent.widget_children) {
+ parent.widget_children.push(this);
+ }
+ // useful to know if the widget was destroyed and should not be used anymore
+ this.widget_is_stopped = false;
+ },
+ /**
+ * Render the current widget and appends it to the given jQuery object or Widget.
+ *
+ * @param target A jQuery object or a Widget instance.
+ */
+ appendTo: function(target) {
+ var self = this;
+ return this._render_and_insert(function(t) {
+ self.$element.appendTo(t);
+ }, target);
+ },
+ /**
+ * Render the current widget and prepends it to the given jQuery object or Widget.
+ *
+ * @param target A jQuery object or a Widget instance.
+ */
+ prependTo: function(target) {
+ var self = this;
+ return this._render_and_insert(function(t) {
+ self.$element.prependTo(t);
+ }, target);
+ },
+ /**
+ * Render the current widget and inserts it after to the given jQuery object or Widget.
+ *
+ * @param target A jQuery object or a Widget instance.
+ */
+ insertAfter: function(target) {
+ var self = this;
+ return this._render_and_insert(function(t) {
+ self.$element.insertAfter(t);
+ }, target);
+ },
+ /**
+ * Render the current widget and inserts it before to the given jQuery object or Widget.
+ *
+ * @param target A jQuery object or a Widget instance.
+ */
+ insertBefore: function(target) {
+ var self = this;
+ return this._render_and_insert(function(t) {
+ self.$element.insertBefore(t);
+ }, target);
+ },
+ _render_and_insert: function(insertion, target) {
+ var rendered = this.render();
+ this.$element = $(rendered);
+ if (target instanceof openerp.web.Widget)
+ target = target.$element;
+ insertion(target);
+ this.on_inserted(this.$element, this);
+ return this.start();
+ },
+ on_inserted: function(element, widget) {},
+ /**
+ * Renders the widget using QWeb, `this.template` must be defined.
+ * The context given to QWeb contains the "widget" key that references `this`.
+ *
+ * @param {Object} additional Additional context arguments to pass to the template.
+ */
+ render: function (additional) {
+ return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {}));
+ },
+ /**
+ * Method called after rendering. Mostly used to bind actions, perform asynchronous
+ * calls, etc...
+ *
+ * By convention, the method should return a promise to inform the caller when
+ * this widget has been initialized.
+ *
+ * @returns {jQuery.Deferred}
+ */
+ start: function() {
+ if (!this.$element) {
+ var tmp = document.getElementById(this.element_id);
+ this.$element = tmp ? $(tmp) : undefined;
+ }
+ return $.Deferred().done().promise();
+ },
+ /**
+ * Destroys the current widget, also destory all its children before destroying itself.
+ */
+ stop: function() {
+ _.each(_.clone(this.widget_children), function(el) {
+ el.stop();
+ });
+ if(this.$element != null) {
+ this.$element.remove();
+ }
+ if (this.widget_parent && this.widget_parent.widget_children) {
+ this.widget_parent.widget_children = _.without(this.widget_parent.widget_children, this);
+ }
+ this.widget_parent = null;
+ this.widget_is_stopped = true;
+ },
+ /**
+ * Inform the action manager to do an action. Of course, this suppose that
+ * the action manager can be found amongst the ancestors of the current widget.
+ * If that's not the case this method will simply return `false`.
+ */
+ do_action: function(action, on_finished) {
+ if (this.widget_parent) {
+ return this.widget_parent.do_action(action, on_finished);
+ }
+ return false;
+ },
+ do_notify: function() {
+ if (this.widget_parent) {
+ return this.widget_parent.do_notify.apply(this,arguments);
+ }
+ return false;
+ },
+ do_warn: function() {
+ if (this.widget_parent) {
+ return this.widget_parent.do_warn.apply(this,arguments);
+ }
+ return false;
+ },
+ rpc: function(url, data, success, error) {
+ var def = $.Deferred().then(success, error);
+ var self = this;
+ this._super(url, data). then(function() {
+ if (!self.widget_is_stopped)
+ def.resolve.apply(def, arguments);
+ }, function() {
+ if (!self.widget_is_stopped)
+ def.reject.apply(def, arguments);
+ });
+ return def.promise();
+ }
+});
+
+/**
+ * @class
+ * @extends openerp.web.Widget
+ * @deprecated
+ * For retro compatibility only, the only difference with is that render() uses
+ * directly ``this`` instead of context with a ``widget`` key.
+ */
+openerp.web.OldWidget = openerp.web.Widget.extend(/** @lends openerp.web.OldWidget# */{
+ render: function (additional) {
+ return openerp.web.qweb.render(this.template, _.extend(_.extend({}, this), additional || {}));
+ }
+});
+
+openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.web.TranslationDataBase# */{
+ /**
+ * @constructs openerp.web.TranslationDataBase
+ * @extends openerp.web.Class
+ */
+ init: function() {
+ this.db = {};
+ this.parameters = {"direction": 'ltr',
+ "date_format": '%m/%d/%Y',
+ "time_format": '%H:%M:%S',
+ "grouping": "[]",
+ "decimal_point": ".",
+ "thousands_sep": ","};
+ },
+ set_bundle: function(translation_bundle) {
+ var self = this;
+ this.db = {};
+ var modules = _.keys(translation_bundle.modules).sort();
+ if (_.include(modules, "web")) {
+ modules = ["web"].concat(_.without(modules, "web"));
+ }
+ _.each(modules, function(name) {
+ self.add_module_translation(translation_bundle.modules[name]);
+ });
+ if (translation_bundle.lang_parameters) {
+ this.parameters = translation_bundle.lang_parameters;
+ }
+ },
+ add_module_translation: function(mod) {
+ var self = this;
+ _.each(mod.messages, function(message) {
+ if (self.db[message.id] === undefined) {
+ self.db[message.id] = message.string;
+ }
+ });
+ },
+ build_translation_function: function() {
+ var self = this;
+ var fcnt = function(str) {
+ var tmp = self.get(str);
+ return tmp === undefined ? str : tmp;
+ };
+ fcnt.database = this;
+ return fcnt;
+ },
+ get: function(key) {
+ if (this.db[key])
+ return this.db[key];
+ return undefined;
+ }
+});
+
+openerp.web._t = new openerp.web.TranslationDataBase().build_translation_function();
+
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
new file mode 100644
index 00000000000..1eb57241fa6
--- /dev/null
+++ b/addons/web/static/src/js/data.js
@@ -0,0 +1,833 @@
+
+openerp.web.data = function(openerp) {
+
+/**
+ * Serializes the sort criterion array of a dataset into a form which can be
+ * consumed by OpenERP's RPC APIs.
+ *
+ * @param {Array} criterion array of fields, from first to last criteria, prefixed with '-' for reverse sorting
+ * @returns {String} SQL-like sorting string (``ORDER BY``) clause
+ */
+openerp.web.serialize_sort = function (criterion) {
+ return _.map(criterion,
+ function (criteria) {
+ if (criteria[0] === '-') {
+ return criteria.slice(1) + ' DESC';
+ }
+ return criteria + ' ASC';
+ }).join(', ');
+};
+
+openerp.web.DataGroup = openerp.web.Widget.extend( /** @lends openerp.web.DataGroup# */{
+ /**
+ * Management interface between views and grouped collections of OpenERP
+ * records.
+ *
+ * The root DataGroup is instantiated with the relevant information
+ * (a session, a model, a domain, a context and a group_by sequence), the
+ * domain and context may be empty. It is then interacted with via
+ * :js:func:`~openerp.web.DataGroup.list`, which is used to read the
+ * content of the current grouping level.
+ *
+ * @constructs openerp.web.DataGroup
+ * @extends openerp.web.Widget
+ *
+ * @param {openerp.web.Session} session Current OpenERP session
+ * @param {String} model name of the model managed by this DataGroup
+ * @param {Array} domain search domain for this DataGroup
+ * @param {Object} context context of the DataGroup's searches
+ * @param {Array} group_by sequence of fields by which to group
+ * @param {Number} [level=0] nesting level of the group
+ */
+ init: function(parent, model, domain, context, group_by, level) {
+ this._super(parent, null);
+ if (group_by) {
+ if (group_by.length || context['group_by_no_leaf']) {
+ return new openerp.web.ContainerDataGroup( this, model, domain, context, group_by, level);
+ } else {
+ return new openerp.web.GrouplessDataGroup( this, model, domain, context, level);
+ }
+ }
+
+ this.model = model;
+ this.context = context;
+ this.domain = domain;
+
+ this.level = level || 0;
+ },
+ cls: 'DataGroup'
+});
+openerp.web.ContainerDataGroup = openerp.web.DataGroup.extend( /** @lends openerp.web.ContainerDataGroup# */ {
+ /**
+ *
+ * @constructs openerp.web.ContainerDataGroup
+ * @extends openerp.web.DataGroup
+ *
+ * @param session
+ * @param model
+ * @param domain
+ * @param context
+ * @param group_by
+ * @param level
+ */
+ init: function (parent, model, domain, context, group_by, level) {
+ this._super(parent, model, domain, context, null, level);
+
+ this.group_by = group_by;
+ },
+ /**
+ * The format returned by ``read_group`` is absolutely dreadful:
+ *
+ * * A ``__context`` key provides future grouping levels
+ * * A ``__domain`` key provides the domain for the next search
+ * * The current grouping value is provided through the name of the
+ * current grouping name e.g. if currently grouping on ``user_id``, then
+ * the ``user_id`` value for this group will be provided through the
+ * ``user_id`` key.
+ * * Similarly, the number of items in the group (not necessarily direct)
+ * is provided via ``${current_field}_count``
+ * * Other aggregate fields are just dumped there
+ *
+ * This function slightly improves the grouping records by:
+ *
+ * * Adding a ``grouped_on`` property providing the current grouping field
+ * * Adding a ``value`` and a ``length`` properties which replace the
+ * ``$current_field`` and ``${current_field}_count`` ones
+ * * Moving aggregate values into an ``aggregates`` property object
+ *
+ * Context and domain keys remain as-is, they should not be used externally
+ * but in case they're needed...
+ *
+ * @param {Object} group ``read_group`` record
+ */
+ transform_group: function (group) {
+ var field_name = this.group_by[0];
+ // In cases where group_by_no_leaf and no group_by, the result of
+ // read_group has aggregate fields but no __context or __domain.
+ // Create default (empty) values for those so that things don't break
+ var fixed_group = _.extend(
+ {__context: {group_by: []}, __domain: []},
+ group);
+
+ var aggregates = {};
+ _(fixed_group).each(function (value, key) {
+ if (key.indexOf('__') === 0
+ || key === field_name
+ || key === field_name + '_count') {
+ return;
+ }
+ aggregates[key] = value || 0;
+ });
+
+ return {
+ __context: fixed_group.__context,
+ __domain: fixed_group.__domain,
+
+ grouped_on: field_name,
+ // if terminal group (or no group) and group_by_no_leaf => use group.__count
+ length: fixed_group[field_name + '_count'] || fixed_group.__count,
+ value: fixed_group[field_name],
+
+ openable: !(this.context['group_by_no_leaf']
+ && fixed_group.__context.group_by.length === 0),
+
+ aggregates: aggregates
+ };
+ },
+ fetch: function (fields) {
+ // internal method
+ var d = new $.Deferred();
+ var self = this;
+
+ this.rpc('/web/group/read', {
+ model: this.model,
+ context: this.context,
+ domain: this.domain,
+ fields: _.uniq(this.group_by.concat(fields)),
+ group_by_fields: this.group_by,
+ sort: openerp.web.serialize_sort(this.sort)
+ }, function () { }).then(function (response) {
+ var data_groups = _(response).map(
+ _.bind(self.transform_group, self));
+ self.groups = data_groups;
+ d.resolveWith(self, [data_groups]);
+ }, function () {
+ d.rejectWith.apply(d, [self, arguments]);
+ });
+ return d.promise();
+ },
+ /**
+ * The items of a list have the following properties:
+ *
+ * ``length``
+ * the number of records contained in the group (and all of its
+ * sub-groups). This does *not* provide the size of the "next level"
+ * of the group, unless the group is terminal (no more groups within
+ * it).
+ * ``grouped_on``
+ * the name of the field this level was grouped on, this is mostly
+ * used for display purposes, in order to know the name of the current
+ * level of grouping. The ``grouped_on`` should be the same for all
+ * objects of the list.
+ * ``value``
+ * the value which led to this group (this is the value all contained
+ * records have for the current ``grouped_on`` field name).
+ * ``aggregates``
+ * a mapping of other aggregation fields provided by ``read_group``
+ *
+ * @param {Array} fields the list of fields to aggregate in each group, can be empty
+ * @param {Function} ifGroups function executed if any group is found (DataGroup.group_by is non-null and non-empty), called with a (potentially empty) list of groups as parameters.
+ * @param {Function} ifRecords function executed if there is no grouping left to perform, called with a DataSet instance as parameter
+ */
+ list: function (fields, ifGroups, ifRecords) {
+ var self = this;
+ this.fetch(fields).then(function (group_records) {
+ ifGroups(_(group_records).map(function (group) {
+ var child_context = _.extend({}, self.context, group.__context);
+ return _.extend(
+ new openerp.web.DataGroup(
+ self, self.model, group.__domain,
+ child_context, child_context.group_by,
+ self.level + 1),
+ group, {sort: self.sort});
+ }));
+ });
+ }
+});
+openerp.web.GrouplessDataGroup = openerp.web.DataGroup.extend( /** @lends openerp.web.GrouplessDataGroup# */ {
+ /**
+ *
+ * @constructs openerp.web.GrouplessDataGroup
+ * @extends openerp.web.DataGroup
+ *
+ * @param session
+ * @param model
+ * @param domain
+ * @param context
+ * @param level
+ */
+ init: function (parent, model, domain, context, level) {
+ this._super(parent, model, domain, context, null, level);
+ },
+ list: function (fields, ifGroups, ifRecords) {
+ ifRecords(_.extend(
+ new openerp.web.DataSetSearch(this, this.model),
+ {domain: this.domain, context: this.context, _sort: this.sort}));
+ }
+});
+openerp.web.StaticDataGroup = openerp.web.GrouplessDataGroup.extend( /** @lends openerp.web.StaticDataGroup# */ {
+ /**
+ * A specialization of groupless data groups, relying on a single static
+ * dataset as its records provider.
+ *
+ * @constructs openerp.web.StaticDataGroup
+ * @extends openerp.web.GrouplessDataGroup
+ * @param {openep.web.DataSetStatic} dataset a static dataset backing the groups
+ */
+ init: function (dataset) {
+ this.dataset = dataset;
+ },
+ list: function (fields, ifGroups, ifRecords) {
+ ifRecords(this.dataset);
+ }
+});
+
+openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet# */{
+ /**
+ * DateaManagement interface between views and the collection of selected
+ * OpenERP records (represents the view's state?)
+ *
+ * @constructs openerp.web.DataSet
+ * @extends openerp.web.Widget
+ *
+ * @param {String} model the OpenERP model this dataset will manage
+ */
+ init: function(source_controller, model, context) {
+ // we don't want the dataset to be a child of anything!
+ this._super(null);
+ this.session = source_controller ? source_controller.session : undefined;
+ this.model = model;
+ this.context = context || {};
+ this.index = null;
+ },
+ start: function() {
+ },
+ previous: function () {
+ this.index -= 1;
+ if (this.index < 0) {
+ this.index = this.ids.length - 1;
+ }
+ return this;
+ },
+ next: function () {
+ this.index += 1;
+ if (this.index >= this.ids.length) {
+ this.index = 0;
+ }
+ return this;
+ },
+ /**
+ * Read records.
+ *
+ * @param {Array} ids identifiers of the records to read
+ * @param {Array} fields fields to read and return, by default all fields are returned
+ * @param {Function} callback function called with read result
+ * @returns {$.Deferred}
+ */
+ read_ids: function (ids, fields, callback) {
+ return this.rpc('/web/dataset/get', {
+ model: this.model,
+ ids: ids,
+ fields: fields,
+ context: this.get_context()
+ }, callback);
+ },
+ /**
+ * Read a slice of the records represented by this DataSet, based on its
+ * domain and context.
+ *
+ * @param {Array} [fields] fields to read and return, by default all fields are returned
+ * @params {Object} options
+ * @param {Number} [options.offset=0] The index from which selected records should be returned
+ * @param {Number} [options.limit=null] The maximum number of records to return
+ * @param {Function} callback function called with read_slice result
+ * @returns {$.Deferred}
+ */
+ read_slice: function (fields, options, callback) {
+ return null;
+ },
+ /**
+ * Reads the current dataset record (from its index)
+ *
+ * @params {Array} [fields] fields to read and return, by default all fields are returned
+ * @params {Function} callback function called with read_index result
+ * @returns {$.Deferred}
+ */
+ read_index: function (fields, callback) {
+ var def = $.Deferred().then(callback);
+ if (_.isEmpty(this.ids)) {
+ def.reject();
+ } else {
+ fields = fields || false;
+ return this.read_ids([this.ids[this.index]], fields).then(function(records) {
+ def.resolve(records[0]);
+ }, function() {
+ def.reject.apply(def, arguments);
+ });
+ }
+ return def.promise();
+ },
+ /**
+ * Reads default values for the current model
+ *
+ * @param {Array} [fields] fields to get default values for, by default all defaults are read
+ * @param {Function} callback function called with default_get result
+ * @returns {$.Deferred}
+ */
+ default_get: function(fields, callback) {
+ return this.rpc('/web/dataset/default_get', {
+ model: this.model,
+ fields: fields,
+ context: this.get_context()
+ }, callback);
+ },
+ /**
+ * Creates a new record in db
+ *
+ * @param {Object} data field values to set on the new record
+ * @param {Function} callback function called with operation result
+ * @param {Function} error_callback function called in case of creation error
+ * @returns {$.Deferred}
+ */
+ create: function(data, callback, error_callback) {
+ return this.rpc('/web/dataset/create', {
+ model: this.model,
+ data: data,
+ context: this.get_context()
+ }, callback, error_callback);
+ },
+ /**
+ * Saves the provided data in an existing db record
+ *
+ * @param {Number|String} id identifier for the record to alter
+ * @param {Object} data field values to write into the record
+ * @param {Function} callback function called with operation result
+ * @param {Function} error_callback function called in case of write error
+ * @returns {$.Deferred}
+ */
+ write: function (id, data, options, callback, error_callback) {
+ var options = options || {};
+ return this.rpc('/web/dataset/save', {
+ model: this.model,
+ id: id,
+ data: data,
+ context: this.get_context(options.context)
+ }, callback, error_callback);
+ },
+ /**
+ * Deletes an existing record from the database
+ *
+ * @param {Number|String} ids identifier of the record to delete
+ * @param {Function} callback function called with operation result
+ * @param {Function} error_callback function called in case of deletion error
+ */
+ unlink: function(ids, callback, error_callback) {
+ var self = this;
+ return this.call_and_eval("unlink", [ids, this.get_context()], null, 1,
+ callback, error_callback);
+ },
+ /**
+ * Calls an arbitrary RPC method
+ *
+ * @param {String} method name of the method (on the current model) to call
+ * @param {Array} [args] arguments to pass to the method
+ * @param {Function} callback
+ * @param {Function} error_callback
+ * @returns {$.Deferred}
+ */
+ call: function (method, args, callback, error_callback) {
+ return this.rpc('/web/dataset/call', {
+ model: this.model,
+ method: method,
+ args: args || []
+ }, callback, error_callback);
+ },
+ /**
+ * Calls an arbitrary method, with more crazy
+ *
+ * @param {String} method
+ * @param {Array} [args]
+ * @param {Number} [domain_index] index of a domain to evaluate in the args array
+ * @param {Number} [context_index] index of a context to evaluate in the args array
+ * @param {Function} callback
+ * @param {Function }error_callback
+ * @returns {$.Deferred}
+ */
+ call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) {
+ return this.rpc('/web/dataset/call', {
+ model: this.model,
+ method: method,
+ domain_id: domain_index || null,
+ context_id: context_index || null,
+ args: args || []
+ }, callback, error_callback);
+ },
+ /**
+ * Calls a button method, usually returning some sort of action
+ *
+ * @param {String} method
+ * @param {Array} [args]
+ * @param {Function} callback
+ * @param {Function} error_callback
+ * @returns {$.Deferred}
+ */
+ call_button: function (method, args, callback, error_callback) {
+ return this.rpc('/web/dataset/call_button', {
+ model: this.model,
+ method: method,
+ domain_id: null,
+ context_id: 1,
+ args: args || []
+ }, callback, error_callback);
+ },
+ /**
+ * Fetches the "readable name" for records, based on intrinsic rules
+ *
+ * @param {Array} ids
+ * @param {Function} callback
+ * @returns {$.Deferred}
+ */
+ name_get: function(ids, callback) {
+ return this.call_and_eval('name_get', [ids, this.get_context()], null, 1, callback);
+ },
+ /**
+ *
+ * @param {String} name name to perform a search for/on
+ * @param {Array} [domain=[]] filters for the objects returned, OpenERP domain
+ * @param {String} [operator='ilike'] matching operator to use with the provided name value
+ * @param {Number} [limit=100] maximum number of matches to return
+ * @param {Function} callback function to call with name_search result
+ * @returns {$.Deferred}
+ */
+ name_search: function (name, domain, operator, limit, callback) {
+ return this.call_and_eval('name_search',
+ [name || '', domain || false, operator || 'ilike', this.get_context(), limit || 100],
+ 1, 3, callback);
+ },
+ /**
+ * @param name
+ * @param callback
+ */
+ name_create: function(name, callback) {
+ return this.call_and_eval('name_create', [name, this.get_context()], null, 1, callback);
+ },
+ exec_workflow: function (id, signal, callback) {
+ return this.rpc('/web/dataset/exec_workflow', {
+ model: this.model,
+ id: id,
+ signal: signal
+ }, callback);
+ },
+ get_context: function(request_context) {
+ if (request_context) {
+ return new openerp.web.CompoundContext(this.context, request_context);
+ }
+ return this.context;
+ }
+});
+openerp.web.DataSetStatic = openerp.web.DataSet.extend({
+ init: function(parent, model, context, ids) {
+ this._super(parent, model, context);
+ // all local records
+ this.ids = ids || [];
+ },
+ read_slice: function (fields, options, callback) {
+ // TODO remove fields from options
+ var self = this,
+ offset = options.offset || 0,
+ limit = options.limit || false,
+ fields = fields || false;
+ var end_pos = limit && limit !== -1 ? offset + limit : undefined;
+ return this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
+ },
+ set_ids: function (ids) {
+ this.ids = ids;
+ if (this.index !== null) {
+ this.index = this.index <= this.ids.length - 1 ?
+ this.index : (this.ids.length > 0 ? this.length - 1 : 0);
+ }
+ },
+ unlink: function(ids) {
+ this.on_unlink(ids);
+ return $.Deferred().resolve({result: true});
+ },
+ on_unlink: function(ids) {
+ this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
+ }
+});
+openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.DataSetSearch */{
+ /**
+ * @constructs openerp.web.DataSetSearch
+ * @extends openerp.web.DataSet
+ *
+ * @param {Object} parent
+ * @param {String} model
+ * @param {Object} context
+ * @param {Array} domain
+ */
+ init: function(parent, model, context, domain) {
+ this._super(parent, model, context);
+ this.domain = domain || [];
+ this._sort = [];
+ this.offset = 0;
+ // subset records[offset:offset+limit]
+ // is it necessary ?
+ this.ids = [];
+ },
+ /**
+ * Read a slice of the records represented by this DataSet, based on its
+ * domain and context.
+ *
+ * @params {Object} options
+ * @param {Array} [options.fields] fields to read and return, by default all fields are returned
+ * @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
+ * @param {Array} [options.domain] domain data to add to the request payload, ANDed with the dataset's domain
+ * @param {Number} [options.offset=0] The index from which selected records should be returned
+ * @param {Number} [options.limit=null] The maximum number of records to return
+ * @param {Function} callback function called with read_slice result
+ * @returns {$.Deferred}
+ */
+ read_slice: function (fields, options, callback) {
+ var self = this;
+ var options = options || {};
+ var offset = options.offset || 0;
+ return this.rpc('/web/dataset/search_read', {
+ model: this.model,
+ fields: fields || false,
+ domain: this.get_domain(options.domain),
+ context: this.get_context(options.context),
+ sort: this.sort(),
+ offset: offset,
+ limit: options.limit || false
+ }, function (result) {
+ self.ids = result.ids;
+ self.offset = offset;
+ if (callback) {
+ callback(result.records);
+ }
+ });
+ },
+ get_domain: function (other_domain) {
+ if (other_domain) {
+ return new openerp.web.CompoundDomain(this.domain, other_domain);
+ }
+ return this.domain;
+ },
+ /**
+ * Reads or changes sort criteria on the dataset.
+ *
+ * If not provided with any argument, serializes the sort criteria to
+ * an SQL-like form usable by OpenERP's ORM.
+ *
+ * If given a field, will set that field as first sorting criteria or,
+ * if the field is already the first sorting criteria, will reverse it.
+ *
+ * @param {String} [field] field to sort on, reverses it (toggle from ASC to DESC) if already the main sort criteria
+ * @param {Boolean} [force_reverse=false] forces inserting the field as DESC
+ * @returns {String|undefined}
+ */
+ sort: function (field, force_reverse) {
+ if (!field) {
+ return openerp.web.serialize_sort(this._sort);
+ }
+ var reverse = force_reverse || (this._sort[0] === field);
+ this._sort.splice.apply(
+ this._sort, [0, this._sort.length].concat(
+ _.without(this._sort, field, '-' + field)));
+
+ this._sort.unshift((reverse ? '-' : '') + field);
+ return undefined;
+ },
+ unlink: function(ids, callback, error_callback) {
+ var self = this;
+ return this._super(ids, function(result) {
+ self.ids = _.without.apply(_, [self.ids].concat(ids));
+ if (this.index !== null) {
+ self.index = self.index <= self.ids.length - 1 ?
+ self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
+ }
+ if (callback)
+ callback(result);
+ }, error_callback);
+ }
+});
+openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
+ virtual_id_prefix: "one2many_v_id_",
+ virtual_id_regex: /one2many_v_id_.*/,
+ debug_mode: true,
+ init: function() {
+ this._super.apply(this, arguments);
+ this.reset_ids([]);
+ },
+ create: function(data, callback, error_callback) {
+ var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data};
+ this.to_create.push(cached);
+ this.cache.push(cached);
+ this.on_change();
+ var to_return = $.Deferred().then(callback);
+ to_return.resolve({result: cached.id});
+ return to_return.promise();
+ },
+ write: function (id, data, options, callback) {
+ var self = this;
+ var record = _.detect(this.to_create, function(x) {return x.id === id;});
+ record = record || _.detect(this.to_write, function(x) {return x.id === id;});
+ var dirty = false;
+ if (record) {
+ for (var k in data) {
+ if (record.values[k] === undefined || record.values[k] !== data[k]) {
+ dirty = true;
+ break;
+ }
+ }
+ $.extend(record.values, data);
+ } else {
+ dirty = true;
+ record = {id: id, values: data};
+ self.to_write.push(record);
+ }
+ var cached = _.detect(this.cache, function(x) {return x.id === id;});
+ $.extend(cached.values, record.values);
+ if (dirty)
+ this.on_change();
+ var to_return = $.Deferred().then(callback);
+ to_return.resolve({result: true});
+ return to_return.promise();
+ },
+ unlink: function(ids, callback, error_callback) {
+ var self = this;
+ _.each(ids, function(id) {
+ if (! _.detect(self.to_create, function(x) { return x.id === id; })) {
+ self.to_delete.push({id: id})
+ }
+ });
+ this.to_create = _.reject(this.to_create, function(x) { return _.include(ids, x.id);});
+ this.to_write = _.reject(this.to_write, function(x) { return _.include(ids, x.id);});
+ this.cache = _.reject(this.cache, function(x) { return _.include(ids, x.id);});
+ this.set_ids(_.without.apply(_, [this.ids].concat(ids)));
+ this.on_change();
+ var to_return = $.Deferred().then(callback);
+ setTimeout(function () {to_return.resolve({result: true});}, 0);
+ return to_return.promise();
+ },
+ reset_ids: function(ids) {
+ this.set_ids(ids);
+ this.to_delete = [];
+ this.to_create = [];
+ this.to_write = [];
+ this.cache = [];
+ this.delete_all = false;
+ },
+ on_change: function() {},
+ read_ids: function (ids, fields, callback) {
+ var self = this;
+ var to_get = [];
+ _.each(ids, function(id) {
+ var cached = _.detect(self.cache, function(x) {return x.id === id;});
+ var created = _.detect(self.to_create, function(x) {return x.id === id;});
+ if (created) {
+ _.each(fields, function(x) {if (cached.values[x] === undefined) cached.values[x] = false;});
+ } else {
+ if (!cached || !_.all(fields, function(x) {return cached.values[x] !== undefined}))
+ to_get.push(id);
+ }
+ });
+ var completion = $.Deferred().then(callback);
+ var return_records = function() {
+ var records = _.map(ids, function(id) {
+ return _.extend({}, _.detect(self.cache, function(c) {return c.id === id;}).values, {"id": id});
+ });
+ if (self.debug_mode) {
+ if (_.include(records, undefined)) {
+ throw "Record not correctly loaded";
+ }
+ }
+ setTimeout(function () {completion.resolve(records);}, 0);
+ };
+ if(to_get.length > 0) {
+ var rpc_promise = this._super(to_get, fields, function(records) {
+ _.each(records, function(record, index) {
+ var id = to_get[index];
+ var cached = _.detect(self.cache, function(x) {return x.id === id;});
+ if (!cached) {
+ self.cache.push({id: id, values: record});
+ } else {
+ // I assume cache value is prioritary
+ _.defaults(cached.values, record);
+ }
+ });
+ return_records();
+ });
+ $.when(rpc_promise).fail(function() {completion.reject();});
+ } else {
+ return_records();
+ }
+ return completion.promise();
+ }
+});
+openerp.web.ReadOnlyDataSetSearch = openerp.web.DataSetSearch.extend({
+ create: function(data, callback, error_callback) {
+ this.on_create(data);
+ var to_return = $.Deferred().then(callback);
+ setTimeout(function () {to_return.resolve({"result": undefined});}, 0);
+ return to_return.promise();
+ },
+ on_create: function(data) {},
+ write: function (id, data, options, callback) {
+ this.on_write(id, data);
+ var to_return = $.Deferred().then(callback);
+ setTimeout(function () {to_return.resolve({"result": true});}, 0);
+ return to_return.promise();
+ },
+ on_write: function(id, data) {},
+ unlink: function(ids, callback, error_callback) {
+ this.on_unlink(ids);
+ var to_return = $.Deferred().then(callback);
+ setTimeout(function () {to_return.resolve({"result": true});}, 0);
+ return to_return.promise();
+ },
+ on_unlink: function(ids) {}
+});
+
+openerp.web.Model = openerp.web.SessionAware.extend({
+ init: function(session, model_name) {
+ this._super(session);
+ this.model_name = model_name;
+ },
+ get_func: function(method_name) {
+ var self = this;
+ return function() {
+ if (method_name == "search_read")
+ return self._search_read.apply(self, arguments);
+ return self._call(method_name, _.toArray(arguments));
+ };
+ },
+ _call: function (method, args) {
+ return this.rpc('/web/dataset/call', {
+ model: this.model_name,
+ method: method,
+ args: args
+ }).pipe(function(result) {
+ if (method == "read" && result instanceof Array && result.length > 0 && result[0]["id"]) {
+ var index = {};
+ _.each(_.range(result.length), function(i) {
+ index[result[i]["id"]] = result[i];
+ })
+ result = _.map(args[0], function(x) {return index[x];});
+ }
+ return result;
+ });
+ },
+ _search_read: function(domain, fields, offset, limit, order, context) {
+ return this.rpc('/web/dataset/search_read', {
+ model: this.model_name,
+ fields: fields,
+ offset: offset,
+ limit: limit,
+ domain: domain,
+ sort: order,
+ context: context
+ }).pipe(function(result) {
+ return result.records;
+ });;
+ }
+});
+
+openerp.web.CompoundContext = openerp.web.Class.extend({
+ init: function () {
+ this.__ref = "compound_context";
+ this.__contexts = [];
+ this.__eval_context = null;
+ var self = this;
+ _.each(arguments, function(x) {
+ self.add(x);
+ });
+ },
+ add: function (context) {
+ this.__contexts.push(context);
+ return this;
+ },
+ set_eval_context: function (eval_context) {
+ this.__eval_context = eval_context;
+ return this;
+ },
+ get_eval_context: function () {
+ return this.__eval_context;
+ }
+});
+
+openerp.web.CompoundDomain = openerp.web.Class.extend({
+ init: function () {
+ this.__ref = "compound_domain";
+ this.__domains = [];
+ this.__eval_context = null;
+ var self = this;
+ _.each(arguments, function(x) {
+ self.add(x);
+ });
+ },
+ add: function(domain) {
+ this.__domains.push(domain);
+ return this;
+ },
+ set_eval_context: function(eval_context) {
+ this.__eval_context = eval_context;
+ return this;
+ },
+ get_eval_context: function() {
+ return this.__eval_context;
+ }
+});
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js
new file mode 100644
index 00000000000..51ac2cbd568
--- /dev/null
+++ b/addons/web/static/src/js/data_export.js
@@ -0,0 +1,391 @@
+openerp.web.data_export = function(openerp) {
+var QWeb = openerp.web.qweb;
+openerp.web.DataExport = openerp.web.Dialog.extend({
+ template: 'ExportTreeView',
+ dialog_title: 'Export Data',
+ init: function(parent, dataset) {
+ this._super(parent);
+ this.records = {};
+ this.dataset = dataset;
+ this.exports = new openerp.web.DataSetSearch(
+ this, 'ir.exports', this.dataset.get_context());
+ },
+ start: function() {
+ var self = this;
+ this._super.apply(this, arguments);
+ this.open({
+ modal: true,
+ width: '55%',
+ height: 'auto',
+ position: 'top',
+ buttons : {
+ "Close" : function() {
+ self.close();
+ },
+ "Export To File" : function() {
+ self.on_click_export_data();
+ }
+ },
+ close: function(event, ui){ self.close();}
+ });
+ self.$element.removeClass('ui-dialog-content ui-widget-content');
+ self.$element.find('#add_field').click(function() {
+ if ($('#field-tree-structure tr.ui-selected')) {
+ var fld = self.$element.find('#field-tree-structure tr.ui-selected').find('a');
+ for (var i = 0; i < fld.length; i++) {
+ var id = $(fld[i]).attr('id').split('-')[1];
+ var string = $(fld[i]).attr('string');
+ self.add_field(id, string);
+ }
+ self.$element.find('#field-tree-structure tr').removeClass('ui-selected');
+ }
+ });
+ self.$element.find('#remove_field').click(function() {
+ self.$element.find('#fields_list option:selected').remove();
+ });
+ self.$element.find('#remove_all_field').click(function() {
+ self.$element.find('#fields_list').empty();
+ });
+ this.$element.find('#export_new_list').click(this.on_show_save_list);
+
+ var got_fields = new $.Deferred();
+ this.$element.find('#import_compat').change(function() {
+ self.$element.find('#fields_list').empty();
+ self.$element.find('#field-tree-structure').remove();
+ var import_comp = self.$element.find("#import_compat").val();
+ self.rpc("/web/export/get_fields", {
+ model: self.dataset.model,
+ import_compat: Boolean(import_comp)
+ }, function (records) {
+ got_fields.resolve();
+ self.on_show_data(records);
+ });
+ }).change();
+
+ return $.when(
+ got_fields,
+ this.rpc('/web/export/formats', {}, this.do_setup_export_formats),
+ this.show_exports_list());
+ },
+ do_setup_export_formats: function (formats) {
+ var $fmts = this.$element.find('#export_format');
+ _(formats).each(function (format) {
+ $fmts.append(new Option(format[1], format[0]));
+ });
+ },
+ show_exports_list: function() {
+ var self = this;
+ if (self.$element.find('#saved_export_list').is(':hidden')) {
+ self.$element.find('#ExistsExportList').show();
+ return;
+ }
+ return this.exports.read_slice(['name'], {
+ domain: [['resource', '=', this.dataset.model]]
+ }, function (export_list) {
+ if (!export_list.length) {
+ return;
+ }
+ self.$element.find('#ExistsExportList').append(QWeb.render('Exists.ExportList', {'existing_exports': export_list}));
+ self.$element.find('#saved_export_list').change(function() {
+ self.$element.find('#fields_list option').remove();
+ var export_id = self.$element.find('#saved_export_list option:selected').val();
+ if (export_id) {
+ self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}, self.do_load_export_field);
+ }
+ });
+ self.$element.find('#delete_export_list').click(function() {
+ var select_exp = self.$element.find('#saved_export_list option:selected');
+ if (select_exp.val()) {
+ self.exports.unlink([parseInt(select_exp.val(), 10)]);
+ select_exp.remove();
+ if (self.$element.find('#saved_export_list option').length <= 1) {
+ self.$element.find('#ExistsExportList').hide();
+ }
+ }
+ });
+ });
+ },
+ do_load_export_field: function(field_list) {
+ var export_node = this.$element.find("#fields_list");
+ _(field_list).each(function (field) {
+ export_node.append(new Option(field.label, field.name));
+ });
+ },
+ on_show_save_list: function() {
+ var self = this;
+ var current_node = self.$element.find("#savenewlist");
+ if (!(current_node.find("label")).length) {
+ current_node.append(QWeb.render('ExportNewList'));
+ current_node.find("#add_export_list").click(function() {
+ var value = current_node.find("#savelist_name").val();
+ if (value) {
+ self.do_save_export_list(value);
+ } else {
+ alert("Pleae Enter Save Field List Name");
+ }
+ });
+ } else {
+ if (current_node.is(':hidden')) {
+ current_node.show();
+ current_node.find("#savelist_name").val("");
+ } else {
+ current_node.hide();
+ }
+ }
+ },
+ do_save_export_list: function(value) {
+ var self = this;
+ var fields = self.get_fields();
+ if (!fields.length) {
+ return;
+ }
+ this.exports.create({
+ name: value,
+ resource: this.dataset.model,
+ export_fields: _(fields).map(function (field) {
+ return [0, 0, {name: field}];
+ })
+ }, function (export_list_id) {
+ if (!export_list_id.result) {
+ return;
+ }
+ self.$element.find("#saved_export_list").append(
+ new Option(value, export_list_id.result));
+ if (self.$element.find("#saved_export_list").is(":hidden")) {
+ self.show_exports_list();
+ }
+ });
+ this.on_show_save_list();
+ this.$element.find("#fields_list option").remove();
+ },
+ on_click: function(id, record) {
+ var self = this;
+ if (!record['children']) {
+ return;
+ }
+ var model = record['params']['model'],
+ prefix = record['params']['prefix'],
+ name = record['params']['name'];
+
+ if (!record.loaded) {
+ var import_comp = self.$element.find("#import_compat").val();
+ self.rpc("/web/export/get_fields", {
+ model: model,
+ prefix: prefix,
+ parent_name: name,
+ import_compat: Boolean(import_comp),
+ parent_field_type : record['field_type']
+ }, function(results) {
+ record.loaded = true;
+ self.on_show_data(results, record.id);
+ });
+ } else {
+ self.showcontent(record.id);
+ }
+ },
+ on_show_data: function(result, after) {
+ var self = this;
+ var imp_cmpt = Boolean(self.$element.find("#import_compat").val());
+
+ if (after) {
+ var current_tr = self.$element.find("tr[id='treerow-" + after + "']");
+ current_tr.addClass('open');
+ current_tr.find('img').attr('src','/web/static/src/img/collapse.gif');
+ current_tr.after(QWeb.render('ExportTreeView-Secondary.children', {'fields': result}));
+ } else {
+ self.$element.find('#left_field_panel').append(QWeb.render('ExportTreeView-Secondary', {'fields': result}));
+ }
+ _.each(result, function(record) {
+ self.records[record.id] = record.value;
+ if (record.required) {
+ var required_fld = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
+ required_fld.addClass("oe_export_requiredfield");
+ }
+ self.$element.find("img[id='parentimg-" + record.id +"']").click(function() {
+ self.on_click(this.id, record);
+ });
+
+ self.$element.find("tr[id='treerow-" + record.id + "']").click(function(e) {
+ if (e.shiftKey) {
+ var frst_click, scnd_click = '';
+ if (self.row_index == 0) {
+ self.row_index = this.rowIndex;
+ frst_click = self.$element.find("tr[id^='treerow-']")[self.row_index-1];
+ $(frst_click).addClass("ui-selected");
+ } else {
+ if (this.rowIndex >=self.row_index) {
+ for (var i = (self.row_index-1); i < this.rowIndex; i++) {
+ scnd_click = self.$element.find("tr[id^='treerow-']")[i];
+ if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
+ $(scnd_click).addClass("ui-selected");
+ }
+ }
+ } else {
+ for (var i = (self.row_index-1); i >= (this.rowIndex-1); i--) {
+ scnd_click = self.$element.find("tr[id^='treerow-']")[i];
+ if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
+ $(scnd_click).addClass("ui-selected");
+ }
+ }
+ }
+ }
+ }
+ self.row_index = this.rowIndex;
+
+ self.$element.find("tr[id='treerow-" + record.id + "']").keyup(function() {
+ self.row_index = 0;
+ });
+ var o2m_selection = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
+ if ($(o2m_selection).hasClass("oe_export_readonlyfield")) {
+ return false;
+ }
+ if (e.ctrlKey) {
+ if ($(this).hasClass('ui-selected')) {
+ $(this).removeClass('ui-selected').find('a').blur();
+ } else {
+ $(this).addClass('ui-selected').find('a').focus();
+ }
+ } else if (!e.shiftKey) {
+ self.$element.find("tr.ui-selected")
+ .removeClass("ui-selected").find('a').blur();
+ $(this).addClass("ui-selected").find('a').focus();
+ }
+ return false;
+ });
+
+ self.$element.find("tr[id='treerow-" + record.id + "']").keydown(function(e) {
+ var keyCode = e.keyCode || e.which;
+ var arrow = {left: 37, up: 38, right: 39, down: 40 };
+ switch (keyCode) {
+ case arrow.left:
+ if ($(this).hasClass('open')) {
+ self.on_click(this.id, record);
+ }
+ break;
+ case arrow.right:
+ if (!$(this).hasClass('open')) {
+ self.on_click(this.id, record);
+ }
+ break;
+ case arrow.up:
+ var elem = this;
+ $(elem).removeClass("ui-selected");
+ while (!$(elem).prev().is(":visible")) {
+ elem = $(elem).prev();
+ }
+ if (!$(elem).prev().find('#tree-column').hasClass("oe_export_readonlyfield")) {
+ $(elem).prev().addClass("ui-selected");
+ }
+ $(elem).prev().find('a').focus();
+ break;
+ case arrow.down:
+ var elem = this;
+ $(elem).removeClass("ui-selected");
+ while(!$(elem).next().is(":visible")) {
+ elem = $(elem).next();
+ }
+ if (!$(elem).next().find('#tree-column').hasClass("oe_export_readonlyfield")) {
+ $(elem).next().addClass("ui-selected");
+ }
+ $(elem).next().find('a').focus();
+ break;
+ }
+ });
+ self.$element.find("tr[id='treerow-" + record.id + "']").dblclick(function() {
+ var $o2m_selection = self.$element.find("tr[id^='treerow-" + record.id + "']").find('#tree-column');
+ if (!$o2m_selection.hasClass("oe_export_readonlyfield")) {
+ self.add_field(record.id, $(this).find("a").attr("string"));
+ }
+ });
+ });
+ self.$element.find('#fields_list').mouseover(function(event) {
+ if (event.relatedTarget) {
+ if (event.relatedTarget.attributes['id'] && event.relatedTarget.attributes['string']) {
+ var field_id = event.relatedTarget.attributes["id"]["value"];
+ if (field_id && field_id.split("-")[0] === 'export') {
+ if (!self.$element.find("tr[id='treerow-" + field_id.split("-")[1] + "']").find('#tree-column').hasClass("oe_export_readonlyfield")) {
+ self.add_field(field_id.split("-")[1], event.relatedTarget.attributes["string"]["value"]);
+ }
+ }
+ }
+ }
+ });
+ },
+ showcontent: function(id) {
+ // show & hide the contents
+ var $this = this.$element.find("tr[id='treerow-" + id + "']");
+ var is_open = $this.hasClass('open');
+ $this.toggleClass('open');
+
+ var first_child = $this.find('img');
+ if (is_open) {
+ first_child.attr('src', '/web/static/src/img/expand.gif');
+ } else {
+ first_child.attr('src', '/web/static/src/img/collapse.gif');
+ }
+ var child_field = this.$element.find("tr[id^='treerow-" + id +"/']");
+ var child_len = (id.split("/")).length + 1;
+ for (var i = 0; i < child_field.length; i++) {
+ var $child = $(child_field[i]);
+ if (is_open) {
+ $child.hide();
+ } else if (child_len == (child_field[i].id.split("/")).length) {
+ if ($child.hasClass('open')) {
+ $child.removeClass('open');
+ $child.find('img').attr('src', '/web/static/src/img/expand.gif');
+ }
+ $child.show();
+ }
+ }
+ },
+ add_field: function(field_id, string) {
+ var field_list = this.$element.find('#fields_list');
+ if (this.$element.find("#fields_list option[value='" + field_id + "']")
+ && !this.$element.find("#fields_list option[value='" + field_id + "']").length) {
+ field_list.append(new Option(string, field_id));
+ }
+ },
+ get_fields: function() {
+ var export_field = [];
+ this.$element.find("#fields_list option").each(function() {
+ export_field.push($(this).val());
+ });
+ if (!export_field.length) {
+ alert('Please select fields to save export list...');
+ }
+ return export_field;
+ },
+ on_click_export_data: function() {
+ $.blockUI(this.$element);
+ var exported_fields = [], self = this;
+ this.$element.find("#fields_list option").each(function() {
+ var fieldname = self.records[$(this).val()];
+ exported_fields.push({name: fieldname, label: $(this).text()});
+ });
+ if (_.isEmpty(exported_fields)) {
+ alert('Please select fields to export...');
+ return;
+ }
+
+ exported_fields.unshift({name: 'id', label: 'External ID'});
+ var export_format = this.$element.find("#export_format").val();
+ this.session.get_file({
+ url: '/web/export/' + export_format,
+ data: {data: JSON.stringify({
+ model: this.dataset.model,
+ fields: exported_fields,
+ ids: this.dataset.ids,
+ domain: this.dataset.domain,
+ import_compat: Boolean(
+ this.$element.find("#import_compat").val())
+ })},
+ complete: $.unblockUI
+ });
+ },
+ close: function() {
+ $(this.$dialog).remove();
+ this._super();
+ }
+});
+
+};
diff --git a/addons/web/static/src/js/dates.js b/addons/web/static/src/js/dates.js
new file mode 100644
index 00000000000..036cf8cd90b
--- /dev/null
+++ b/addons/web/static/src/js/dates.js
@@ -0,0 +1,138 @@
+
+openerp.web.dates = function(openerp) {
+
+/**
+ * Converts a string to a Date javascript object using OpenERP's
+ * datetime string format (exemple: '2011-12-01 15:12:35').
+ *
+ * The timezone is assumed to be UTC (standard for OpenERP 6.1)
+ * and will be converted to the browser's timezone.
+ *
+ * @param {String} str A string representing a datetime.
+ * @returns {Date}
+ */
+openerp.web.str_to_datetime = function(str) {
+ if(!str) {
+ return str;
+ }
+ var regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/;
+ var res = regex.exec(str);
+ if ( !res ) {
+ throw "'" + str + "' is not a valid datetime";
+ }
+ var obj = Date.parse(res[1] + " GMT");
+ if (! obj) {
+ throw "'" + str + "' is not a valid datetime";
+ }
+ return obj;
+};
+
+/**
+ * Converts a string to a Date javascript object using OpenERP's
+ * date string format (exemple: '2011-12-01').
+ *
+ * @param {String} str A string representing a date.
+ * @returns {Date}
+ */
+openerp.web.str_to_date = function(str) {
+ if(!str) {
+ return str;
+ }
+ var regex = /^\d\d\d\d-\d\d-\d\d$/;
+ var res = regex.exec(str);
+ if ( !res ) {
+ throw "'" + str + "' is not a valid date";
+ }
+ var obj = Date.parse(str);
+ if (! obj) {
+ throw "'" + str + "' is not a valid date";
+ }
+ return obj;
+};
+
+/**
+ * Converts a string to a Date javascript object using OpenERP's
+ * time string format (exemple: '15:12:35').
+ *
+ * @param {String} str A string representing a time.
+ * @returns {Date}
+ */
+openerp.web.str_to_time = function(str) {
+ if(!str) {
+ return str;
+ }
+ var regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/;
+ var res = regex.exec(str);
+ if ( !res ) {
+ throw "'" + str + "' is not a valid time";
+ }
+ var obj = Date.parse(res[1]);
+ if (! obj) {
+ throw "'" + str + "' is not a valid time";
+ }
+ return obj;
+};
+
+/*
+ * Left-pad provided arg 1 with zeroes until reaching size provided by second
+ * argument.
+ *
+ * @param {Number|String} str value to pad
+ * @param {Number} size size to reach on the final padded value
+ * @returns {String} padded string
+ */
+var zpad = function(str, size) {
+ str = "" + str;
+ return new Array(size - str.length + 1).join('0') + str;
+};
+
+/**
+ * Converts a Date javascript object to a string using OpenERP's
+ * datetime string format (exemple: '2011-12-01 15:12:35').
+ *
+ * The timezone of the Date object is assumed to be the one of the
+ * browser and it will be converted to UTC (standard for OpenERP 6.1).
+ *
+ * @param {Date} obj
+ * @returns {String} A string representing a datetime.
+ */
+openerp.web.datetime_to_str = function(obj) {
+ if (!obj) {
+ return false;
+ }
+ return zpad(obj.getUTCFullYear(),4) + "-" + zpad(obj.getUTCMonth() + 1,2) + "-"
+ + zpad(obj.getUTCDate(),2) + " " + zpad(obj.getUTCHours(),2) + ":"
+ + zpad(obj.getUTCMinutes(),2) + ":" + zpad(obj.getUTCSeconds(),2);
+};
+
+/**
+ * Converts a Date javascript object to a string using OpenERP's
+ * date string format (exemple: '2011-12-01').
+ *
+ * @param {Date} obj
+ * @returns {String} A string representing a date.
+ */
+openerp.web.date_to_str = function(obj) {
+ if (!obj) {
+ return false;
+ }
+ return zpad(obj.getFullYear(),4) + "-" + zpad(obj.getMonth() + 1,2) + "-"
+ + zpad(obj.getDate(),2);
+};
+
+/**
+ * Converts a Date javascript object to a string using OpenERP's
+ * time string format (exemple: '15:12:35').
+ *
+ * @param {Date} obj
+ * @returns {String} A string representing a time.
+ */
+openerp.web.time_to_str = function(obj) {
+ if (!obj) {
+ return false;
+ }
+ return zpad(obj.getHours(),2) + ":" + zpad(obj.getMinutes(),2) + ":"
+ + zpad(obj.getSeconds(),2);
+};
+
+};
diff --git a/addons/web/static/src/js/form.js b/addons/web/static/src/js/form.js
new file mode 100644
index 00000000000..c4540d591a2
--- /dev/null
+++ b/addons/web/static/src/js/form.js
@@ -0,0 +1,2588 @@
+openerp.web.form = function (openerp) {
+
+var _t = openerp.web._t;
+var QWeb = openerp.web.qweb;
+
+openerp.web.views.add('form', 'openerp.web.FormView');
+openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# */{
+ /**
+ * Indicates that this view is not searchable, and thus that no search
+ * view should be displayed (if there is one active).
+ */
+ searchable: false,
+ template: "FormView",
+ /**
+ * @constructs openerp.web.FormView
+ * @extends openerp.web.View
+ *
+ * @param {openerp.web.Session} session the current openerp session
+ * @param {String} element_id this view's root element id
+ * @param {openerp.web.DataSet} dataset the dataset this view will work with
+ * @param {String} view_id the identifier of the OpenERP view object
+ *
+ * @property {openerp.web.Registry} registry=openerp.web.form.widgets widgets registry for this form view instance
+ */
+ init: function(parent, element_id, dataset, view_id, options) {
+ this._super(parent, element_id);
+ this.set_default_options(options);
+ this.dataset = dataset;
+ this.model = dataset.model;
+ this.view_id = view_id;
+ this.fields_view = {};
+ this.widgets = {};
+ this.widgets_counter = 0;
+ this.fields = {};
+ this.datarecord = {};
+ this.ready = false;
+ this.show_invalid = true;
+ this.dirty = false;
+ this.default_focus_field = null;
+ this.default_focus_button = null;
+ this.registry = openerp.web.form.widgets;
+ this.has_been_loaded = $.Deferred();
+ this.$form_header = null;
+ this.translatable_fields = [];
+ _.defaults(this.options, {"always_show_new_button": true});
+ },
+ start: function() {
+ if (this.embedded_view) {
+ var def = $.Deferred().then(this.on_loaded);
+ var self = this;
+ setTimeout(function() {def.resolve(self.embedded_view);}, 0);
+ return def.promise();
+ } else {
+ var context = new openerp.web.CompoundContext(this.dataset.get_context());
+ return this.rpc("/web/view/load", {
+ "model": this.model,
+ "view_id": this.view_id,
+ "view_type": "form",
+ toolbar: this.options.sidebar,
+ context: context
+ }, this.on_loaded);
+ }
+ },
+ stop: function() {
+ if (this.sidebar) {
+ this.sidebar.attachments.stop();
+ this.sidebar.stop();
+ }
+ _.each(this.widgets, function(w) {
+ w.stop();
+ });
+ },
+ on_loaded: function(data) {
+ var self = this;
+ this.fields_view = data;
+ var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch);
+
+ this.$element.html(QWeb.render(this.template, { 'frame': frame, 'view': this }));
+ _.each(this.widgets, function(w) {
+ w.start();
+ });
+ this.$form_header = this.$element.find('#' + this.element_id + '_header');
+ this.$form_header.find('div.oe_form_pager button[data-pager-action]').click(function() {
+ var action = $(this).data('pager-action');
+ self.on_pager_action(action);
+ });
+
+ this.$form_header.find('button.oe_form_button_save').click(this.do_save);
+ this.$form_header.find('button.oe_form_button_save_edit').click(this.do_save_edit);
+ this.$form_header.find('button.oe_form_button_cancel').click(this.do_cancel);
+ this.$form_header.find('button.oe_form_button_new').click(this.on_button_new);
+
+ if (this.session.debug) {
+ this.$form_header.find('button.oe_get_xml_view').click(function() {
+ $('<xmp>' + openerp.web.json_node_to_xml(self.fields_view.arch, true) + '</xmp>').dialog({ width: '95%', height: 600});
+ });
+ }
+
+ if (this.options.sidebar && this.options.sidebar_id) {
+ this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
+ this.sidebar.start();
+ this.sidebar.do_unfold();
+ this.sidebar.attachments = new openerp.web.form.SidebarAttachments(this.sidebar, this.sidebar.add_section('attachments', "Attachments"), this);
+ this.sidebar.add_toolbar(this.fields_view.toolbar);
+ this.set_common_sidebar_sections(this.sidebar);
+ }
+ this.has_been_loaded.resolve();
+ },
+ do_show: function () {
+ var promise;
+ if (this.dataset.index === null) {
+ // null index means we should start a new record
+ promise = this.on_button_new();
+ } else {
+ promise = this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
+ }
+ this.$element.show();
+ if (this.sidebar) {
+ this.sidebar.$element.show();
+ }
+ return promise;
+ },
+ do_hide: function () {
+ this.$element.hide();
+ if (this.sidebar) {
+ this.sidebar.$element.hide();
+ }
+ },
+ on_record_loaded: function(record) {
+ if (!record) {
+ throw("Form: No record received");
+ }
+ if (!record.id) {
+ this.$form_header.find('.oe_form_on_create').show();
+ this.$form_header.find('.oe_form_on_update').hide();
+ if (!this.options["always_show_new_button"]) {
+ this.$form_header.find('button.oe_form_button_new').hide();
+ }
+ } else {
+ this.$form_header.find('.oe_form_on_create').hide();
+ this.$form_header.find('.oe_form_on_update').show();
+ this.$form_header.find('button.oe_form_button_new').show();
+ }
+ this.dirty = false;
+ this.datarecord = record;
+ for (var f in this.fields) {
+ var field = this.fields[f];
+ field.dirty = false;
+ field.set_value(this.datarecord[f] || false);
+ field.validate();
+ }
+ if (!record.id) {
+ // New record: Second pass in order to trigger the onchanges
+ this.dirty = true;
+ this.show_invalid = false;
+ for (var f in record) {
+ var field = this.fields[f];
+ if (field) {
+ field.dirty = true;
+ this.do_onchange(field);
+ }
+ }
+ }
+ this.on_form_changed();
+ this.show_invalid = this.ready = true;
+ this.do_update_pager(record.id == null);
+ if (this.sidebar) {
+ this.sidebar.attachments.do_update();
+ this.sidebar.$element.find('.oe_sidebar_translate').toggleClass('oe_hide', !record.id);
+ }
+ if (this.default_focus_field && !this.embedded_view) {
+ this.default_focus_field.focus();
+ }
+ },
+ on_form_changed: function() {
+ for (var w in this.widgets) {
+ w = this.widgets[w];
+ w.process_modifiers();
+ w.update_dom();
+ }
+ },
+ on_pager_action: function(action) {
+ switch (action) {
+ case 'first':
+ this.dataset.index = 0;
+ break;
+ case 'previous':
+ this.dataset.previous();
+ break;
+ case 'next':
+ this.dataset.next();
+ break;
+ case 'last':
+ this.dataset.index = this.dataset.ids.length - 1;
+ break;
+ }
+ this.reload();
+ },
+ do_update_pager: function(hide_index) {
+ var $pager = this.$element.find('#' + this.element_id + '_header div.oe_form_pager');
+ var index = hide_index ? '-' : this.dataset.index + 1;
+ $pager.find('span.oe_pager_index').html(index);
+ $pager.find('span.oe_pager_count').html(this.dataset.ids.length);
+ },
+ do_onchange: function(widget, processed) {
+ processed = processed || [];
+ if (widget.node.attrs.on_change) {
+ var self = this;
+ this.ready = false;
+ var onchange = _.trim(widget.node.attrs.on_change);
+ var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
+ if (call) {
+ var method = call[1], args = [];
+ var context_index = null;
+ var argument_replacement = {
+ 'False' : function() {return false;},
+ 'True' : function() {return true;},
+ 'None' : function() {return null;},
+ 'context': function(i) {
+ context_index = i;
+ var ctx = widget.build_context ? widget.build_context() : {};
+ return ctx;
+ }
+ };
+ var parent_fields = null;
+ _.each(call[2].split(','), function(a, i) {
+ var field = _.trim(a);
+ if (field in argument_replacement) {
+ args.push(argument_replacement[field](i));
+ return;
+ } else if (self.fields[field]) {
+ var value = self.fields[field].get_on_change_value();
+ args.push(value == null ? false : value);
+ return;
+ } else {
+ var splitted = field.split('.');
+ if (splitted.length > 1 && _.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
+ if (parent_fields === null) {
+ parent_fields = self.dataset.parent_view.get_fields_values();
+ }
+ var p_val = parent_fields[_.trim(splitted[1])];
+ if (p_val !== undefined) {
+ args.push(p_val == null ? false : p_val);
+ return;
+ }
+ }
+ }
+ throw "Could not get field with name '" + field +
+ "' for onchange '" + onchange + "'";
+ });
+ var ajax = {
+ url: '/web/dataset/call',
+ async: false
+ };
+ return this.rpc(ajax, {
+ model: this.dataset.model,
+ method: method,
+ args: [(this.datarecord.id == null ? [] : [this.datarecord.id])].concat(args),
+ context_id: context_index === null ? null : context_index + 1
+ }, function(response) {
+ self.on_processed_onchange(response, processed);
+ });
+ } else {
+ console.log("Wrong on_change format", on_change);
+ }
+ }
+ },
+ on_processed_onchange: function(response, processed) {
+ var result = response;
+ if (result.value) {
+ for (var f in result.value) {
+ var field = this.fields[f];
+ // If field is not defined in the view, just ignore it
+ if (field) {
+ var value = result.value[f];
+ processed.push(field.name);
+ if (field.get_value() != value) {
+ field.set_value(value);
+ field.dirty = true;
+ if (_.indexOf(processed, field.name) < 0) {
+ this.do_onchange(field, processed);
+ }
+ }
+ }
+ }
+ this.on_form_changed();
+ }
+ if (!_.isEmpty(result.warning)) {
+ $(QWeb.render("DialogWarning", result.warning)).dialog({
+ modal: true,
+ buttons: {
+ Ok: function() {
+ $(this).dialog("close");
+ }
+ }
+ });
+ }
+ if (result.domain) {
+ // TODO:
+ }
+ this.ready = true;
+ },
+ on_button_new: function() {
+ var self = this;
+ var def = $.Deferred();
+ $.when(this.has_been_loaded).then(function() {
+ self.dataset.default_get(
+ _.keys(self.fields_view.fields)).then(self.on_record_loaded).then(function() {
+ def.resolve();
+ });
+ });
+ return def.promise();
+ },
+ /**
+ * Triggers saving the form's record. Chooses between creating a new
+ * record or saving an existing one depending on whether the record
+ * already has an id property.
+ *
+ * @param {Function} success callback on save success
+ * @param {Boolean} [prepend_on_create=false] if ``do_save`` creates a new record, should that record be inserted at the start of the dataset (by default, records are added at the end)
+ */
+ do_save: function(success, prepend_on_create) {
+ var self = this;
+ if (!this.ready) {
+ return false;
+ }
+ var form_dirty = false,
+ form_invalid = false,
+ values = {},
+ first_invalid_field = null;
+ for (var f in this.fields) {
+ f = this.fields[f];
+ if (!f.is_valid()) {
+ form_invalid = true;
+ f.update_dom();
+ if (!first_invalid_field) {
+ first_invalid_field = f;
+ }
+ } else if (f.is_dirty()) {
+ form_dirty = true;
+ values[f.name] = f.get_value();
+ }
+ }
+ if (form_invalid) {
+ first_invalid_field.focus();
+ this.on_invalid();
+ return false;
+ } else if (form_dirty) {
+ console.log("About to save", values);
+ if (!this.datarecord.id) {
+ return this.dataset.create(values, function(r) {
+ self.on_created(r, success, prepend_on_create);
+ });
+ } else {
+ return this.dataset.write(this.datarecord.id, values, {}, function(r) {
+ self.on_saved(r, success);
+ });
+ }
+ } else {
+ setTimeout(function() {
+ self.on_saved({ result: true }, success);
+ });
+ return true;
+ }
+ },
+ do_save_edit: function() {
+ this.do_save();
+ //this.switch_readonly(); Use promises
+ },
+ switch_readonly: function() {
+ },
+ switch_editable: function() {
+ },
+ on_invalid: function() {
+ var msg = "<ul>";
+ _.each(this.fields, function(f) {
+ if (!f.is_valid()) {
+ msg += "<li>" + f.string + "</li>";
+ }
+ });
+ msg += "</ul>";
+ this.notification.warn("The following fields are invalid :", msg);
+ },
+ on_saved: function(r, success) {
+ if (!r.result) {
+ // should not happen in the server, but may happen for internal purpose
+ } else {
+ console.debug(_.sprintf("The record #%s has been saved.", this.datarecord.id));
+ if (success) {
+ success(r);
+ }
+ this.reload();
+ }
+ },
+ /**
+ * Updates the form' dataset to contain the new record:
+ *
+ * * Adds the newly created record to the current dataset (at the end by
+ * default)
+ * * Selects that record (sets the dataset's index to point to the new
+ * record's id).
+ * * Updates the pager and sidebar displays
+ *
+ * @param {Object} r
+ * @param {Function} success callback to execute after having updated the dataset
+ * @param {Boolean} [prepend_on_create=false] adds the newly created record at the beginning of the dataset instead of the end
+ */
+ on_created: function(r, success, prepend_on_create) {
+ if (!r.result) {
+ // should not happen in the server, but may happen for internal purpose
+ } else {
+ this.datarecord.id = r.result;
+ if (!prepend_on_create) {
+ this.dataset.ids.push(this.datarecord.id);
+ this.dataset.index = this.dataset.ids.length - 1;
+ } else {
+ this.dataset.ids.unshift(this.datarecord.id);
+ this.dataset.index = 0;
+ }
+ this.do_update_pager();
+ if (this.sidebar) {
+ this.sidebar.attachments.do_update();
+ }
+ console.debug("The record has been created with id #" + this.datarecord.id);
+ if (success) {
+ success(_.extend(r, {created: true}));
+ }
+ this.reload();
+ }
+ },
+ do_search: function (domains, contexts, groupbys) {
+ console.debug("Searching form");
+ },
+ on_action: function (action) {
+ console.debug('Executing action', action);
+ },
+ do_cancel: function () {
+ console.debug("Cancelling form");
+ },
+ reload: function() {
+ if (this.dataset.index == null || this.dataset.index < 0) {
+ this.on_button_new();
+ } else {
+ this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
+ }
+ },
+ get_fields_values: function() {
+ var values = {};
+ _.each(this.fields, function(value, key) {
+ var val = value.get_value();
+ values[key] = val;
+ });
+ return values;
+ },
+ get_selected_ids: function() {
+ var id = this.dataset.ids[this.dataset.index];
+ return id ? [id] : [];
+ }
+});
+openerp.web.FormDialog = openerp.web.Dialog.extend({
+ init: function(parent, options, view_id, dataset) {
+ this._super(parent, options);
+ this.dataset = dataset;
+ this.view_id = view_id;
+ return this;
+ },
+ start: function() {
+ this._super();
+ this.form = new openerp.web.FormView(this, this.element_id, this.dataset, this.view_id, {
+ sidebar: false,
+ pager: false
+ });
+ this.form.start();
+ this.form.on_created.add_last(this.on_form_dialog_saved);
+ this.form.on_saved.add_last(this.on_form_dialog_saved);
+ return this;
+ },
+ load_id: function(id) {
+ var self = this;
+ return this.dataset.read_ids([id], _.keys(this.form.fields_view.fields), function(records) {
+ self.form.on_record_loaded(records[0]);
+ });
+ },
+ on_form_dialog_saved: function(r) {
+ this.close();
+ }
+});
+
+/** @namespace */
+openerp.web.form = {};
+
+openerp.web.form.SidebarAttachments = openerp.web.Widget.extend({
+ init: function(parent, element_id, form_view) {
+ this._super(parent, element_id);
+ this.view = form_view;
+ },
+ do_update: function() {
+ if (!this.view.datarecord.id) {
+ this.on_attachments_loaded([]);
+ } else {
+ (new openerp.web.DataSetSearch(
+ this, 'ir.attachment', this.view.dataset.get_context(),
+ [
+ ['res_model', '=', this.view.dataset.model],
+ ['res_id', '=', this.view.datarecord.id],
+ ['type', 'in', ['binary', 'url']]
+ ])).read_slice(['name', 'url', 'type'], {}, this.on_attachments_loaded);
+ }
+ },
+ on_attachments_loaded: function(attachments) {
+ this.attachments = attachments;
+ this.$element.html(QWeb.render('FormView.sidebar.attachments', this));
+ this.$element.find('.oe-binary-file').change(this.on_attachment_changed);
+ this.$element.find('.oe-sidebar-attachment-delete').click(this.on_attachment_delete);
+ },
+ on_attachment_changed: function(e) {
+ window[this.element_id + '_iframe'] = this.do_update;
+ var $e = $(e.target);
+ if ($e.val() != '') {
+ this.$element.find('form.oe-binary-form').submit();
+ $e.parent().find('input[type=file]').attr('disabled', 'true');
+ $e.parent().find('button').attr('disabled', 'true').find('img, span').toggle();
+ }
+ },
+ on_attachment_delete: function(e) {
+ var self = this, $e = $(e.currentTarget);
+ var name = _.trim($e.parent().find('a.oe-sidebar-attachments-link').text());
+ if (confirm("Do you really want to delete the attachment " + name + " ?")) {
+ this.rpc('/web/dataset/unlink', {
+ model: 'ir.attachment',
+ ids: [parseInt($e.attr('data-id'))]
+ }, function(r) {
+ $e.parent().remove();
+ self.notification.notify("Delete an attachment", "The attachment '" + name + "' has been deleted");
+ });
+ }
+ }
+});
+
+openerp.web.form.compute_domain = function(expr, fields) {
+ var stack = [];
+ for (var i = expr.length - 1; i >= 0; i--) {
+ var ex = expr[i];
+ if (ex.length == 1) {
+ var top = stack.pop();
+ switch (ex) {
+ case '|':
+ stack.push(stack.pop() || top);
+ continue;
+ case '&':
+ stack.push(stack.pop() && top);
+ continue;
+ case '!':
+ stack.push(!top);
+ continue;
+ default:
+ throw new Error('Unknown domain operator ' + ex);
+ }
+ }
+
+ var field = fields[ex[0]];
+ if (!field) {
+ throw new Error("Domain references unknown field : " + ex[0]);
+ }
+ var field_value = field.get_value ? fields[ex[0]].get_value() : fields[ex[0]].value;
+ var op = ex[1];
+ var val = ex[2];
+
+ switch (op.toLowerCase()) {
+ case '=':
+ case '==':
+ stack.push(field_value == val);
+ break;
+ case '!=':
+ case '<>':
+ stack.push(field_value != val);
+ break;
+ case '<':
+ stack.push(field_value < val);
+ break;
+ case '>':
+ stack.push(field_value > val);
+ break;
+ case '<=':
+ stack.push(field_value <= val);
+ break;
+ case '>=':
+ stack.push(field_value >= val);
+ break;
+ case 'in':
+ stack.push(_(val).contains(field_value));
+ break;
+ case 'not in':
+ stack.push(!_(val).contains(field_value));
+ break;
+ default:
+ console.log("Unsupported operator in modifiers :", op);
+ }
+ }
+ return _.all(stack, _.identity);
+};
+
+openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.Widget# */{
+ template: 'Widget',
+ /**
+ * @constructs openerp.web.form.Widget
+ * @extends openerp.web.Widget
+ *
+ * @param view
+ * @param node
+ */
+ init: function(view, node) {
+ this.view = view;
+ this.node = node;
+ this.modifiers = JSON.parse(this.node.attrs.modifiers || '{}');
+ this.type = this.type || node.tag;
+ this.element_name = this.element_name || this.type;
+ this.element_id = [this.view.element_id, this.element_name, this.view.widgets_counter++].join("_");
+
+ this._super(view, this.element_id);
+
+ this.view.widgets[this.element_id] = this;
+ this.children = node.children;
+ this.colspan = parseInt(node.attrs.colspan || 1, 10);
+ this.decrease_max_width = 0;
+
+ this.string = this.string || node.attrs.string;
+ this.help = this.help || node.attrs.help;
+ this.invisible = this.modifiers['invisible'] === true;
+ this.classname = 'oe_form_' + this.type;
+
+ this.width = this.node.attrs.width;
+ },
+ start: function() {
+ this.$element = $('#' + this.element_id);
+ },
+ stop: function() {
+ if (this.$element) {
+ this.$element.remove();
+ }
+ },
+ process_modifiers: function() {
+ var compute_domain = openerp.web.form.compute_domain;
+ for (var a in this.modifiers) {
+ this[a] = compute_domain(this.modifiers[a], this.view.fields);
+ }
+ },
+ update_dom: function() {
+ this.$element.toggle(!this.invisible);
+ },
+ render: function() {
+ var template = this.template;
+ return QWeb.render(template, { "widget": this });
+ }
+});
+
+openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({
+ template: 'WidgetFrame',
+ init: function(view, node) {
+ this._super(view, node);
+ this.columns = parseInt(node.attrs.col || 4, 10);
+ this.x = 0;
+ this.y = 0;
+ this.table = [];
+ this.add_row();
+ for (var i = 0; i < node.children.length; i++) {
+ var n = node.children[i];
+ if (n.tag == "newline") {
+ this.add_row();
+ } else {
+ this.handle_node(n);
+ }
+ }
+ this.set_row_cells_with(this.table[this.table.length - 1]);
+ },
+ add_row: function(){
+ if (this.table.length) {
+ this.set_row_cells_with(this.table[this.table.length - 1]);
+ }
+ var row = [];
+ this.table.push(row);
+ this.x = 0;
+ this.y += 1;
+ return row;
+ },
+ set_row_cells_with: function(row) {
+ var bypass = 0,
+ max_width = 100;
+ for (var i = 0; i < row.length; i++) {
+ bypass += row[i].width === undefined ? 0 : 1;
+ max_width -= row[i].decrease_max_width;
+ }
+ var size_unit = Math.round(max_width / (this.columns - bypass)),
+ colspan_sum = 0;
+ for (var i = 0; i < row.length; i++) {
+ var w = row[i];
+ colspan_sum += w.colspan;
+ if (w.width === undefined) {
+ var width = (i === row.length - 1 && colspan_sum === this.columns) ? max_width : Math.round(size_unit * w.colspan);
+ max_width -= width;
+ w.width = width + '%';
+ }
+ }
+ },
+ handle_node: function(node) {
+ var type = {};
+ if (node.tag == 'field') {
+ type = this.view.fields_view.fields[node.attrs.name] || {};
+ }
+ var widget = new (this.view.registry.get_any(
+ [node.attrs.widget, type.type, node.tag])) (this.view, node);
+ if (node.tag == 'field') {
+ if (!this.view.default_focus_field || node.attrs.default_focus == '1') {
+ this.view.default_focus_field = widget;
+ }
+ if (node.attrs.nolabel != '1') {
+ var label = new (this.view.registry.get_object('label')) (this.view, node);
+ label["for"] = widget;
+ this.add_widget(label, widget.colspan + 1);
+ }
+ }
+ this.add_widget(widget);
+ },
+ add_widget: function(widget, colspan) {
+ colspan = colspan || widget.colspan;
+ var current_row = this.table[this.table.length - 1];
+ if (current_row.length && (this.x + colspan) > this.columns) {
+ current_row = this.add_row();
+ }
+ current_row.push(widget);
+ this.x += widget.colspan;
+ return widget;
+ }
+});
+
+openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({
+ template: 'WidgetNotebook',
+ init: function(view, node) {
+ this._super(view, node);
+ this.pages = [];
+ for (var i = 0; i < node.children.length; i++) {
+ var n = node.children[i];
+ if (n.tag == "page") {
+ var page = new openerp.web.form.WidgetNotebookPage(this.view, n, this, this.pages.length);
+ this.pages.push(page);
+ }
+ }
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.tabs();
+ this.view.on_button_new.add_last(this.do_select_first_visible_tab);
+ },
+ do_select_first_visible_tab: function() {
+ for (var i = 0; i < this.pages.length; i++) {
+ var page = this.pages[i];
+ if (page.invisible === false) {
+ this.$element.tabs('select', page.index);
+ break;
+ }
+ }
+ }
+});
+
+openerp.web.form.WidgetNotebookPage = openerp.web.form.WidgetFrame.extend({
+ template: 'WidgetNotebookPage',
+ init: function(view, node, notebook, index) {
+ this.notebook = notebook;
+ this.index = index;
+ this.element_name = 'page_' + index;
+ this._super(view, node);
+ this.element_tab_id = this.element_id + '_tab';
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element_tab = $('#' + this.element_tab_id);
+ },
+ update_dom: function() {
+ if (this.invisible && this.index === this.notebook.$element.tabs('option', 'selected')) {
+ this.notebook.do_select_first_visible_tab();
+ }
+ this.$element_tab.toggle(!this.invisible);
+ this.$element.toggle(!this.invisible);
+ }
+});
+
+openerp.web.form.WidgetSeparator = openerp.web.form.Widget.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "WidgetSeparator";
+ this.orientation = node.attrs.orientation || 'horizontal';
+ if (this.orientation === 'vertical') {
+ this.width = '1';
+ }
+ this.classname += '_' + this.orientation;
+ }
+});
+
+openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "WidgetButton";
+ if (this.string) {
+ // We don't have button key bindings in the webclient
+ this.string = this.string.replace(/_/g, '');
+ }
+ if (node.attrs.default_focus == '1') {
+ // TODO fme: provide enter key binding to widgets
+ this.view.default_focus_button = this;
+ }
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.click(this.on_click);
+ },
+ on_click: function(saved) {
+ var self = this;
+ if (!this.node.attrs.special && this.view.dirty && saved !== true) {
+ this.view.do_save(function() {
+ self.on_click(true);
+ });
+ } else {
+ if (this.node.attrs.confirm) {
+ var dialog = $('<div>' + this.node.attrs.confirm + '</div>').dialog({
+ title: 'Confirm',
+ modal: true,
+ buttons: {
+ Ok: function() {
+ self.on_confirmed();
+ $(this).dialog("close");
+ },
+ Cancel: function() {
+ $(this).dialog("close");
+ }
+ }
+ });
+ } else {
+ this.on_confirmed();
+ }
+ }
+ },
+ on_confirmed: function() {
+ var self = this;
+
+ this.view.execute_action(
+ this.node.attrs, this.view.dataset, this.view.datarecord.id, function () {
+ self.view.reload();
+ });
+ }
+});
+
+openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
+ init: function(view, node) {
+ this.element_name = 'label_' + node.attrs.name;
+
+ this._super(view, node);
+
+ // TODO fme: support for attrs.align
+ if (this.node.tag == 'label' && (this.node.attrs.colspan || (this.string && this.string.length > 32))) {
+ this.template = "WidgetParagraph";
+ this.colspan = parseInt(this.node.attrs.colspan || 1, 10);
+ } else {
+ this.template = "WidgetLabel";
+ this.colspan = 1;
+ this.width = '1%';
+ this.decrease_max_width = 1;
+ this.nowrap = true;
+ }
+ },
+ render: function () {
+ if (this['for'] && this.type !== 'label') {
+ return QWeb.render(this.template, {widget: this['for']});
+ }
+ // Actual label widgets should not have a false and have type label
+ return QWeb.render(this.template, {widget: this});
+ },
+ start: function() {
+ this._super();
+ var self = this;
+ this.$element.find("label").dblclick(function() {
+ var widget = self['for'] || self;
+ console.log(widget.element_id , widget);
+ window.w = widget;
+ });
+ }
+});
+
+openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.form.Field# */{
+ /**
+ * @constructs openerp.web.form.Field
+ * @extends openerp.web.form.Widget
+ *
+ * @param view
+ * @param node
+ */
+ init: function(view, node) {
+ this.name = node.attrs.name;
+ this.value = undefined;
+ view.fields[this.name] = this;
+ this.type = node.attrs.widget || view.fields_view.fields[node.attrs.name].type;
+ this.element_name = "field_" + this.name + "_" + this.type;
+
+ this._super(view, node);
+
+ if (node.attrs.nolabel != '1' && this.colspan > 1) {
+ this.colspan--;
+ }
+ this.field = view.fields_view.fields[node.attrs.name] || {};
+ this.string = node.attrs.string || this.field.string;
+ this.help = node.attrs.help || this.field.help;
+ this.nolabel = (this.field.nolabel || node.attrs.nolabel) === '1';
+ this.readonly = this.modifiers['readonly'] === true;
+ this.required = this.modifiers['required'] === true;
+ this.invalid = false;
+ this.dirty = false;
+
+ this.classname = 'oe_form_field_' + this.type;
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ if (this.field.translate) {
+ this.view.translatable_fields.push(this);
+ this.$element.find('.oe_field_translate').click(this.on_translate);
+ }
+ },
+ set_value: function(value) {
+ this.value = value;
+ this.invalid = false;
+ this.update_dom();
+ this.on_value_changed();
+ },
+ set_value_from_ui: function() {
+ this.on_value_changed();
+ },
+ on_value_changed: function() {
+ },
+ on_translate: function() {
+ this.view.open_translate_dialog(this);
+ },
+ get_value: function() {
+ return this.value;
+ },
+ is_valid: function() {
+ return !this.invalid;
+ },
+ is_dirty: function() {
+ return this.dirty;
+ },
+ get_on_change_value: function() {
+ return this.get_value();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ if (this.field.translate) {
+ this.$element.find('.oe_field_translate').toggle(!!this.view.datarecord.id);
+ }
+ if (!this.disable_utility_classes) {
+ this.$element.toggleClass('disabled', this.readonly);
+ this.$element.toggleClass('required', this.required);
+ if (this.view.show_invalid) {
+ this.$element.toggleClass('invalid', !this.is_valid());
+ }
+ }
+ },
+ on_ui_change: function() {
+ this.dirty = this.view.dirty = true;
+ this.validate();
+ if (this.is_valid()) {
+ this.set_value_from_ui();
+ this.view.do_onchange(this);
+ this.view.on_form_changed();
+ } else {
+ this.update_dom();
+ }
+ },
+ validate: function() {
+ this.invalid = false;
+ },
+ focus: function() {
+ },
+ _build_view_fields_values: function() {
+ var a_dataset = this.view.dataset || {};
+ var fields_values = this.view.get_fields_values();
+ var parent_values = a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {};
+ fields_values.parent = parent_values;
+ return fields_values;
+ },
+ /**
+ * Builds a new context usable for operations related to fields by merging
+ * the fields'context with the action's context.
+ */
+ build_context: function() {
+ // I previously belevied contexts should be herrited, but now I doubt it
+ //var a_context = this.view.dataset.get_context() || {};
+ var f_context = this.field.context || null;
+ // maybe the default_get should only be used when we do a default_get?
+ var v_context1 = this.node.attrs.default_get || {};
+ var v_context2 = this.node.attrs.context || {};
+ var v_context = new openerp.web.CompoundContext(v_context1, v_context2);
+ if (v_context1.__ref || v_context2.__ref || true) { //TODO niv: remove || true
+ var fields_values = this._build_view_fields_values();
+ v_context.set_eval_context(fields_values);
+ }
+ // if there is a context on the node, overrides the model's context
+ var ctx = f_context || v_context;
+ return ctx;
+ },
+ build_domain: function() {
+ var f_domain = this.field.domain || null;
+ var v_domain = this.node.attrs.domain || [];
+ if (!(v_domain instanceof Array) || true) { //TODO niv: remove || true
+ var fields_values = this._build_view_fields_values();
+ v_domain = new openerp.web.CompoundDomain(v_domain).set_eval_context(fields_values);
+ }
+ // if there is a domain on the node, overrides the model's domain
+ return f_domain || v_domain;
+ }
+});
+
+openerp.web.form.FieldChar = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldChar";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input').change(this.on_ui_change);
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ var show_value = openerp.web.format_value(value, this, '');
+ this.$element.find('input').val(show_value);
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input').attr('disabled', this.readonly);
+ },
+ set_value_from_ui: function() {
+ this.value = openerp.web.parse_value(this.$element.find('input').val(), this);
+ this._super();
+ },
+ validate: function() {
+ this.invalid = false;
+ try {
+ var value = openerp.web.parse_value(this.$element.find('input').val(), this, '');
+ this.invalid = this.required && value === '';
+ } catch(e) {
+ this.invalid = true;
+ }
+ },
+ focus: function() {
+ this.$element.find('input').focus();
+ }
+});
+
+openerp.web.form.FieldEmail = openerp.web.form.FieldChar.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldEmail";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('button').click(this.on_button_clicked);
+ },
+ on_button_clicked: function() {
+ if (!this.value || !this.is_valid()) {
+ this.notification.warn("E-mail error", "Can't send email to invalid e-mail address");
+ } else {
+ location.href = 'mailto:' + this.value;
+ }
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ this.$element.find('a').attr('href', 'mailto:' + this.$element.find('input').val());
+ }
+});
+
+openerp.web.form.FieldUrl = openerp.web.form.FieldChar.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldUrl";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('button').click(this.on_button_clicked);
+ },
+ on_button_clicked: function() {
+ if (!this.value) {
+ this.notification.warn("Resource error", "This resource is empty");
+ } else {
+ window.open(this.value);
+ }
+ }
+});
+
+openerp.web.form.FieldFloat = openerp.web.form.FieldChar.extend({
+ set_value: function(value) {
+ if (value === false || value === undefined) {
+ // As in GTK client, floats default to 0
+ value = 0;
+ this.dirty = true;
+ }
+ this._super.apply(this, [value]);
+ }
+});
+
+openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldDate";
+ this.jqueryui_object = 'datetimepicker';
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input').change(this.on_ui_change)[this.jqueryui_object]({
+ dateFormat: 'yy-mm-dd',
+ timeFormat: 'hh:mm:ss',
+ showOn: 'button',
+ buttonImage: '/web/static/src/img/ui/field_calendar.png',
+ buttonImageOnly: true,
+ constrainInput: false
+ });
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ if (!value) {
+ this.$element.find('input').val('');
+ } else {
+ this.$element.find('input').unbind('change');
+ // jQuery UI date picker wrongly call on_change event herebelow
+ this.$element.find('input')[this.jqueryui_object]('setDate', this.parse(value));
+ this.$element.find('input').change(this.on_ui_change);
+ }
+ },
+ set_value_from_ui: function() {
+ this.value = this.$element.find('input')[this.jqueryui_object]('getDate') || false;
+ if (this.value) {
+ this.value = this.format(this.value);
+ }
+ this._super();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input').datepicker(this.readonly ? 'disable' : 'enable');
+ },
+ validate: function() {
+ this.invalid = false;
+ var value = this.$element.find('input').val();
+ if (value === "") {
+ this.invalid = this.required;
+ } else {
+ this.invalid = !this.$element.find('input')[this.jqueryui_object]('getDate');
+ }
+ },
+ focus: function() {
+ this.$element.find('input').focus();
+ },
+ parse: openerp.web.auto_str_to_date,
+ format: function(val) {
+ return openerp.web.auto_date_to_str(val, this.field.type);
+ }
+});
+
+openerp.web.form.FieldDate = openerp.web.form.FieldDatetime.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.jqueryui_object = 'datepicker';
+ }
+});
+
+openerp.web.form.FieldText = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldText";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('textarea').change(this.on_ui_change);
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ var show_value = openerp.web.format_value(value, this, '');
+ this.$element.find('textarea').val(show_value);
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('textarea').attr('disabled', this.readonly);
+ },
+ set_value_from_ui: function() {
+ this.value = openerp.web.parse_value(this.$element.find('textarea').val(), this);
+ this._super();
+ },
+ validate: function() {
+ this.invalid = false;
+ try {
+ var value = openerp.web.parse_value(this.$element.find('textarea').val(), this, '');
+ this.invalid = this.required && value === '';
+ } catch(e) {
+ this.invalid = true;
+ }
+ },
+ focus: function() {
+ this.$element.find('textarea').focus();
+ }
+});
+
+openerp.web.form.FieldBoolean = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldBoolean";
+ },
+ start: function() {
+ var self = this;
+ this._super.apply(this, arguments);
+ this.$element.find('input').click(function() {
+ if ($(this).is(':checked') != self.value) {
+ self.on_ui_change();
+ }
+ });
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ this.$element.find('input')[0].checked = value;
+ },
+ set_value_from_ui: function() {
+ this.value = this.$element.find('input').is(':checked');
+ this._super();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input').attr('disabled', this.readonly);
+ },
+ validate: function() {
+ this.invalid = this.required && !this.$element.find('input').is(':checked');
+ },
+ focus: function() {
+ this.$element.find('input').focus();
+ }
+});
+
+openerp.web.form.FieldProgressBar = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldProgressBar";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('div').progressbar({
+ value: this.value,
+ disabled: this.readonly
+ });
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ var show_value = Number(value);
+ if (isNaN(show_value)) {
+ show_value = 0;
+ }
+ this.$element.find('div').progressbar('option', 'value', show_value).find('span').html(show_value + '%');
+ }
+});
+
+openerp.web.form.FieldTextXml = openerp.web.form.Field.extend({
+// to replace view editor
+});
+
+openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ var self = this;
+ this._super(view, node);
+ this.template = "FieldSelection";
+ this.values = this.field.selection;
+ _.each(this.values, function(v, i) {
+ if (v[0] === false && v[1] === '') {
+ self.values.splice(i, 1);
+ }
+ });
+ this.values.unshift([false, '']);
+ },
+ start: function() {
+ // Flag indicating whether we're in an event chain containing a change
+ // event on the select, in order to know what to do on keyup[RETURN]:
+ // * If the user presses [RETURN] as part of changing the value of a
+ // selection, we should just let the value change and not let the
+ // event broadcast further (e.g. to validating the current state of
+ // the form in editable list view, which would lead to saving the
+ // current row or switching to the next one)
+ // * If the user presses [RETURN] with a select closed (side-effect:
+ // also if the user opened the select and pressed [RETURN] without
+ // changing the selected value), takes the action as validating the
+ // row
+ var ischanging = false;
+ this._super.apply(this, arguments);
+ this.$element.find('select')
+ .change(this.on_ui_change)
+ .change(function () { ischanging = true; })
+ .click(function () { ischanging = false; })
+ .keyup(function (e) {
+ if (e.which !== 13 || !ischanging) { return; }
+ e.stopPropagation();
+ ischanging = false;
+ });
+ },
+ set_value: function(value) {
+ value = value === null ? false : value;
+ value = value instanceof Array ? value[0] : value;
+ this._super(value);
+ var index = 0;
+ for (var i = 0, ii = this.values.length; i < ii; i++) {
+ if (this.values[i][0] === value) index = i;
+ }
+ this.$element.find('select')[0].selectedIndex = index;
+ },
+ set_value_from_ui: function() {
+ this.value = this.values[this.$element.find('select')[0].selectedIndex][0];
+ this._super();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('select').attr('disabled', this.readonly);
+ },
+ validate: function() {
+ var value = this.values[this.$element.find('select')[0].selectedIndex];
+ this.invalid = !(value && !(this.required && value[0] === false));
+ },
+ focus: function() {
+ this.$element.find('select').focus();
+ }
+});
+
+// jquery autocomplete tweak to allow html
+(function() {
+ var proto = $.ui.autocomplete.prototype,
+ initSource = proto._initSource;
+
+ function filter( array, term ) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( $( "<div>" ).html( value.label || value.value || value ).text() );
+ });
+ }
+
+ $.extend( proto, {
+ _initSource: function() {
+ if ( this.options.html && $.isArray(this.options.source) ) {
+ this.source = function( request, response ) {
+ response( filter( this.options.source, request.term ) );
+ };
+ } else {
+ initSource.call( this );
+ }
+ },
+
+ _renderItem: function( ul, item) {
+ return $( "<li></li>" )
+ .data( "item.autocomplete", item )
+ .append( $( "<a></a>" )[ this.options.html ? "html" : "text" ]( item.label ) )
+ .appendTo( ul );
+ }
+ });
+})();
+
+openerp.web.form.dialog = function(content, options) {
+ options = _.extend({
+ autoOpen: true,
+ width: '90%',
+ height: '90%',
+ min_width: '800px',
+ min_height: '600px'
+ }, options || {});
+ options.autoOpen = true;
+ var dialog = new openerp.web.Dialog(null, options);
+ dialog.$dialog = $(content).dialog(dialog.dialog_options);
+ return dialog.$dialog;
+};
+
+openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldMany2One";
+ this.limit = 7;
+ this.value = null;
+ this.cm_id = _.uniqueId('m2o_cm_');
+ this.last_search = [];
+ this.tmp_value = undefined;
+ },
+ start: function() {
+ this._super();
+ var self = this;
+ this.$input = this.$element.find("input");
+ this.$drop_down = this.$element.find(".oe-m2o-drop-down-button");
+ this.$menu_btn = this.$element.find(".oe-m2o-cm-button");
+
+ // context menu
+ var init_context_menu_def = $.Deferred().then(function(e) {
+ var rdataset = new openerp.web.DataSetStatic(self, "ir.values", self.build_context());
+ rdataset.call("get", ['action', 'client_action_relate',
+ [[self.field.relation, false]], false, rdataset.get_context()], false, 0)
+ .then(function(result) {
+ self.related_entries = result;
+
+ var $cmenu = $("#" + self.cm_id);
+ $cmenu.append(QWeb.render("FieldMany2One.context_menu", {widget: self}));
+ var bindings = {};
+ bindings[self.cm_id + "_search"] = function() {
+ self._search_create_popup("search");
+ };
+ bindings[self.cm_id + "_create"] = function() {
+ self._search_create_popup("form");
+ };
+ bindings[self.cm_id + "_open"] = function() {
+ if (!self.value) {
+ return;
+ }
+ var pop = new openerp.web.form.FormOpenPopup(self.view);
+ pop.show_element(self.field.relation, self.value[0],self.build_context(), {});
+ pop.on_write_completed.add_last(function() {
+ self.set_value(self.value[0]);
+ });
+ };
+ _.each(_.range(self.related_entries.length), function(i) {
+ bindings[self.cm_id + "_related_" + i] = function() {
+ self.open_related(self.related_entries[i]);
+ };
+ });
+ var cmenu = self.$menu_btn.contextMenu(self.cm_id, {'leftClickToo': true,
+ bindings: bindings, itemStyle: {"color": ""},
+ onContextMenu: function() {
+ if(self.value) {
+ $("#" + self.cm_id + " .oe_m2o_menu_item_mandatory").removeClass("oe-m2o-disabled-cm");
+ } else {
+ $("#" + self.cm_id + " .oe_m2o_menu_item_mandatory").addClass("oe-m2o-disabled-cm");
+ }
+ return true;
+ }, menuStyle: {width: "200px"}
+ });
+ setTimeout(function() {self.$menu_btn.trigger(e);}, 0);
+ });
+ });
+ var ctx_callback = function(e) {init_context_menu_def.resolve(e); e.preventDefault()};
+ this.$menu_btn.bind('contextmenu', ctx_callback);
+ this.$menu_btn.click(ctx_callback);
+
+ // some behavior for input
+ this.$input.keyup(function() {
+ if (self.$input.val() === "") {
+ self._change_int_value(null);
+ } else if (self.value === null || (self.value && self.$input.val() !== self.value[1])) {
+ self._change_int_value(undefined);
+ }
+ });
+ this.$drop_down.click(function() {
+ if (self.$input.autocomplete("widget").is(":visible")) {
+ self.$input.autocomplete("close");
+ } else {
+ if (self.value) {
+ self.$input.autocomplete("search", "");
+ } else {
+ self.$input.autocomplete("search");
+ }
+ self.$input.focus();
+ }
+ });
+ var anyoneLoosesFocus = function() {
+ if (!self.$input.is(":focus") &&
+ !self.$input.autocomplete("widget").is(":visible") &&
+ !self.value) {
+ if (self.value === undefined && self.last_search.length > 0) {
+ self._change_int_ext_value(self.last_search[0]);
+ } else {
+ self._change_int_ext_value(null);
+ }
+ }
+ };
+ this.$input.focusout(anyoneLoosesFocus);
+
+ var isSelecting = false;
+ // autocomplete
+ this.$input.autocomplete({
+ source: function(req, resp) { self.get_search_result(req, resp); },
+ select: function(event, ui) {
+ isSelecting = true;
+ var item = ui.item;
+ if (item.id) {
+ self._change_int_value([item.id, item.name]);
+ } else if (item.action) {
+ self._change_int_value(undefined);
+ item.action();
+ return false;
+ }
+ },
+ focus: function(e, ui) {
+ e.preventDefault();
+ },
+ html: true,
+ close: anyoneLoosesFocus,
+ minLength: 0,
+ delay: 0
+ });
+ // used to correct a bug when selecting an element by pushing 'enter' in an editable list
+ this.$input.keyup(function(e) {
+ if (e.which === 13) {
+ if (isSelecting)
+ e.stopPropagation();
+ }
+ isSelecting = false;
+ });
+ },
+ // autocomplete component content handling
+ get_search_result: function(request, response) {
+ var search_val = request.term;
+ var self = this;
+
+ var dataset = new openerp.web.DataSetStatic(this, this.field.relation, self.build_context());
+
+ dataset.name_search(search_val, self.build_domain(), 'ilike',
+ this.limit + 1, function(data) {
+ self.last_search = data;
+ // possible selections for the m2o
+ var values = _.map(data, function(x) {
+ return {label: $('<span />').text(x[1]).html(), name:x[1], id:x[0]};
+ });
+
+ // search more... if more results that max
+ if (values.length > self.limit) {
+ values = values.slice(0, self.limit);
+ values.push({label: _t("<em>   Search More...</em>"), action: function() {
+ dataset.name_search(search_val, self.build_domain(), 'ilike'
+ , false, function(data) {
+ self._change_int_value(null);
+ self._search_create_popup("search", data);
+ });
+ }});
+ }
+ // quick create
+ var raw_result = _(data.result).map(function(x) {return x[1];});
+ if (search_val.length > 0 &&
+ !_.include(raw_result, search_val) &&
+ (!self.value || search_val !== self.value[1])) {
+ values.push({label: _.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
+ $('<span />').text(search_val).html()), action: function() {
+ self._quick_create(search_val);
+ }});
+ }
+ // create...
+ values.push({label: _t("<em>   Create and Edit...</em>"), action: function() {
+ self._change_int_value(null);
+ self._search_create_popup("form", undefined, {"default_name": search_val});
+ }});
+
+ response(values);
+ });
+ },
+ _quick_create: function(name) {
+ var self = this;
+ var dataset = new openerp.web.DataSetStatic(this, this.field.relation, self.build_context());
+ dataset.name_create(name, function(data) {
+ self._change_int_ext_value(data);
+ }).fail(function(error, event) {
+ event.preventDefault();
+ self._change_int_value(null);
+ self._search_create_popup("form", undefined, {"default_name": name});
+ });
+ },
+ // all search/create popup handling
+ _search_create_popup: function(view, ids, context) {
+ var self = this;
+ var pop = new openerp.web.form.SelectCreatePopup(this);
+ pop.select_element(self.field.relation,{
+ initial_ids: ids ? _.map(ids, function(x) {return x[0]}) : undefined,
+ initial_view: view,
+ disable_multiple_selection: true
+ }, self.build_domain(),
+ new openerp.web.CompoundContext(self.build_context(), context || {}));
+ pop.on_select_elements.add(function(element_ids) {
+ var dataset = new openerp.web.DataSetStatic(self, self.field.relation, self.build_context());
+ dataset.name_get([element_ids[0]], function(data) {
+ self._change_int_ext_value(data[0]);
+ });
+ });
+ },
+ _change_int_ext_value: function(value) {
+ this._change_int_value(value);
+ this.$input.val(this.value ? this.value[1] : "");
+ },
+ _change_int_value: function(value) {
+ this.value = value;
+ var back_orig_value = this.original_value;
+ if (this.value === null || this.value) {
+ this.original_value = this.value;
+ }
+ if (back_orig_value === undefined) { // first use after a set_value()
+ return;
+ }
+ if (this.value !== undefined && ((back_orig_value ? back_orig_value[0] : null)
+ !== (this.value ? this.value[0] : null))) {
+ this.on_ui_change();
+ }
+ },
+ set_value: function(value) {
+ value = value || null;
+ this.invalid = false;
+ var self = this;
+ this.tmp_value = value;
+ self.update_dom();
+ self.on_value_changed();
+ var real_set_value = function(rval) {
+ self.tmp_value = undefined;
+ self.value = rval;
+ self.original_value = undefined;
+ self._change_int_ext_value(rval);
+ };
+ if(typeof(value) === "number") {
+ var dataset = new openerp.web.DataSetStatic(this, this.field.relation, self.build_context());
+ dataset.name_get([value], function(data) {
+ real_set_value(data[0]);
+ }).fail(function() {self.tmp_value = undefined;});
+ } else {
+ setTimeout(function() {real_set_value(value);}, 0);
+ }
+ },
+ get_value: function() {
+ if (this.tmp_value !== undefined) {
+ if (this.tmp_value instanceof Array) {
+ return this.tmp_value[0];
+ }
+ return this.tmp_value ? this.tmp_value : false;
+ }
+ if (this.value === undefined)
+ return this.original_value ? this.original_value[0] : false;
+ return this.value ? this.value[0] : false;
+ },
+ validate: function() {
+ this.invalid = false;
+ var val = this.tmp_value !== undefined ? this.tmp_value : this.value;
+ if (val === null) {
+ this.invalid = this.required;
+ }
+ },
+ open_related: function(related) {
+ var self = this;
+ if (!self.value)
+ return;
+ var additional_context = {
+ active_id: self.value[0],
+ active_ids: [self.value[0]],
+ active_model: self.field.relation
+ };
+ self.rpc("/web/action/load", {
+ action_id: related[2].id,
+ context: additional_context
+ }, function(result) {
+ result.result.context = _.extend(result.result.context || {}, additional_context);
+ self.do_action(result.result);
+ });
+ }
+});
+
+/*
+# Values: (0, 0, { fields }) create
+# (1, ID, { fields }) update
+# (2, ID) remove (delete)
+# (3, ID) unlink one (target id or target of relation)
+# (4, ID) link
+# (5) unlink all (only valid for one2many)
+*/
+var commands = {
+ // (0, _, {values})
+ CREATE: 0,
+ 'create': function (values) {
+ return [commands.CREATE, false, values];
+ },
+ // (1, id, {values})
+ UPDATE: 1,
+ 'update': function (id, values) {
+ return [commands.UPDATE, id, values];
+ },
+ // (2, id[, _])
+ DELETE: 2,
+ 'delete': function (id) {
+ return [commands.DELETE, id, false];
+ },
+ // (3, id[, _]) removes relation, but not linked record itself
+ FORGET: 3,
+ 'forget': function (id) {
+ return [commands.FORGET, id, false];
+ },
+ // (4, id[, _])
+ LINK_TO: 4,
+ 'link_to': function (id) {
+ return [commands.LINK_TO, id, false];
+ },
+ // (5[, _[, _]])
+ DELETE_ALL: 5,
+ 'delete_all': function () {
+ return [5, false, false];
+ },
+ // (6, _, ids) replaces all linked records with provided ids
+ REPLACE_WITH: 6,
+ 'replace_with': function (ids) {
+ return [6, false, ids];
+ }
+};
+openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
+ multi_selection: false,
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldOne2Many";
+ this.is_started = $.Deferred();
+ this.form_last_update = $.Deferred();
+ this.disable_utility_classes = true;
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+
+ var self = this;
+
+ this.dataset = new openerp.web.form.One2ManyDataSet(this, this.field.relation);
+ this.dataset.o2m = this;
+ this.dataset.parent_view = this.view;
+ this.dataset.on_change.add_last(function() {
+ self.on_ui_change();
+ });
+
+ var modes = this.node.attrs.mode;
+ modes = !!modes ? modes.split(",") : ["tree", "form"];
+ var views = [];
+ _.each(modes, function(mode) {
+ var view = {
+ view_id: false,
+ view_type: mode == "tree" ? "list" : mode,
+ options: { sidebar : false }
+ };
+ if (self.field.views && self.field.views[mode]) {
+ view.embedded_view = self.field.views[mode];
+ }
+ if(view.view_type === "list") {
+ view.options.selectable = self.multi_selection;
+ }
+ views.push(view);
+ });
+ this.views = views;
+
+ this.viewmanager = new openerp.web.ViewManager(this, this.dataset, views);
+ this.viewmanager.registry = openerp.web.views.clone({
+ list: 'openerp.web.form.One2ManyListView',
+ form: 'openerp.web.form.One2ManyFormView'
+ });
+ var once = $.Deferred().then(function() {
+ self.form_last_update.resolve();
+ });
+ this.viewmanager.on_controller_inited.add_last(function(view_type, controller) {
+ if (view_type == "list") {
+ controller.o2m = self;
+ } else if (view_type == "form") {
+ controller.on_record_loaded.add_last(function() {
+ once.resolve();
+ });
+ controller.on_pager_action.add_first(function() {
+ self.save_form_view();
+ });
+ controller.$element.find(".oe_form_button_save_edit").hide();
+ }
+ self.is_started.resolve();
+ });
+ this.viewmanager.on_mode_switch.add_first(function() {
+ self.save_form_view();
+ });
+ setTimeout(function () {
+ self.viewmanager.appendTo(self.$element);
+ }, 0);
+ },
+ reload_current_view: function() {
+ var self = this;
+ var view = self.viewmanager.views[self.viewmanager.active_view].controller;
+ if(self.viewmanager.active_view === "list") {
+ view.reload_content();
+ } else if (self.viewmanager.active_view === "form") {
+ if (this.dataset.index === null && this.dataset.ids.length >= 1) {
+ this.dataset.index = 0;
+ }
+ this.form_last_update.then(function() {
+ this.form_last_update = view.do_show();
+ });
+ }
+ },
+ set_value: function(value) {
+ value = value || [];
+ var self = this;
+ this.dataset.reset_ids([]);
+ if(value.length >= 1 && value[0] instanceof Array) {
+ var ids = [];
+ _.each(value, function(command) {
+ var obj = {values: command[2]};
+ switch (command[0]) {
+ case commands.CREATE:
+ obj['id'] = _.uniqueId(self.dataset.virtual_id_prefix);
+ self.dataset.to_create.push(obj);
+ self.dataset.cache.push(_.clone(obj));
+ ids.push(obj.id);
+ return;
+ case commands.UPDATE:
+ obj['id'] = command[1];
+ self.dataset.to_write.push(obj);
+ self.dataset.cache.push(_.clone(obj));
+ ids.push(obj.id);
+ return;
+ case commands.DELETE:
+ self.dataset.to_delete.push({id: command[1]});
+ return;
+ case commands.LINK_TO:
+ ids.push(command[1]);
+ return;
+ case commands.DELETE_ALL:
+ self.dataset.delete_all = true;
+ return;
+ }
+ });
+ this._super(ids);
+ this.dataset.set_ids(ids);
+ } else if (value.length >= 1 && typeof(value[0]) === "object") {
+ var ids = [];
+ this.dataset.delete_all = true;
+ _.each(value, function(command) {
+ var obj = {values: command};
+ obj['id'] = _.uniqueId(self.dataset.virtual_id_prefix);
+ self.dataset.to_create.push(obj);
+ self.dataset.cache.push(_.clone(obj));
+ ids.push(obj.id);
+ });
+ this._super(ids);
+ this.dataset.set_ids(ids);
+ } else {
+ this._super(value);
+ this.dataset.reset_ids(value);
+ }
+ if (this.dataset.index === null && this.dataset.ids.length > 0) {
+ this.dataset.index = 0;
+ }
+ $.when(this.is_started).then(function() {
+ self.reload_current_view();
+ });
+ },
+ get_value: function() {
+ var self = this;
+ if (!this.dataset)
+ return [];
+ var val = this.dataset.delete_all ? [commands.delete_all()] : [];
+ val = val.concat(_.map(this.dataset.ids, function(id) {
+ var alter_order = _.detect(self.dataset.to_create, function(x) {return x.id === id;});
+ if (alter_order) {
+ return commands.create(alter_order.values);
+ }
+ alter_order = _.detect(self.dataset.to_write, function(x) {return x.id === id;});
+ if (alter_order) {
+ return commands.update(alter_order.id, alter_order.values);
+ }
+ return commands.link_to(id);
+ }));
+ return val.concat(_.map(
+ this.dataset.to_delete, function(x) {
+ return commands['delete'](x.id);}));
+ },
+ save_form_view: function() {
+ if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view &&
+ this.viewmanager.views[this.viewmanager.active_view] &&
+ this.viewmanager.views[this.viewmanager.active_view].controller) {
+ var view = this.viewmanager.views[this.viewmanager.active_view].controller;
+ if (this.viewmanager.active_view === "form") {
+ var res = $.when(view.do_save());
+ if (res === false) {
+ // ignore
+ } else if (res.isRejected()) {
+ throw "Save or create on one2many dataset is not supposed to fail.";
+ } else if (!res.isResolved()) {
+ throw "Asynchronous get_value() is not supported in form view.";
+ }
+ return res;
+ }
+ }
+ return false;
+ },
+ is_valid: function() {
+ this.validate();
+ return this._super();
+ },
+ validate: function() {
+ this.invalid = false;
+ var self = this;
+ var view = self.viewmanager.views[self.viewmanager.active_view].controller;
+ if (self.viewmanager.active_view === "form") {
+ for (var f in view.fields) {
+ f = view.fields[f];
+ if (!f.is_valid()) {
+ this.invalid = true;
+ return;
+ }
+ }
+ }
+ },
+ is_dirty: function() {
+ this.save_form_view();
+ return this._super();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.toggleClass('disabled', this.readonly);
+ }
+});
+
+openerp.web.form.One2ManyDataSet = openerp.web.BufferedDataSet.extend({
+ get_context: function() {
+ this.context = this.o2m.build_context();
+ return this.context;
+ }
+});
+
+openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({
+});
+
+openerp.web.form.One2ManyListView = openerp.web.ListView.extend({
+ do_add_record: function () {
+ if (this.options.editable) {
+ this._super.apply(this, arguments);
+ } else {
+ var self = this;
+ var pop = new openerp.web.form.SelectCreatePopup(this);
+ pop.select_element(self.o2m.field.relation,{
+ initial_view: "form",
+ alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
+ create_function: function(data) {
+ return self.o2m.dataset.create(data, function(r) {
+ self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r.result]));
+ self.o2m.dataset.on_change();
+ });
+ },
+ parent_view: self.o2m.view
+ }, self.o2m.build_domain(), self.o2m.build_context());
+ pop.on_select_elements.add_last(function() {
+ self.o2m.reload_current_view();
+ });
+ }
+ },
+ do_activate_record: function(index, id) {
+ var self = this;
+ var pop = new openerp.web.form.FormOpenPopup(self.o2m.view);
+ pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(),{
+ auto_write: false,
+ alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
+ parent_view: self.o2m.view,
+ read_function: function() {
+ return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments);
+ }
+ });
+ pop.on_write.add(function(id, data) {
+ self.o2m.dataset.write(id, data, {}, function(r) {
+ self.o2m.reload_current_view();
+ });
+ });
+ }
+});
+
+openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({
+ multi_selection: false,
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldMany2Many";
+ this.list_id = _.uniqueId("many2many");
+ this.is_started = $.Deferred();
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+
+ var self = this;
+
+ this.dataset = new openerp.web.form.Many2ManyDataSet(this, this.field.relation);
+ this.dataset.m2m = this;
+ this.dataset.on_unlink.add_last(function(ids) {
+ self.on_ui_change();
+ });
+
+ this.list_view = new openerp.web.form.Many2ManyListView(this, this.list_id, this.dataset, false, {
+ 'addable': 'Add',
+ 'selectable': self.multi_selection
+ });
+ this.list_view.m2m_field = this;
+ this.list_view.on_loaded.add_last(function() {
+ self.is_started.resolve();
+ });
+ setTimeout(function () {
+ self.list_view.start();
+ }, 0);
+ },
+ set_value: function(value) {
+ value = value || [];
+ if (value.length >= 1 && value[0] instanceof Array) {
+ value = value[0][2];
+ }
+ this._super(value);
+ this.dataset.set_ids(value);
+ var self = this;
+ $.when(this.is_started).then(function() {
+ self.list_view.reload_content();
+ });
+ },
+ get_value: function() {
+ return [commands.replace_with(this.dataset.ids)];
+ },
+ validate: function() {
+ this.invalid = false;
+ // TODO niv
+ }
+});
+
+openerp.web.form.Many2ManyDataSet = openerp.web.DataSetStatic.extend({
+ get_context: function() {
+ this.context = this.m2m.build_context();
+ return this.context;
+ }
+});
+
+/**
+ * @class
+ * @extends openerp.web.ListView
+ */
+openerp.web.form.Many2ManyListView = openerp.web.ListView.extend(/** @lends openerp.web.form.Many2ManyListView# */{
+ do_add_record: function () {
+ var pop = new openerp.web.form.SelectCreatePopup(this);
+ pop.select_element(this.model, {},
+ new openerp.web.CompoundDomain(this.m2m_field.build_domain(), ["!", ["id", "in", this.m2m_field.dataset.ids]]),
+ this.m2m_field.build_context());
+ var self = this;
+ pop.on_select_elements.add(function(element_ids) {
+ _.each(element_ids, function(element_id) {
+ if(! _.detect(self.dataset.ids, function(x) {return x == element_id;})) {
+ self.dataset.set_ids([].concat(self.dataset.ids, [element_id]));
+ self.m2m_field.on_ui_change();
+ self.reload_content();
+ }
+ });
+ });
+ },
+ do_activate_record: function(index, id) {
+ var self = this;
+ var pop = new openerp.web.form.FormOpenPopup(this);
+ pop.show_element(this.dataset.model, id, this.m2m_field.build_context(), {});
+ pop.on_write_completed.add_last(function() {
+ self.reload_content();
+ });
+ }
+});
+
+/**
+ * @class
+ * @extends openerp.web.OldWidget
+ */
+openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends openerp.web.form.SelectCreatePopup# */{
+ identifier_prefix: "selectcreatepopup",
+ template: "SelectCreatePopup",
+ /**
+ * options:
+ * - initial_ids
+ * - initial_view: form or search (default search)
+ * - disable_multiple_selection
+ * - alternative_form_view
+ * - create_function (defaults to a naive saving behavior)
+ * - parent_view
+ */
+ select_element: function(model, options, domain, context) {
+ var self = this;
+ this.model = model;
+ this.domain = domain || [];
+ this.context = context || {};
+ this.options = _.defaults(options || {}, {"initial_view": "search", "create_function": function() {
+ return self.create_row.apply(self, arguments);
+ }});
+ this.initial_ids = this.options.initial_ids;
+ this.created_elements = [];
+ openerp.web.form.dialog(this.render(), {close:function() {
+ self.check_exit();
+ }});
+ this.start();
+ },
+ start: function() {
+ this._super();
+ this.dataset = new openerp.web.ReadOnlyDataSetSearch(this, this.model,
+ this.context);
+ this.dataset.parent_view = this.options.parent_view;
+ if (this.options.initial_view == "search") {
+ this.setup_search_view();
+ } else { // "form"
+ this.new_object();
+ }
+ },
+ setup_search_view: function() {
+ var self = this;
+ if (this.searchview) {
+ this.searchview.stop();
+ }
+ this.searchview = new openerp.web.SearchView(this,
+ this.element_id + "_search", this.dataset, false, {
+ "selectable": !this.options.disable_multiple_selection,
+ "deletable": false
+ });
+ this.searchview.on_search.add(function(domains, contexts, groupbys) {
+ if (self.initial_ids) {
+ self.view_list.do_search.call(self, domains.concat([[["id", "in", self.initial_ids]], self.domain]),
+ contexts, groupbys);
+ self.initial_ids = undefined;
+ } else {
+ self.view_list.do_search.call(self, domains.concat([self.domain]), contexts, groupbys);
+ }
+ });
+ this.searchview.on_loaded.add_last(function () {
+ var $buttons = self.searchview.$element.find(".oe_search-view-buttons");
+ $buttons.append(QWeb.render("SelectCreatePopup.search.buttons"));
+ var $cbutton = $buttons.find(".oe_selectcreatepopup-search-close");
+ $cbutton.click(function() {
+ self.stop();
+ });
+ var $sbutton = $buttons.find(".oe_selectcreatepopup-search-select");
+ if(self.options.disable_multiple_selection) {
+ $sbutton.hide();
+ }
+ $sbutton.click(function() {
+ self.on_select_elements(self.selected_ids);
+ self.stop();
+ });
+ self.view_list = new openerp.web.form.SelectCreateListView(self,
+ self.element_id + "_view_list", self.dataset, false,
+ {'deletable': false});
+ self.view_list.popup = self;
+ self.view_list.do_show();
+ self.view_list.start().then(function() {
+ self.searchview.do_search();
+ });
+ });
+ this.searchview.start();
+ },
+ create_row: function(data) {
+ var self = this;
+ var wdataset = new openerp.web.DataSetSearch(this, this.model, this.context, this.domain);
+ wdataset.parent_view = this.options.parent_view;
+ return wdataset.create(data);
+ },
+ on_select_elements: function(element_ids) {
+ },
+ on_click_element: function(ids) {
+ this.selected_ids = ids || [];
+ if(this.selected_ids.length > 0) {
+ this.$element.find(".oe_selectcreatepopup-search-select").removeAttr('disabled');
+ } else {
+ this.$element.find(".oe_selectcreatepopup-search-select").attr('disabled', "disabled");
+ }
+ },
+ new_object: function() {
+ var self = this;
+ if (this.searchview) {
+ this.searchview.hide();
+ }
+ if (this.view_list) {
+ this.view_list.$element.hide();
+ }
+ this.dataset.index = null;
+ this.view_form = new openerp.web.FormView(this, this.element_id + "_view_form", this.dataset, false);
+ if (this.options.alternative_form_view) {
+ this.view_form.set_embedded_view(this.options.alternative_form_view);
+ }
+ this.view_form.start();
+ this.view_form.on_loaded.add_last(function() {
+ var $buttons = self.view_form.$element.find(".oe_form_buttons");
+ $buttons.html(QWeb.render("SelectCreatePopup.form.buttons", {widget:self}));
+ var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save-new");
+ $nbutton.click(function() {
+ self._created = $.Deferred().then(function() {
+ self._created = undefined;
+ self.view_form.on_button_new();
+ });
+ self.view_form.do_save();
+ });
+ var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save");
+ $nbutton.click(function() {
+ self._created = $.Deferred().then(function() {
+ self._created = undefined;
+ self.check_exit();
+ });
+ self.view_form.do_save();
+ });
+ var $cbutton = $buttons.find(".oe_selectcreatepopup-form-close");
+ $cbutton.click(function() {
+ self.check_exit();
+ });
+ });
+ this.dataset.on_create.add(function(data) {
+ self.options.create_function(data).then(function(r) {
+ self.created_elements.push(r.result);
+ if (self._created) {
+ self._created.resolve();
+ }
+ });
+ });
+ this.view_form.do_show();
+ },
+ check_exit: function() {
+ if (this.created_elements.length > 0) {
+ this.on_select_elements(this.created_elements);
+ }
+ this.stop();
+ }
+});
+
+openerp.web.form.SelectCreateListView = openerp.web.ListView.extend({
+ do_add_record: function () {
+ this.popup.new_object();
+ },
+ select_record: function(index) {
+ this.popup.on_select_elements([this.dataset.ids[index]]);
+ this.popup.stop();
+ },
+ do_select: function(ids, records) {
+ this._super(ids, records);
+ this.popup.on_click_element(ids);
+ }
+});
+
+/**
+ * @class
+ * @extends openerp.web.OldWidget
+ */
+openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp.web.form.FormOpenPopup# */{
+ identifier_prefix: "formopenpopup",
+ template: "FormOpenPopup",
+ /**
+ * options:
+ * - alternative_form_view
+ * - auto_write (default true)
+ * - read_function
+ * - parent_view
+ */
+ show_element: function(model, row_id, context, options) {
+ this.model = model;
+ this.row_id = row_id;
+ this.context = context || {};
+ this.options = _.defaults(options || {}, {"auto_write": true});
+ jQuery(this.render()).dialog({title: '',
+ modal: true,
+ width: 960,
+ height: 600});
+ this.start();
+ },
+ start: function() {
+ this._super();
+ this.dataset = new openerp.web.form.FormOpenDataset(this, this.model, this.context);
+ this.dataset.fop = this;
+ this.dataset.ids = [this.row_id];
+ this.dataset.index = 0;
+ this.dataset.parent_view = this.options.parent_view;
+ this.setup_form_view();
+ },
+ on_write: function(id, data) {
+ this.stop();
+ if (!this.options.auto_write)
+ return;
+ var self = this;
+ var wdataset = new openerp.web.DataSetSearch(this, this.model, this.context, this.domain);
+ wdataset.parent_view = this.options.parent_view;
+ wdataset.write(id, data, {}, function(r) {
+ self.on_write_completed();
+ });
+ },
+ on_write_completed: function() {},
+ setup_form_view: function() {
+ var self = this;
+ this.view_form = new openerp.web.FormView(this, this.element_id + "_view_form", this.dataset, false);
+ if (this.options.alternative_form_view) {
+ this.view_form.set_embedded_view(this.options.alternative_form_view);
+ }
+ this.view_form.start();
+ this.view_form.on_loaded.add_last(function() {
+ var $buttons = self.view_form.$element.find(".oe_form_buttons");
+ $buttons.html(QWeb.render("FormOpenPopup.form.buttons"));
+ var $nbutton = $buttons.find(".oe_formopenpopup-form-save");
+ $nbutton.click(function() {
+ self.view_form.do_save();
+ });
+ var $cbutton = $buttons.find(".oe_formopenpopup-form-close");
+ $cbutton.click(function() {
+ self.stop();
+ });
+ self.view_form.do_show();
+ });
+ this.dataset.on_write.add(this.on_write);
+ }
+});
+
+openerp.web.form.FormOpenDataset = openerp.web.ReadOnlyDataSetSearch.extend({
+ read_ids: function() {
+ if (this.fop.options.read_function) {
+ return this.fop.options.read_function.apply(null, arguments);
+ } else {
+ return this._super.apply(this, arguments);
+ }
+ }
+});
+
+openerp.web.form.FieldReference = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldReference";
+ this.fields_view = {
+ fields: {
+ selection: {
+ selection: view.fields_view.fields[this.name].selection
+ },
+ m2o: {
+ relation: null
+ }
+ }
+ };
+ this.get_fields_values = view.get_fields_values;
+ this.do_onchange = this.on_form_changed = this.on_nop;
+ this.widgets = {};
+ this.fields = {};
+ this.selection = new openerp.web.form.FieldSelection(this, { attrs: {
+ name: 'selection',
+ widget: 'selection'
+ }});
+ this.selection.on_value_changed.add_last(this.on_selection_changed);
+ this.m2o = new openerp.web.form.FieldMany2One(this, { attrs: {
+ name: 'm2o',
+ widget: 'many2one'
+ }});
+ },
+ on_nop: function() {
+ },
+ on_selection_changed: function() {
+ this.m2o.field.relation = this.selection.get_value();
+ this.m2o.set_value(null);
+ },
+ start: function() {
+ this._super();
+ this.selection.start();
+ this.m2o.start();
+ },
+ is_valid: function() {
+ return this.required === false || typeof(this.get_value()) === 'string';
+ },
+ is_dirty: function() {
+ return this.selection.is_dirty() || this.m2o.is_dirty();
+ },
+ set_value: function(value) {
+ this._super(value);
+ if (typeof(value) === 'string') {
+ var vals = value.split(',');
+ this.selection.set_value(vals[0]);
+ this.m2o.set_value(parseInt(vals[1], 10));
+ }
+ },
+ get_value: function() {
+ var model = this.selection.get_value(),
+ id = this.m2o.get_value();
+ if (typeof(model) === 'string' && typeof(id) === 'number') {
+ return model + ',' + id;
+ } else {
+ return false;
+ }
+ }
+});
+
+openerp.web.form.FieldBinary = openerp.web.form.Field.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.iframe = this.element_id + '_iframe';
+ this.binary_value = false;
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input.oe-binary-file').change(this.on_file_change);
+ this.$element.find('button.oe-binary-file-save').click(this.on_save_as);
+ this.$element.find('.oe-binary-file-clear').click(this.on_clear);
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('.oe-binary').toggle(!this.readonly);
+ },
+ human_filesize : function(size) {
+ var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+ var i = 0;
+ while (size >= 1024) {
+ size /= 1024;
+ ++i;
+ }
+ return size.toFixed(2) + ' ' + units[i];
+ },
+ on_file_change: function(e) {
+ // TODO: on modern browsers, we could directly read the file locally on client ready to be used on image cropper
+ // http://www.html5rocks.com/tutorials/file/dndfiles/
+ // http://deepliquid.com/projects/Jcrop/demos.php?demo=handler
+ window[this.iframe] = this.on_file_uploaded;
+ if ($(e.target).val() != '') {
+ this.$element.find('form.oe-binary-form input[name=session_id]').val(this.session.session_id);
+ this.$element.find('form.oe-binary-form').submit();
+ this.toggle_progress();
+ }
+ },
+ toggle_progress: function() {
+ this.$element.find('.oe-binary-progress, .oe-binary').toggle();
+ },
+ on_file_uploaded: function(size, name, content_type, file_base64) {
+ delete(window[this.iframe]);
+ if (size === false) {
+ this.notification.warn("File Upload", "There was a problem while uploading your file");
+ // TODO: use openerp web crashmanager
+ console.warn("Error while uploading file : ", name);
+ } else {
+ this.on_file_uploaded_and_valid.apply(this, arguments);
+ this.on_ui_change();
+ }
+ this.toggle_progress();
+ },
+ on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
+ },
+ on_save_as: function() {
+ if (!this.view.datarecord.id) {
+ this.notification.warn("Can't save file", "The record has not yet been saved");
+ } else {
+ var url = '/web/binary/saveas?session_id=' + this.session.session_id + '&model=' +
+ this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name +
+ '&fieldname=' + (this.node.attrs.filename || '') + '&t=' + (new Date().getTime());
+ window.open(url);
+ }
+ },
+ on_clear: function() {
+ if (this.value !== false) {
+ this.value = false;
+ this.binary_value = false;
+ this.on_ui_change();
+ }
+ return false;
+ }
+});
+
+openerp.web.form.FieldBinaryFile = openerp.web.form.FieldBinary.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldBinaryFile";
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ var show_value = (value != null && value !== false) ? value : '';
+ this.$element.find('input').eq(0).val(show_value);
+ },
+ on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
+ this.value = file_base64;
+ this.binary_value = true;
+ var show_value = this.human_filesize(size);
+ this.$element.find('input').eq(0).val(show_value);
+ this.set_filename(name);
+ },
+ set_filename: function(value) {
+ var filename = this.node.attrs.filename;
+ if (this.view.fields[filename]) {
+ this.view.fields[filename].set_value(value);
+ this.view.fields[filename].on_ui_change();
+ }
+ },
+ on_clear: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('input').eq(0).val('');
+ this.set_filename('');
+ }
+});
+
+openerp.web.form.FieldBinaryImage = openerp.web.form.FieldBinary.extend({
+ init: function(view, node) {
+ this._super(view, node);
+ this.template = "FieldBinaryImage";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$image = this.$element.find('img.oe-binary-image');
+ },
+ set_value: function(value) {
+ this._super.apply(this, arguments);
+ this.set_image_maxwidth();
+ var url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' +
+ this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name + '&t=' + (new Date().getTime());
+ this.$image.attr('src', url);
+ },
+ set_image_maxwidth: function() {
+ this.$image.css('max-width', this.$element.width());
+ },
+ on_file_change: function() {
+ this.set_image_maxwidth();
+ this._super.apply(this, arguments);
+ },
+ on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
+ this.value = file_base64;
+ this.binary_value = true;
+ this.$image.attr('src', 'data:' + (content_type || 'image/png') + ';base64,' + file_base64);
+ },
+ on_clear: function() {
+ this._super.apply(this, arguments);
+ this.$image.attr('src', '/web/static/src/img/placeholder.png');
+ }
+});
+
+openerp.web.form.FieldStatus = openerp.web.form.Field.extend({
+ template: "FieldStatus",
+ start: function() {
+ this._super();
+ this.selected_value = null;
+
+ this.render_list();
+ },
+ set_value: function(value) {
+ this._super(value);
+ this.selected_value = value;
+
+ this.render_list();
+ },
+ render_list: function() {
+ var self = this;
+ var shown = _.map(((this.node.attrs || {}).statusbar_visible || "").split(","),
+ function(x) { return x.trim(); });
+ shown = _.select(shown, function(x) { return x.length > 0; });
+
+ if (shown.length == 0) {
+ this.to_show = this.field.selection;
+ } else {
+ this.to_show = _.select(this.field.selection, function(x) {
+ return _.indexOf(shown, x[0]) !== -1 || x[0] === self.selected_value;
+ });
+ }
+
+ var content = openerp.web.qweb.render("FieldStatus.content", {widget: this, _:_});
+ this.$element.html(content);
+
+ var colors = JSON.parse((this.node.attrs || {}).statusbar_colors || "{}");
+ var color = colors[this.selected_value];
+ if (color) {
+ var elem = this.$element.find("li.oe-arrow-list-selected span");
+ elem.css("border-color", color);
+ elem = this.$element.find("li.oe-arrow-list-selected .oe-arrow-list-before");
+ elem.css("border-left-color", "rgba(0,0,0,0)");
+ elem = this.$element.find("li.oe-arrow-list-selected .oe-arrow-list-after");
+ elem.css("border-color", "rgba(0,0,0,0)");
+ elem.css("border-left-color", color);
+ }
+ }
+});
+
+/**
+ * Registry of form widgets, called by :js:`openerp.web.FormView`
+ */
+openerp.web.form.widgets = new openerp.web.Registry({
+ 'frame' : 'openerp.web.form.WidgetFrame',
+ 'group' : 'openerp.web.form.WidgetFrame',
+ 'notebook' : 'openerp.web.form.WidgetNotebook',
+ 'separator' : 'openerp.web.form.WidgetSeparator',
+ 'label' : 'openerp.web.form.WidgetLabel',
+ 'button' : 'openerp.web.form.WidgetButton',
+ 'char' : 'openerp.web.form.FieldChar',
+ 'email' : 'openerp.web.form.FieldEmail',
+ 'url' : 'openerp.web.form.FieldUrl',
+ 'text' : 'openerp.web.form.FieldText',
+ 'text_wiki' : 'openerp.web.form.FieldText',
+ 'date' : 'openerp.web.form.FieldDate',
+ 'datetime' : 'openerp.web.form.FieldDatetime',
+ 'selection' : 'openerp.web.form.FieldSelection',
+ 'many2one' : 'openerp.web.form.FieldMany2One',
+ 'many2many' : 'openerp.web.form.FieldMany2Many',
+ 'one2many' : 'openerp.web.form.FieldOne2Many',
+ 'one2many_list' : 'openerp.web.form.FieldOne2Many',
+ 'reference' : 'openerp.web.form.FieldReference',
+ 'boolean' : 'openerp.web.form.FieldBoolean',
+ 'float' : 'openerp.web.form.FieldFloat',
+ 'integer': 'openerp.web.form.FieldFloat',
+ 'float_time': 'openerp.web.form.FieldFloat',
+ 'progressbar': 'openerp.web.form.FieldProgressBar',
+ 'image': 'openerp.web.form.FieldBinaryImage',
+ 'binary': 'openerp.web.form.FieldBinaryFile',
+ 'statusbar': 'openerp.web.form.FieldStatus'
+});
+
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
new file mode 100644
index 00000000000..b0dc4fcc289
--- /dev/null
+++ b/addons/web/static/src/js/formats.js
@@ -0,0 +1,197 @@
+
+openerp.web.formats = function(openerp) {
+
+/**
+ * Formats a single atomic value based on a field descriptor
+ *
+ * @param {Object} value read from OpenERP
+ * @param {Object} descriptor union of orm field and view field
+ * @param {Object} [descriptor.widget] widget to use to display the value
+ * @param {Object} descriptor.type fallback if no widget is provided, or if the provided widget is unknown
+ * @param {Object} [descriptor.digits] used for the formatting of floats
+ * @param {String} [value_if_empty=''] returned if the ``value`` argument is considered empty
+ */
+openerp.web.format_value = function (value, descriptor, value_if_empty) {
+ // If NaN value, display as with a `false` (empty cell)
+ if (typeof value === 'number' && isNaN(value)) {
+ value = false;
+ }
+ switch (value) {
+ case false:
+ case Infinity:
+ case -Infinity:
+ return value_if_empty === undefined ? '' : value_if_empty;
+ }
+ switch (descriptor.widget || descriptor.type) {
+ case 'integer':
+ return _.sprintf('%d', value);
+ case 'float':
+ var precision = descriptor.digits ? descriptor.digits[1] : 2;
+ var int_part = Math.floor(value);
+ var dec_part = Math.abs(Math.floor((value % 1) * Math.pow(10, precision)));
+ return _.sprintf('%d%s%d',
+ int_part,
+ openerp.web._t.database.parameters.decimal_point, dec_part);
+ case 'float_time':
+ return _.sprintf("%02d:%02d",
+ Math.floor(value),
+ Math.round((value % 1) * 60));
+ case 'progressbar':
+ return _.sprintf(
+ '<progress value="%.2f" max="100.0">%.2f%%</progress>',
+ value, value);
+ case 'many2one':
+ // name_get value format
+ return value[1];
+ case 'datetime':
+ if (typeof(value) == "string")
+ value = openerp.web.auto_str_to_date(value);
+ try {
+ return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
+ Date.CultureInfo.formatPatterns.longTime));
+ } catch (e) {
+ return value.format("%m/%d/%Y %H:%M:%S");
+ }
+ return value;
+ case 'date':
+ if (typeof(value) == "string")
+ value = openerp.web.auto_str_to_date(value);
+ try {
+ return value.toString(Date.CultureInfo.formatPatterns.shortDate);
+ } catch (e) {
+ return value.format("%m/%d/%Y");
+ }
+ case 'time':
+ if (typeof(value) == "string")
+ value = openerp.web.auto_str_to_date(value);
+ try {
+ return value.toString(Date.CultureInfo.formatPatterns.longTime);
+ } catch (e) {
+ return value.format("%H:%M:%S");
+ }
+ default:
+ return value;
+ }
+};
+
+openerp.web.parse_value = function (value, descriptor, value_if_empty) {
+ switch (value) {
+ case false:
+ case "":
+ return value_if_empty === undefined ? false : value_if_empty;
+ }
+ switch (descriptor.widget || descriptor.type) {
+ case 'integer':
+ var tmp = Number(value);
+ if (isNaN(tmp))
+ throw value + " is not a correct integer";
+ return tmp;
+ case 'float':
+ var tmp = Number(value);
+ if (!isNaN(tmp))
+ return tmp;
+ tmp = value.replace(openerp.web._t.database.parameters.decimal_point, ".");
+ var tmp2 = tmp;
+ do {
+ tmp = tmp2;
+ tmp2 = tmp.replace(openerp.web._t.database.parameters.thousands_sep, "");
+ } while(tmp !== tmp2);
+ tmp = Number(tmp);
+ if (isNaN(tmp))
+ throw value + " is not a correct float";
+ return tmp;
+ case 'float_time':
+ var tmp = value.split(":");
+ if (tmp.length != 2)
+ throw value + " is not a correct float_time";
+ var tmp1 = openerp.web.parse_value(tmp[0], {type: "integer"});
+ var tmp2 = openerp.web.parse_value(tmp[1], {type: "integer"});
+ return tmp1 + (tmp2 / 60);
+ case 'progressbar':
+ return openerp.web.parse_value(value, {type: "float"});
+ case 'datetime':
+ var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
+ Date.CultureInfo.formatPatterns.longTime));
+ if (tmp !== null)
+ return tmp;
+ tmp = Date.parse(value);
+ if (tmp !== null)
+ return tmp;
+ throw value + " is not a valid datetime";
+ case 'date':
+ var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate);
+ if (tmp !== null)
+ return tmp;
+ tmp = Date.parse(value);
+ if (tmp !== null)
+ return tmp;
+ throw value + " is not a valid date";
+ case 'time':
+ var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime);
+ if (tmp !== null)
+ return tmp;
+ tmp = Date.parse(value);
+ if (tmp !== null)
+ return tmp;
+ throw value + " is not a valid time";
+ }
+ return value;
+};
+
+openerp.web.auto_str_to_date = function(value, type) {
+ try {
+ return openerp.web.str_to_datetime(value);
+ } catch(e) {}
+ try {
+ return openerp.web.str_to_date(value);
+ } catch(e) {}
+ try {
+ return openerp.web.str_to_time(value);
+ } catch(e) {}
+ throw "'" + value + "' is not a valid date, datetime nor time"
+};
+
+openerp.web.auto_date_to_str = function(value, type) {
+ switch(type) {
+ case 'datetime':
+ return openerp.web.datetime_to_str(value);
+ case 'date':
+ return openerp.web.date_to_str(value);
+ case 'time':
+ return openerp.web.time_to_str(value);
+ default:
+ throw type + " is not convertible to date, datetime nor time"
+ }
+};
+
+/**
+ * Formats a provided cell based on its field type
+ *
+ * @param {Object} row_data record whose values should be displayed in the cell
+ * @param {Object} column column descriptor
+ * @param {"button"|"field"} column.tag base control type
+ * @param {String} column.type widget type for a field control
+ * @param {String} [column.string] button label
+ * @param {String} [column.icon] button icon
+ * @param {String} [value_if_empty=''] what to display if the field's value is ``false``
+ */
+openerp.web.format_cell = function (row_data, column, value_if_empty) {
+ var attrs = column.modifiers_for(row_data);
+ if (attrs.invisible) { return ''; }
+ if (column.tag === 'button') {
+ return [
+ '<button type="button" title="', column.string || '', '">',
+ '<img src="/web/static/src/img/icons/', column.icon, '.png"',
+ ' alt="', column.string || '', '"/>',
+ '</button>'
+ ].join('')
+ }
+
+ if (!row_data[column.id]) {
+ return value_if_empty === undefined ? '' : value_if_empty;
+ }
+ return openerp.web.format_value(
+ row_data[column.id].value, column, value_if_empty);
+}
+
+};
diff --git a/addons/web/static/src/js/list-editable.js b/addons/web/static/src/js/list-editable.js
new file mode 100644
index 00000000000..c38c43a4c9c
--- /dev/null
+++ b/addons/web/static/src/js/list-editable.js
@@ -0,0 +1,336 @@
+/**
+ * handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
+ * @namespace
+ */
+openerp.web.list_editable = function (openerp) {
+ var KEY_RETURN = 13,
+ KEY_ESCAPE = 27;
+
+ // editability status of list rows
+ openerp.web.ListView.prototype.defaults.editable = null;
+
+ // TODO: not sure second @lends on existing item is correct, to check
+ openerp.web.ListView.include(/** @lends openerp.web.ListView# */{
+ init: function () {
+ var self = this;
+ this._super.apply(this, arguments);
+ $(this.groups).bind({
+ 'edit': function (e, id, dataset) {
+ self.do_edit(dataset.index, id, dataset);
+ },
+ 'saved': function () {
+ if (self.groups.get_selection().length) {
+ return;
+ }
+ self.compute_aggregates();
+ }
+ })
+ },
+ /**
+ * Handles the activation of a record in editable mode (making a record
+ * editable), called *after* the record has become editable.
+ *
+ * The default behavior is to setup the listview's dataset to match
+ * whatever dataset was provided by the editing List
+ *
+ * @param {Number} index index of the record in the dataset
+ * @param {Object} id identifier of the record being edited
+ * @param {openerp.web.DataSet} dataset dataset in which the record is available
+ */
+ do_edit: function (index, id, dataset) {
+ _.extend(this.dataset, dataset);
+ },
+ /**
+ * Sets editability status for the list, based on defaults, view
+ * architecture and the provided flag, if any.
+ *
+ * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom".
+ */
+ set_editable: function (force) {
+ // If ``force``, set editability to bottom
+ // otherwise rely on view default
+ // view' @editable is handled separately as we have not yet
+ // fetched and processed the view at this point.
+ this.options.editable = (
+ (force && "bottom")
+ || this.defaults.editable);
+ },
+ /**
+ * Replace do_actual_search to handle editability process
+ */
+ do_actual_search: function (results) {
+ this.set_editable(results.context['set_editable']);
+ this._super(results);
+ },
+ /**
+ * Replace do_add_record to handle editability (and adding new record
+ * as an editable row at the top or bottom of the list)
+ */
+ do_add_record: function () {
+ if (this.options.editable) {
+ this.groups.new_record();
+ } else {
+ this._super();
+ }
+ },
+ on_loaded: function (data, grouped) {
+ // tree/@editable takes priority on everything else if present.
+ this.options.editable = data.arch.attrs.editable || this.options.editable;
+ return this._super(data, grouped);
+ }
+ });
+
+ openerp.web.ListView.Groups.include(/** @lends openerp.web.ListView.Groups# */{
+ passtrough_events: openerp.web.ListView.Groups.prototype.passtrough_events + " edit saved",
+ new_record: function () {
+ // TODO: handle multiple children
+ this.children[null].new_record();
+ }
+ });
+
+ openerp.web.ListView.List.include(/** @lends openerp.web.ListView.List# */{
+ row_clicked: function (event) {
+ if (!this.options.editable) {
+ return this._super(event);
+ }
+ this.edit_record($(event.currentTarget).data('id'));
+ },
+ /**
+ * Checks if a record is being edited, and if so cancels it
+ */
+ cancel_pending_edition: function () {
+ var self = this, cancelled = $.Deferred();
+ if (!this.edition) {
+ cancelled.resolve();
+ return cancelled.promise();
+ }
+
+ if (this.edition_id != null) {
+ this.reload_record(self.records.get(this.edition_id)).then(function () {
+ cancelled.resolve();
+ });
+ } else {
+ cancelled.resolve();
+ }
+ cancelled.then(function () {
+ self.view.unpad_columns();
+ self.edition_form.stop();
+ self.edition_form.$element.remove();
+ delete self.edition_form;
+ delete self.edition_id;
+ delete self.edition;
+ });
+ return cancelled.promise();
+ },
+ /**
+ * Adapts this list's view description to be suitable to the inner form
+ * view of a row being edited.
+ *
+ * @returns {Object} fields_view_get's view section suitable for putting into form view of editable rows.
+ */
+ get_form_fields_view: function () {
+ // deep copy of view
+ var view = $.extend(true, {}, this.group.view.fields_view);
+ _(view.arch.children).each(function (widget) {
+ widget.attrs.nolabel = true;
+ if (widget.tag === 'button') {
+ delete widget.attrs.string;
+ }
+ });
+ view.arch.attrs.col = 2 * view.arch.children.length;
+ return view;
+ },
+ render_row_as_form: function (row) {
+ var self = this;
+ this.cancel_pending_edition().then(function () {
+ var record_id = $(row).data('id');
+ var $new_row = $('<tr>', {
+ id: _.uniqueId('oe-editable-row-'),
+ 'data-id': record_id,
+ 'class': $(row).attr('class') + ' oe_forms',
+ click: function (e) {e.stopPropagation();}
+ })
+ .delegate('button.oe-edit-row-save', 'click', function () {
+ self.save_row();
+ })
+ .delegate('button.oe-edit-row-cancel', 'click', function () {
+ self.cancel_edition();
+ })
+ .delegate('button', 'keyup', function (e) {
+ e.stopImmediatePropagation();
+ })
+ .keyup(function (e) {
+ switch (e.which) {
+ case KEY_RETURN:
+ self.save_row(true);
+ break;
+ case KEY_ESCAPE:
+ self.cancel_edition();
+ break;
+ default:
+ return;
+ }
+ });
+ if (row) {
+ $new_row.replaceAll(row);
+ } else if (self.options.editable === 'top') {
+ self.$current.prepend($new_row);
+ } else if (self.options.editable) {
+ self.$current.append($new_row);
+ }
+ self.edition = true;
+ self.edition_id = record_id;
+ self.edition_form = _.extend(new openerp.web.FormView(
+ self, $new_row.attr('id'), self.dataset, false), {
+ template: 'ListView.row.form',
+ registry: openerp.web.list.form.widgets
+ });
+ $.when(self.edition_form.on_loaded(self.get_form_fields_view())).then(function () {
+ // put in $.when just in case FormView.on_loaded becomes asynchronous
+ $new_row.find('td')
+ .addClass('oe-field-cell')
+ .removeAttr('width')
+ .end()
+ .find('td:first').removeClass('oe-field-cell').end()
+ .find('td:last').removeClass('oe-field-cell').end();
+ // pad in case of groupby
+ _(self.columns).each(function (column) {
+ if (column.meta) {
+ $new_row.prepend('<td>');
+ }
+ });
+ // Add columns for the cancel and save buttons, if
+ // there are none in the list
+ if (!self.options.selectable) {
+ self.view.pad_columns(
+ 1, {except: $new_row, position: 'before'});
+ }
+ if (!self.options.deletable) {
+ self.view.pad_columns(
+ 1, {except: $new_row});
+ }
+
+ self.edition_form.do_show();
+ });
+ });
+ },
+ handle_onwrite: function (source_record_id) {
+ var self = this;
+ var on_write_callback = self.view.fields_view.arch.attrs.on_write;
+ if (!on_write_callback) { return; }
+ this.dataset.call(on_write_callback, [source_record_id], function (ids) {
+ _(ids).each(function (id) {
+ var record = self.records.get(id);
+ if (!record) {
+ // insert after the source record
+ var index = self.records.indexOf(
+ self.records.get(source_record_id)) + 1;
+ record = new openerp.web.list.Record({id: id});
+ self.records.add(record, {at: index});
+ self.dataset.ids.splice(index, 0, id);
+ }
+ self.reload_record(record);
+ });
+ });
+ },
+ /**
+ * Saves the current row, and triggers the edition of its following
+ * sibling if asked.
+ *
+ * @param {Boolean} [edit_next=false] should the next row become editable
+ */
+ save_row: function (edit_next) {
+ var self = this;
+ this.edition_form.do_save(function (result) {
+ if (result.created && !self.edition_id) {
+ self.records.add({id: result.result},
+ {at: self.options.editable === 'top' ? 0 : null});
+ self.edition_id = result.result;
+ }
+ var edited_record = self.records.get(self.edition_id),
+ next_record = self.records.at(
+ self.records.indexOf(edited_record) + 1);
+
+ self.handle_onwrite(self.edition_id);
+ self.cancel_pending_edition().then(function () {
+ $(self).trigger('saved', [self.dataset]);
+ if (!edit_next) {
+ return;
+ }
+ if (result.created) {
+ self.new_record();
+ return;
+ }
+ var next_record_id;
+ if (next_record) {
+ next_record_id = next_record.get('id');
+ self.dataset.index = _(self.dataset.ids)
+ .indexOf(next_record_id);
+ } else {
+ self.dataset.index = 0;
+ next_record_id = self.records.at(0).get('id');
+ }
+ self.edit_record(next_record_id);
+ });
+ }, this.options.editable === 'top');
+ },
+ /**
+ * Cancels the edition of the row for the current dataset index
+ */
+ cancel_edition: function () {
+ this.cancel_pending_edition();
+ },
+ /**
+ * Edits record currently selected via dataset
+ */
+ edit_record: function (record_id) {
+ this.render_row_as_form(
+ this.$current.find('[data-id=' + record_id + ']'));
+ $(this).trigger(
+ 'edit',
+ [record_id, this.dataset]);
+ },
+ new_record: function () {
+ this.dataset.index = null;
+ this.render_row_as_form();
+ }
+ });
+ if (!openerp.web.list) {
+ openerp.web.list = {};
+ }
+ if (!openerp.web.list.form) {
+ openerp.web.list.form = {};
+ }
+ openerp.web.list.form.WidgetFrame = openerp.web.form.WidgetFrame.extend({
+ template: 'ListView.row.frame'
+ });
+ var form_widgets = openerp.web.form.widgets;
+ openerp.web.list.form.widgets = form_widgets.clone({
+ 'frame': 'openerp.web.list.form.WidgetFrame'
+ });
+ // All form widgets inherit a problematic behavior from
+ // openerp.web.form.WidgetFrame: the cell itself is removed when invisible
+ // whether it's @invisible or @attrs[invisible]. In list view, only the
+ // former should completely remove the cell. We need to override update_dom
+ // on all widgets since we can't just hit on widget itself (I think)
+ var list_form_widgets = openerp.web.list.form.widgets;
+ _(list_form_widgets.map).each(function (widget_path, key) {
+ if (key === 'frame') { return; }
+ var new_path = 'openerp.web.list.form.' + key;
+
+ openerp.web.list.form[key] = (form_widgets.get_object(key)).extend({
+ update_dom: function () {
+ this.$element.children().css('visibility', '');
+ if (this.modifiers.tree_invisible) {
+ var old_invisible = this.invisible;
+ this.invisible = !!this.modifiers.tree_invisible;
+ this._super();
+ this.invisible = old_invisible;
+ } else if (this.invisible) {
+ this.$element.children().css('visibility', 'hidden');
+ }
+ }
+ });
+ list_form_widgets.add(key, new_path);
+ });
+};
diff --git a/addons/web/static/src/js/list.js b/addons/web/static/src/js/list.js
new file mode 100644
index 00000000000..95a8207144b
--- /dev/null
+++ b/addons/web/static/src/js/list.js
@@ -0,0 +1,1523 @@
+openerp.web.list = function (openerp) {
+var QWeb = openerp.web.qweb;
+openerp.web.views.add('list', 'openerp.web.ListView');
+openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# */ {
+ defaults: {
+ // records can be selected one by one
+ 'selectable': true,
+ // list rows can be deleted
+ 'deletable': true,
+ // whether the column headers should be displayed
+ 'header': true,
+ // display addition button, with that label
+ 'addable': "New",
+ // whether the list view can be sorted, note that once a view has been
+ // sorted it can not be reordered anymore
+ 'sortable': true,
+ // whether the view rows can be reordered (via vertical drag & drop)
+ 'reorderable': true
+ },
+ /**
+ * Core class for list-type displays.
+ *
+ * As a view, needs a number of view-related parameters to be correctly
+ * instantiated, provides options and overridable methods for behavioral
+ * customization.
+ *
+ * See constructor parameters and method documentations for information on
+ * the default behaviors and possible options for the list view.
+ *
+ * @constructs openerp.web.ListView
+ * @extends openerp.web.View
+ *
+ * @param parent parent object
+ * @param element_id the id of the DOM elements this view should link itself to
+ * @param {openerp.web.DataSet} dataset the dataset the view should work with
+ * @param {String} view_id the listview's identifier, if any
+ * @param {Object} options A set of options used to configure the view
+ * @param {Boolean} [options.selectable=true] determines whether view rows are selectable (e.g. via a checkbox)
+ * @param {Boolean} [options.header=true] should the list's header be displayed
+ * @param {Boolean} [options.deletable=true] are the list rows deletable
+ * @param {void|String} [options.addable="New"] should the new-record button be displayed, and what should its label be. Use ``null`` to hide the button.
+ * @param {Boolean} [options.sortable=true] is it possible to sort the table by clicking on column headers
+ * @param {Boolean} [options.reorderable=true] is it possible to reorder list rows
+ *
+ * @borrows openerp.web.ActionExecutor#execute_action as #execute_action
+ */
+ init: function(parent, element_id, dataset, view_id, options) {
+ var self = this;
+ this._super(parent, element_id);
+ this.set_default_options(_.extend({}, this.defaults, options || {}));
+ this.dataset = dataset;
+ this.model = dataset.model;
+ this.view_id = view_id;
+ this.previous_colspan = null;
+
+ this.columns = [];
+
+ this.records = new Collection();
+
+ this.set_groups(new openerp.web.ListView.Groups(this));
+
+ if (this.dataset instanceof openerp.web.DataSetStatic) {
+ this.groups.datagroup = new openerp.web.StaticDataGroup(this.dataset);
+ } else {
+ this.groups.datagroup = new openerp.web.DataGroup(
+ this, this.model,
+ dataset.get_domain(),
+ dataset.get_context(),
+ {});
+ this.groups.datagroup.sort = this.dataset._sort;
+ }
+
+ this.page = 0;
+ this.records.bind('change', function (event, record, key) {
+ if (!_(self.aggregate_columns).chain()
+ .pluck('name').contains(key).value()) {
+ return;
+ }
+ self.compute_aggregates();
+ });
+ },
+ /**
+ * Retrieves the view's number of records per page (|| section)
+ *
+ * options > defaults > parent.action.limit > indefinite
+ *
+ * @returns {Number|null}
+ */
+ limit: function () {
+ if (this._limit === undefined) {
+ this._limit = (this.options.limit
+ || this.defaults.limit
+ || (this.widget_parent.action || {}).limit
+ || null);
+ }
+ return this._limit;
+ },
+ /**
+ * Set a custom Group construct as the root of the List View.
+ *
+ * @param {openerp.web.ListView.Groups} groups
+ */
+ set_groups: function (groups) {
+ var self = this;
+ if (this.groups) {
+ $(this.groups).unbind("selected deleted action row_link");
+ delete this.groups;
+ }
+
+ this.groups = groups;
+ $(this.groups).bind({
+ 'selected': function (e, ids, records) {
+ self.do_select(ids, records);
+ },
+ 'deleted': function (e, ids) {
+ self.do_delete(ids);
+ },
+ 'action': function (e, action_name, id, callback) {
+ self.do_button_action(action_name, id, callback);
+ },
+ 'row_link': function (e, id, dataset) {
+ self.do_activate_record(dataset.index, id, dataset);
+ }
+ });
+ },
+ /**
+ * View startup method, the default behavior is to set the ``oe-listview``
+ * class on its root element and to perform an RPC load call.
+ *
+ * @returns {$.Deferred} loading promise
+ */
+ start: function() {
+ this.$element.addClass('oe-listview');
+ return this.reload_view(null, null, true);
+ },
+ /**
+ * Called after loading the list view's description, sets up such things
+ * as the view table's columns, renders the table itself and hooks up the
+ * various table-level and row-level DOM events (action buttons, deletion
+ * buttons, selection of records, [New] button, selection of a given
+ * record, ...)
+ *
+ * Sets up the following:
+ *
+ * * Processes arch and fields to generate a complete field descriptor for each field
+ * * Create the table itself and allocate visible columns
+ * * Hook in the top-level (header) [New|Add] and [Delete] button
+ * * Sets up showing/hiding the top-level [Delete] button based on records being selected or not
+ * * Sets up event handlers for action buttons and per-row deletion button
+ * * Hooks global callback for clicking on a row
+ * * Sets up its sidebar, if any
+ *
+ * @param {Object} data wrapped fields_view_get result
+ * @param {Object} data.fields_view fields_view_get result (processed)
+ * @param {Object} data.fields_view.fields mapping of fields for the current model
+ * @param {Object} data.fields_view.arch current list view descriptor
+ * @param {Boolean} grouped Is the list view grouped
+ */
+ on_loaded: function(data, grouped) {
+ var self = this;
+ this.fields_view = data;
+ this.name = "" + this.fields_view.arch.attrs.string;
+
+ this.setup_columns(this.fields_view.fields, grouped);
+
+ this.$element.html(QWeb.render("ListView", this));
+
+ // Head hook
+ this.$element.find('.oe-list-add')
+ .click(this.do_add_record)
+ .attr('disabled', grouped && this.options.editable);
+ this.$element.find('.oe-list-delete')
+ .attr('disabled', true)
+ .click(this.do_delete_selected);
+ this.$element.find('thead').delegate('th.oe-sortable[data-id]', 'click', function (e) {
+ e.stopPropagation();
+
+ var $this = $(this);
+ self.dataset.sort($this.data('id'));
+ if ($this.find('span').length) {
+ $this.find('span').toggleClass(
+ 'ui-icon-triangle-1-s ui-icon-triangle-1-n');
+ } else {
+ $this.append('<span class="ui-icon ui-icon-triangle-1-s">')
+ .siblings('.oe-sortable').find('span').remove();
+ }
+
+ self.reload_content();
+ });
+
+ this.$element.find('.oe-list-pager')
+ .delegate('button', 'click', function () {
+ var $this = $(this);
+ switch ($this.data('pager-action')) {
+ case 'first':
+ self.page = 0; break;
+ case 'last':
+ self.page = Math.floor(
+ self.dataset.ids.length / self.limit());
+ break;
+ case 'next':
+ self.page += 1; break;
+ case 'previous':
+ self.page -= 1; break;
+ }
+ self.reload_content();
+ }).find('.oe-pager-state')
+ .click(function (e) {
+ e.stopPropagation();
+ var $this = $(this);
+
+ var $select = $('<select>')
+ .appendTo($this.empty())
+ .click(function (e) {e.stopPropagation();})
+ .append('<option value="80">80</option>' +
+ '<option value="100">100</option>' +
+ '<option value="200">200</option>' +
+ '<option value="500">500</option>' +
+ '<option value="NaN">Unlimited</option>')
+ .change(function () {
+ var val = parseInt($select.val(), 10);
+ self._limit = (isNaN(val) ? null : val);
+ self.page = 0;
+ self.reload_content();
+ })
+ .val(self._limit || 'NaN');
+ });
+ if (!this.sidebar && this.options.sidebar && this.options.sidebar_id) {
+ this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
+ this.sidebar.start();
+ this.sidebar.add_toolbar(this.fields_view.toolbar);
+ this.set_common_sidebar_sections(this.sidebar);
+ }
+ },
+ /**
+ * Configures the ListView pager based on the provided dataset's information
+ *
+ * Horrifying side-effect: sets the dataset's data on this.dataset?
+ *
+ * @param {openerp.web.DataSet} dataset
+ */
+ configure_pager: function (dataset) {
+ this.dataset.ids = dataset.ids;
+
+ var limit = this.limit(),
+ total = dataset.ids.length,
+ first = (this.page * limit),
+ last;
+ if (!limit || (total - first) < limit) {
+ last = total;
+ } else {
+ last = first + limit;
+ }
+ this.$element.find('span.oe-pager-state').empty().text(_.sprintf(
+ "[%d to %d] of %d", first + 1, last, total));
+
+ this.$element
+ .find('button[data-pager-action=first], button[data-pager-action=previous]')
+ .attr('disabled', this.page === 0)
+ .end()
+ .find('button[data-pager-action=last], button[data-pager-action=next]')
+ .attr('disabled', last === total);
+ },
+ /**
+ * Sets up the listview's columns: merges view and fields data, move
+ * grouped-by columns to the front of the columns list and make them all
+ * visible.
+ *
+ * @param {Object} fields fields_view_get's fields section
+ * @param {Boolean} [grouped] Should the grouping columns (group and count) be displayed
+ */
+ setup_columns: function (fields, grouped) {
+ var domain_computer = openerp.web.form.compute_domain;
+
+ var noop = function () { return {}; };
+ var field_to_column = function (field) {
+ var name = field.attrs.name;
+ var column = _.extend({id: name, tag: field.tag},
+ field.attrs, fields[name]);
+ // modifiers computer
+ if (column.modifiers) {
+ var modifiers = JSON.parse(column.modifiers);
+ column.modifiers_for = function (fields) {
+ if (!modifiers.invisible) {
+ return {};
+ }
+ return {
+ 'invisible': domain_computer(modifiers.invisible, fields)
+ };
+ };
+ if (modifiers['tree_invisible']) {
+ column.invisible = '1';
+ }
+ } else {
+ column.modifiers_for = noop;
+ }
+ return column;
+ };
+
+ this.columns.splice(0, this.columns.length);
+ this.columns.push.apply(
+ this.columns,
+ _(this.fields_view.arch.children).map(field_to_column));
+ if (grouped) {
+ this.columns.unshift({
+ id: '_group', tag: '', string: "Group", meta: true,
+ modifiers_for: function () { return {}; }
+ }, {
+ id: '_count', tag: '', string: '#', meta: true,
+ modifiers_for: function () { return {}; }
+ });
+ }
+
+ this.visible_columns = _.filter(this.columns, function (column) {
+ return column.invisible !== '1';
+ });
+
+ this.aggregate_columns = _(this.visible_columns)
+ .map(function (column) {
+ if (column.type !== 'integer' && column.type !== 'float') {
+ return {};
+ }
+ var aggregation_func = column['group_operator'] || 'sum';
+
+ return _.extend({}, column, {
+ 'function': aggregation_func,
+ label: column[aggregation_func]
+ });
+ });
+ },
+ /**
+ * Used to handle a click on a table row, if no other handler caught the
+ * event.
+ *
+ * The default implementation asks the list view's view manager to switch
+ * to a different view (by calling
+ * :js:func:`~openerp.web.ViewManager.on_mode_switch`), using the
+ * provided record index (within the current list view's dataset).
+ *
+ * If the index is null, ``switch_to_record`` asks for the creation of a
+ * new record.
+ *
+ * @param {Number|void} index the record index (in the current dataset) to switch to
+ * @param {String} [view="form"] the view type to switch to
+ */
+ select_record:function (index, view) {
+ view = view || 'form';
+ this.dataset.index = index;
+ _.delay(_.bind(function () {
+ this.do_switch_view(view);
+ }, this));
+ },
+ do_show: function () {
+ this.$element.show();
+ if (this.sidebar) {
+ this.sidebar.$element.show();
+ }
+ if (!_(this.dataset.ids).isEmpty()) {
+ this.reload_content();
+ }
+ },
+ do_hide: function () {
+ this.$element.hide();
+ if (this.sidebar) {
+ this.sidebar.$element.hide();
+ }
+ },
+ /**
+ * Reloads the list view based on the current settings (dataset & al)
+ *
+ * @param {Boolean} [grouped] Should the list be displayed grouped
+ * @param {Object} [context] context to send the server while loading the view
+ */
+ reload_view: function (grouped, context, initial) {
+ var self = this;
+ var callback = function (field_view_get) {
+ self.on_loaded(field_view_get, grouped);
+ };
+ if (this.embedded_view) {
+ return $.Deferred().then(callback).resolve(this.embedded_view);
+ } else {
+ return this.rpc('/web/listview/load', {
+ model: this.model,
+ view_id: this.view_id,
+ view_type: "tree",
+ context: this.dataset.get_context(context),
+ toolbar: this.options.sidebar
+ }, callback);
+ }
+ },
+ /**
+ * re-renders the content of the list view
+ */
+ reload_content: function () {
+ var self = this;
+ this.records.reset();
+ this.$element.find('.oe-listview-content').append(
+ this.groups.render(function () {
+ if (self.dataset.index == null) {
+ var has_one = false;
+ self.records.each(function () { has_one = true; });
+ if (has_one) {
+ self.dataset.index = 0;
+ }
+ }
+ self.compute_aggregates();
+ }));
+ },
+ /**
+ * Event handler for a search, asks for the computation/folding of domains
+ * and contexts (and group-by), then reloads the view's content.
+ *
+ * @param {Array} domains a sequence of literal and non-literal domains
+ * @param {Array} contexts a sequence of literal and non-literal contexts
+ * @param {Array} groupbys a sequence of literal and non-literal group-by contexts
+ * @returns {$.Deferred} fold request evaluation promise
+ */
+ do_search: function (domains, contexts, groupbys) {
+ return this.rpc('/web/session/eval_domain_and_context', {
+ domains: [this.dataset.get_domain()].concat(domains),
+ contexts: [this.dataset.get_context()].concat(contexts),
+ group_by_seq: groupbys
+ }, $.proxy(this, 'do_actual_search'));
+ },
+ /**
+ * Handler for the result of eval_domain_and_context, actually perform the
+ * searching
+ *
+ * @param {Object} results results of evaluating domain and process for a search
+ */
+ do_actual_search: function (results) {
+ this.groups.datagroup = new openerp.web.DataGroup(
+ this, this.model,
+ results.domain,
+ results.context,
+ results.group_by);
+ this.groups.datagroup.sort = this.dataset._sort;
+
+ if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) {
+ results.group_by = null;
+ }
+
+ this.reload_view(!!results.group_by, results.context).then(
+ $.proxy(this, 'reload_content'));
+ },
+ /**
+ * Handles the signal to delete lines from the records list
+ *
+ * @param {Array} ids the ids of the records to delete
+ */
+ do_delete: function (ids) {
+ if (!ids.length) {
+ return;
+ }
+ var self = this;
+ return $.when(this.dataset.unlink(ids)).then(function () {
+ _(ids).each(function (id) {
+ self.records.remove(self.records.get(id));
+ });
+ self.compute_aggregates();
+ });
+ },
+ /**
+ * Handles the signal indicating that a new record has been selected
+ *
+ * @param {Array} ids selected record ids
+ * @param {Array} records selected record values
+ */
+ do_select: function (ids, records) {
+ this.$element.find('.oe-list-delete')
+ .attr('disabled', !ids.length);
+
+ if (!records.length) {
+ this.compute_aggregates();
+ return;
+ }
+ this.compute_aggregates(_(records).map(function (record) {
+ return {count: 1, values: record};
+ }));
+ },
+ /**
+ * Handles action button signals on a record
+ *
+ * @param {String} name action name
+ * @param {Object} id id of the record the action should be called on
+ * @param {Function} callback should be called after the action is executed, if non-null
+ */
+ do_button_action: function (name, id, callback) {
+ var action = _.detect(this.columns, function (field) {
+ return field.name === name;
+ });
+ if (!action) { return; }
+ this.execute_action(action, this.dataset, id, callback);
+ },
+ /**
+ * Handles the activation of a record (clicking on it)
+ *
+ * @param {Number} index index of the record in the dataset
+ * @param {Object} id identifier of the activated record
+ * @param {openerp.web.DataSet} dataset dataset in which the record is available (may not be the listview's dataset in case of nested groups)
+ */
+ do_activate_record: function (index, id, dataset) {
+ var self = this;
+ // TODO is it needed ?
+ this.dataset.read_slice([],{
+ context: dataset.get_context(),
+ domain: dataset.get_domain()
+ }, function () {
+ self.select_record(index);
+ });
+ },
+ /**
+ * Handles signal for the addition of a new record (can be a creation,
+ * can be the addition from a remote source, ...)
+ *
+ * The default implementation is to switch to a new record on the form view
+ */
+ do_add_record: function () {
+ this.select_record(null);
+ },
+ /**
+ * Handles deletion of all selected lines
+ */
+ do_delete_selected: function () {
+ this.do_delete(this.groups.get_selection().ids);
+ },
+ /**
+ * Computes the aggregates for the current list view, either on the
+ * records provided or on the records of the internal
+ * :js:class:`~openerp.web.ListView.Group`, by calling
+ * :js:func:`~openerp.web.ListView.group.get_records`.
+ *
+ * Then displays the aggregates in the table through
+ * :js:method:`~openerp.web.ListView.display_aggregates`.
+ *
+ * @param {Array} [records]
+ */
+ compute_aggregates: function (records) {
+ var columns = _(this.aggregate_columns).filter(function (column) {
+ return column['function']; });
+ if (_.isEmpty(columns)) { return; }
+
+ if (_.isEmpty(records)) {
+ records = this.groups.get_records();
+ }
+
+ var count = 0, sums = {};
+ _(columns).each(function (column) {
+ switch (column['function']) {
+ case 'max':
+ sums[column.id] = -Infinity;
+ break;
+ case 'min':
+ sums[column.id] = Infinity;
+ break;
+ default:
+ sums[column.id] = 0;
+ }
+ });
+ _(records).each(function (record) {
+ count += record.count || 1;
+ _(columns).each(function (column) {
+ var field = column.id,
+ value = record.values[field];
+ switch (column['function']) {
+ case 'sum':
+ sums[field] += value;
+ break;
+ case 'avg':
+ sums[field] += record.count * value;
+ break;
+ case 'min':
+ if (sums[field] > value) {
+ sums[field] = value;
+ }
+ break;
+ case 'max':
+ if (sums[field] < value) {
+ sums[field] = value;
+ }
+ break;
+ }
+ });
+ });
+
+ var aggregates = {};
+ _(columns).each(function (column) {
+ var field = column.id;
+ switch (column['function']) {
+ case 'avg':
+ aggregates[field] = {value: sums[field] / count};
+ break;
+ default:
+ aggregates[field] = {value: sums[field]};
+ }
+ });
+
+ this.display_aggregates(aggregates);
+ },
+ display_aggregates: function (aggregation) {
+ var $footer_cells = this.$element.find('.oe-list-footer');
+ _(this.aggregate_columns).each(function (column) {
+ if (!column['function']) {
+ return;
+ }
+
+ $footer_cells.filter(_.sprintf('[data-field=%s]', column.id))
+ .html(openerp.web.format_cell(aggregation, column));
+ });
+ },
+ get_selected_ids: function() {
+ var ids = this.groups.get_selection().ids;
+ return ids;
+ },
+ /**
+ * Adds padding columns at the start or end of all table rows (including
+ * field names row)
+ *
+ * @param {Number} count number of columns to add
+ * @param {Object} options
+ * @param {"before"|"after"} [position="after"] insertion position for the new columns
+ * @param {Object} [except] content row to not pad
+ */
+ pad_columns: function (count, options) {
+ options = options || {};
+ // padding for action/pager header
+ var $first_header = this.$element.find('thead tr:first th');
+ var colspan = $first_header.attr('colspan');
+ if (colspan) {
+ if (!this.previous_colspan) {
+ this.previous_colspan = colspan;
+ }
+ $first_header.attr('colspan', parseInt(colspan, 10) + count);
+ }
+ // Padding for column titles, footer and data rows
+ var $rows = this.$element
+ .find('.oe-listview-header-columns, tr:not(thead tr)')
+ .not(options['except']);
+ var newcols = new Array(count+1).join('<td class="oe-listview-padding"></td>');
+ if (options.position === 'before') {
+ $rows.prepend(newcols);
+ } else {
+ $rows.append(newcols);
+ }
+ },
+ /**
+ * Removes all padding columns of the table
+ */
+ unpad_columns: function () {
+ this.$element.find('.oe-listview-padding').remove();
+ if (this.previous_colspan) {
+ this.$element
+ .find('thead tr:first th')
+ .attr('colspan', this.previous_colspan);
+ this.previous_colspan = null;
+ }
+ }
+});
+openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.ListView.List# */{
+ /**
+ * List display for the ListView, handles basic DOM events and transforms
+ * them in the relevant higher-level events, to which the list view (or
+ * other consumers) can subscribe.
+ *
+ * Events on this object are registered via jQuery.
+ *
+ * Available events:
+ *
+ * `selected`
+ * Triggered when a row is selected (using check boxes), provides an
+ * array of ids of all the selected records.
+ * `deleted`
+ * Triggered when deletion buttons are hit, provide an array of ids of
+ * all the records being marked for suppression.
+ * `action`
+ * Triggered when an action button is clicked, provides two parameters:
+ *
+ * * The name of the action to execute (as a string)
+ * * The id of the record to execute the action on
+ * `row_link`
+ * Triggered when a row of the table is clicked, provides the index (in
+ * the rows array) and id of the selected record to the handle function.
+ *
+ * @constructs openerp.web.ListView.List
+ * @extends openerp.web.Class
+ *
+ * @param {Object} opts display options, identical to those of :js:class:`openerp.web.ListView`
+ */
+ init: function (group, opts) {
+ var self = this;
+ this.group = group;
+ this.view = group.view;
+ this.session = this.view.session;
+
+ this.options = opts.options;
+ this.columns = opts.columns;
+ this.dataset = opts.dataset;
+ this.records = opts.records;
+
+ this.record_callbacks = {
+ 'remove': function (event, record) {
+ var $row = self.$current.find(
+ '[data-id=' + record.get('id') + ']');
+ var index = $row.data('index');
+ $row.remove();
+ self.refresh_zebra(index);
+ },
+ 'reset': $.proxy(this, 'on_records_reset'),
+ 'change': function (event, record) {
+ var $row = self.$current.find('[data-id=' + record.get('id') + ']');
+ $row.replaceWith(self.render_record(record));
+ },
+ 'add': function (ev, records, record, index) {
+ var $new_row = $('<tr>').attr({
+ 'data-id': record.get('id')
+ });
+
+ if (index === 0) {
+ $new_row.prependTo(self.$current);
+ } else {
+ var previous_record = records.at(index-1),
+ $previous_sibling = self.$current.find(
+ '[data-id=' + previous_record.get('id') + ']');
+ $new_row.insertAfter($previous_sibling);
+ }
+
+ self.refresh_zebra(index, 1);
+ }
+ };
+ _(this.record_callbacks).each(function (callback, event) {
+ this.records.bind(event, callback);
+ }, this);
+
+ this.$_element = $('<tbody class="ui-widget-content">')
+ .appendTo(document.body)
+ .delegate('th.oe-record-selector', 'click', function (e) {
+ e.stopPropagation();
+ var selection = self.get_selection();
+ $(self).trigger(
+ 'selected', [selection.ids, selection.records]);
+ })
+ .delegate('td.oe-record-delete button', 'click', function (e) {
+ e.stopPropagation();
+ var $row = $(e.target).closest('tr');
+ $(self).trigger('deleted', [[self.row_id($row)]]);
+ })
+ .delegate('td.oe-field-cell button', 'click', function (e) {
+ e.stopPropagation();
+ var $target = $(e.currentTarget),
+ field = $target.closest('td').data('field'),
+ $row = $target.closest('tr'),
+ record_id = self.row_id($row);
+
+ $(self).trigger('action', [field, record_id, function () {
+ return self.reload_record(self.records.get(record_id));
+ }]);
+ })
+ .delegate('tr', 'click', function (e) {
+ e.stopPropagation();
+ self.dataset.index = self.records.indexOf(
+ self.records.get(
+ self.row_id(e.currentTarget)));
+ self.row_clicked(e);
+ });
+ },
+ row_clicked: function () {
+ $(this).trigger(
+ 'row_link',
+ [this.records.at(this.dataset.index).get('id'),
+ this.dataset]);
+ },
+ render: function () {
+ if (this.$current) {
+ this.$current.remove();
+ }
+ this.$current = this.$_element.clone(true);
+ this.$current.empty().append(
+ QWeb.render('ListView.rows', _.extend({
+ render_cell: openerp.web.format_cell}, this)));
+ },
+ /**
+ * Gets the ids of all currently selected records, if any
+ * @returns {Object} object with the keys ``ids`` and ``records``, holding respectively the ids of all selected records and the records themselves.
+ */
+ get_selection: function () {
+ if (!this.options.selectable) {
+ return [];
+ }
+ var records = this.records;
+ var result = {ids: [], records: []};
+ this.$current.find('th.oe-record-selector input:checked')
+ .closest('tr').each(function () {
+ var record = records.get($(this).data('id'));
+ result.ids.push(record.get('id'));
+ result.records.push(record.attributes);
+ });
+ return result;
+ },
+ /**
+ * Returns the identifier of the object displayed in the provided table
+ * row
+ *
+ * @param {Object} row the selected table row
+ * @returns {Number|String} the identifier of the row's object
+ */
+ row_id: function (row) {
+ return $(row).data('id');
+ },
+ /**
+ * Death signal, cleans up list display
+ */
+ on_records_reset: function () {
+ _(this.record_callbacks).each(function (callback, event) {
+ this.records.unbind(event, callback);
+ }, this);
+ if (!this.$current) { return; }
+ this.$current.remove();
+ this.$current = null;
+ this.$_element.remove();
+ },
+ get_records: function () {
+ return this.records.map(function (record) {
+ return {count: 1, values: record.attributes};
+ });
+ },
+ /**
+ * Reloads the provided record by re-reading its content from the server.
+ *
+ * @param {Record} record
+ * @returns {$.Deferred} promise to the finalization of the reloading
+ */
+ reload_record: function (record) {
+ return this.dataset.read_ids(
+ [record.get('id')],
+ _.pluck(_(this.columns).filter(function (r) {
+ return r.tag === 'field';
+ }), 'name'),
+ function (records) {
+ _(records[0]).each(function (value, key) {
+ record.set(key, value, {silent: true});
+ });
+ record.trigger('change', record);
+ }
+ );
+ },
+ /**
+ * Renders a list record to HTML
+ *
+ * @param {Record} record index of the record to render in ``this.rows``
+ * @returns {String} QWeb rendering of the selected record
+ */
+ render_record: function (record) {
+ var index = this.records.indexOf(record);
+ return QWeb.render('ListView.row', {
+ columns: this.columns,
+ options: this.options,
+ record: record,
+ row_parity: (index % 2 === 0) ? 'even' : 'odd',
+ render_cell: openerp.web.format_cell
+ });
+ },
+ /**
+ * Fixes fixes the even/odd classes
+ *
+ * @param {Number} [from_index] index from which to resequence
+ * @param {Number} [offset = 0] selection offset for DOM, in case there are rows to ignore in the table
+ */
+ refresh_zebra: function (from_index, offset) {
+ offset = offset || 0;
+ from_index = from_index || 0;
+ var dom_offset = offset + from_index;
+ var sel = dom_offset ? ':gt(' + (dom_offset - 1) + ')' : null;
+ this.$current.children(sel).each(function (i, e) {
+ var index = from_index + i;
+ // reset record-index accelerators on rows and even/odd
+ var even = index%2 === 0;
+ $(e).toggleClass('even', even)
+ .toggleClass('odd', !even);
+ });
+ }
+});
+openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.ListView.Groups# */{
+ passtrough_events: 'action deleted row_link',
+ /**
+ * Grouped display for the ListView. Handles basic DOM events and interacts
+ * with the :js:class:`~openerp.web.DataGroup` bound to it.
+ *
+ * Provides events similar to those of
+ * :js:class:`~openerp.web.ListView.List`
+ *
+ * @constructs openerp.web.ListView.Groups
+ * @extends openerp.web.Class
+ *
+ * @param {openerp.web.ListView} view
+ * @param {Object} [options]
+ * @param {Collection} [options.records]
+ * @param {Object} [options.options]
+ * @param {Array} [options.columns]
+ */
+ init: function (view, options) {
+ options = options || {};
+ this.view = view;
+ this.records = options.records || view.records;
+ this.options = options.options || view.options;
+ this.columns = options.columns || view.columns;
+ this.datagroup = null;
+
+ this.$row = null;
+ this.children = {};
+
+ this.page = 0;
+
+ this.records.bind('reset', $.proxy(this, 'on_records_reset'));
+ },
+ make_fragment: function () {
+ return document.createDocumentFragment();
+ },
+ /**
+ * Returns a DOM node after which a new tbody can be inserted, so that it
+ * follows the provided row.
+ *
+ * Necessary to insert the result of a new group or list view within an
+ * existing groups render, without losing track of the groups's own
+ * elements
+ *
+ * @param {HTMLTableRowElement} row the row after which the caller wants to insert a body
+ * @returns {HTMLTableSectionElement} element after which a tbody can be inserted
+ */
+ point_insertion: function (row) {
+ var $row = $(row);
+ var red_letter_tboday = $row.closest('tbody')[0];
+
+ var $next_siblings = $row.nextAll();
+ if ($next_siblings.length) {
+ var $root_kanal = $('<tbody>').insertAfter(red_letter_tboday);
+
+ $root_kanal.append($next_siblings);
+ this.elements.splice(
+ _.indexOf(this.elements, red_letter_tboday),
+ 0,
+ $root_kanal[0]);
+ }
+ return red_letter_tboday;
+ },
+ make_paginator: function () {
+ var self = this;
+ var $prev = $('<button type="button" data-pager-action="previous">&lt;</button>')
+ .click(function (e) {
+ e.stopPropagation();
+ self.page -= 1;
+
+ self.$row.closest('tbody').next()
+ .replaceWith(self.render());
+ });
+ var $next = $('<button type="button" data-pager-action="next">&gt;</button>')
+ .click(function (e) {
+ e.stopPropagation();
+ self.page += 1;
+
+ self.$row.closest('tbody').next()
+ .replaceWith(self.render());
+ });
+ this.$row.children().last()
+ .append($prev)
+ .append('<span class="oe-pager-state"></span>')
+ .append($next);
+ },
+ open: function (point_insertion) {
+ this.render().insertAfter(point_insertion);
+ this.make_paginator();
+ },
+ close: function () {
+ this.$row.children().last().empty();
+ this.records.reset();
+ },
+ /**
+ * Prefixes ``$node`` with floated spaces in order to indent it relative
+ * to its own left margin/baseline
+ *
+ * @param {jQuery} $node jQuery object to indent
+ * @param {Number} level current nesting level, >= 1
+ * @returns {jQuery} the indentation node created
+ */
+ indent: function ($node, level) {
+ return $('<span>')
+ .css({'float': 'left', 'white-space': 'pre'})
+ .text(new Array(level).join(' '))
+ .prependTo($node);
+ },
+ render_groups: function (datagroups) {
+ var self = this;
+ var placeholder = this.make_fragment();
+ _(datagroups).each(function (group) {
+ if (self.children[group.value]) {
+ self.records.proxy(group.value).reset();
+ delete self.children[group.value];
+ }
+ var child = self.children[group.value] = new openerp.web.ListView.Groups(self.view, {
+ records: self.records.proxy(group.value),
+ options: self.options,
+ columns: self.columns
+ });
+ self.bind_child_events(child);
+ child.datagroup = group;
+
+ var $row = child.$row = $('<tr>');
+ if (group.openable) {
+ $row.click(function (e) {
+ if (!$row.data('open')) {
+ $row.data('open', true)
+ .find('span.ui-icon')
+ .removeClass('ui-icon-triangle-1-e')
+ .addClass('ui-icon-triangle-1-s');
+ child.open(self.point_insertion(e.currentTarget));
+ } else {
+ $row.removeData('open')
+ .find('span.ui-icon')
+ .removeClass('ui-icon-triangle-1-s')
+ .addClass('ui-icon-triangle-1-e');
+ child.close();
+ }
+ });
+ }
+ placeholder.appendChild($row[0]);
+
+ var $group_column = $('<th class="oe-group-name">').appendTo($row);
+ // Don't fill this if group_by_no_leaf but no group_by
+ if (group.grouped_on) {
+ var row_data = {};
+ row_data[group.grouped_on] = group;
+ var group_column = _(self.columns).detect(function (column) {
+ return column.id === group.grouped_on; });
+ $group_column.html(openerp.web.format_cell(
+ row_data, group_column, "Undefined"
+ ));
+ if (group.openable) {
+ // Make openable if not terminal group & group_by_no_leaf
+ $group_column
+ .prepend('<span class="ui-icon ui-icon-triangle-1-e" style="float: left;">');
+ }
+ }
+ self.indent($group_column, group.level);
+ // count column
+ $('<td>').text(group.length).appendTo($row);
+
+ if (self.options.selectable) {
+ $row.append('<td>');
+ }
+ _(self.columns).chain()
+ .filter(function (column) {return !column.invisible;})
+ .each(function (column) {
+ if (column.meta) {
+ // do not do anything
+ } else if (column.id in group.aggregates) {
+ var value = group.aggregates[column.id];
+ var format;
+ if (column.type === 'integer') {
+ format = "%.0f";
+ } else if (column.type === 'float') {
+ format = "%.2f";
+ }
+ $('<td>')
+ .text(_.sprintf(format, value))
+ .appendTo($row);
+ } else {
+ $row.append('<td>');
+ }
+ });
+ if (self.options.deletable) {
+ $row.append('<td class="oe-group-pagination">');
+ }
+ });
+ return placeholder;
+ },
+ bind_child_events: function (child) {
+ var $this = $(this),
+ self = this;
+ $(child).bind('selected', function (e) {
+ // can have selections spanning multiple links
+ var selection = self.get_selection();
+ $this.trigger(e, [selection.ids, selection.records]);
+ }).bind(this.passtrough_events, function (e) {
+ // additional positional parameters are provided to trigger as an
+ // Array, following the event type or event object, but are
+ // provided to the .bind event handler as *args.
+ // Convert our *args back into an Array in order to trigger them
+ // on the group itself, so it can ultimately be forwarded wherever
+ // it's supposed to go.
+ var args = Array.prototype.slice.call(arguments, 1);
+ $this.trigger.call($this, e, args);
+ });
+ },
+ render_dataset: function (dataset) {
+ var self = this,
+ list = new openerp.web.ListView.List(this, {
+ options: this.options,
+ columns: this.columns,
+ dataset: dataset,
+ records: this.records
+ });
+ this.bind_child_events(list);
+
+ var view = this.view,
+ limit = view.limit(),
+ d = new $.Deferred(),
+ page = this.datagroup.openable ? this.page : view.page;
+
+ var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
+ var options = { offset: page * limit, limit: limit };
+ dataset.read_slice(fields, options , function (records) {
+ if (!self.datagroup.openable) {
+ view.configure_pager(dataset);
+ } else {
+ var pages = Math.ceil(dataset.ids.length / limit);
+ self.$row
+ .find('.oe-pager-state')
+ .text(_.sprintf('%d/%d', page + 1, pages))
+ .end()
+ .find('button[data-pager-action=previous]')
+ .attr('disabled', page === 0)
+ .end()
+ .find('button[data-pager-action=next]')
+ .attr('disabled', page === pages - 1);
+ }
+
+ self.records.add(records, {silent: true});
+ list.render();
+ d.resolve(list);
+ });
+ return d.promise();
+ },
+ setup_resequence_rows: function (list, dataset) {
+ // drag and drop enabled if list is not sorted and there is a
+ // "sequence" column in the view.
+ if ((dataset.sort && dataset.sort())
+ || !_(this.columns).any(function (column) {
+ return column.name === 'sequence'; })) {
+ return;
+ }
+ // ondrop, move relevant record & fix sequences
+ list.$current.sortable({
+ stop: function (event, ui) {
+ var to_move = list.records.get(ui.item.data('id')),
+ target_id = ui.item.prev().data('id');
+
+ list.records.remove(to_move);
+ var to = target_id ? list.records.indexOf(list.records.get(target_id)) : 0;
+ list.records.add(to_move, { at: to });
+
+ // resequencing time!
+ var record, index = to,
+ // if drag to 1st row (to = 0), start sequencing from 0
+ // (exclusive lower bound)
+ seq = to ? list.records.at(to - 1).get('sequence') : 0;
+ while (++seq, record = list.records.at(index++)) {
+ // write are independent from one another, so we can just
+ // launch them all at the same time and we don't really
+ // give a fig about when they're done
+ dataset.write(record.get('id'), {sequence: seq});
+ record.set('sequence', seq);
+ }
+
+ list.refresh_zebra();
+ }
+ });
+ },
+ render: function (post_render) {
+ var self = this;
+ var $element = $('<tbody>');
+ this.elements = [$element[0]];
+
+ this.datagroup.list(
+ _(this.view.visible_columns).chain()
+ .filter(function (column) { return column.tag === 'field' })
+ .pluck('name').value(),
+ function (groups) {
+ $element[0].appendChild(
+ self.render_groups(groups));
+ if (post_render) { post_render(); }
+ }, function (dataset) {
+ self.render_dataset(dataset).then(function (list) {
+ self.children[null] = list;
+ self.elements =
+ [list.$current.replaceAll($element)[0]];
+ self.setup_resequence_rows(list, dataset);
+ if (post_render) { post_render(); }
+ });
+ });
+ return $element;
+ },
+ /**
+ * Returns the ids of all selected records for this group, and the records
+ * themselves
+ */
+ get_selection: function () {
+ var ids = [], records = [];
+
+ _(this.children)
+ .each(function (child) {
+ var selection = child.get_selection();
+ ids.push.apply(ids, selection.ids);
+ records.push.apply(records, selection.records);
+ });
+
+ return {ids: ids, records: records};
+ },
+ on_records_reset: function () {
+ this.children = {};
+ $(this.elements).remove();
+ },
+ get_records: function () {
+ if (_(this.children).isEmpty()) {
+ return {
+ count: this.datagroup.length,
+ values: this.datagroup.aggregates
+ }
+ }
+ return _(this.children).chain()
+ .map(function (child) {
+ return child.get_records();
+ }).flatten().value();
+ }
+});
+
+/**
+ * @mixin Events
+ */
+var Events = /** @lends Events# */{
+ /**
+ * @param {String} event event to listen to on the current object, null for all events
+ * @param {Function} handler event handler to bind to the relevant event
+ * @returns this
+ */
+ bind: function (event, handler) {
+ var calls = this['_callbacks'] || (this._callbacks = {});
+
+ if (event in calls) {
+ calls[event].push(handler);
+ } else {
+ calls[event] = [handler];
+ }
+ return this;
+ },
+ /**
+ * @param {String} event event to unbind on the current object
+ * @param {function} [handler] specific event handler to remove (otherwise unbind all handlers for the event)
+ * @returns this
+ */
+ unbind: function (event, handler) {
+ var calls = this._callbacks || {};
+ if (!(event in calls)) { return this; }
+ if (!handler) {
+ delete calls[event];
+ } else {
+ var handlers = calls[event];
+ handlers.splice(
+ _(handlers).indexOf(handler),
+ 1);
+ }
+ return this;
+ },
+ /**
+ * @param {String} event
+ * @returns this
+ */
+ trigger: function (event) {
+ var calls;
+ if (!(calls = this._callbacks)) { return this; }
+ var callbacks = (calls[event] || []).concat(calls[null] || []);
+ for(var i=0, length=callbacks.length; i<length; ++i) {
+ callbacks[i].apply(this, arguments);
+ }
+ return this;
+ }
+};
+var Record = openerp.web.Class.extend(/** @lends Record# */{
+ /**
+ * @constructs Record
+ * @extends openerp.web.Class
+ *
+ * @mixes Events
+ * @param {Object} [data]
+ */
+ init: function (data) {
+ this.attributes = data || {};
+ },
+ /**
+ * @param {String} key
+ * @returns {Object}
+ */
+ get: function (key) {
+ return this.attributes[key];
+ },
+ /**
+ * @param key
+ * @param value
+ * @param {Object} [options]
+ * @param {Boolean} [options.silent=false]
+ * @returns {Record}
+ */
+ set: function (key, value, options) {
+ options = options || {};
+ var old_value = this.attributes[key];
+ if (old_value === value) {
+ return this;
+ }
+ this.attributes[key] = value;
+ if (!options.silent) {
+ this.trigger('change:' + key, this, value, old_value);
+ this.trigger('change', this, key, value, old_value);
+ }
+ return this;
+ },
+ /**
+ * Converts the current record to the format expected by form views:
+ *
+ * .. code-block:: javascript
+ *
+ * data: {
+ * $fieldname: {
+ * value: $value
+ * }
+ * }
+ *
+ *
+ * @returns {Object} record displayable in a form view
+ */
+ toForm: function () {
+ var form_data = {};
+ _(this.attributes).each(function (value, key) {
+ form_data[key] = {value: value};
+ });
+
+ return {data: form_data};
+ }
+});
+Record.include(Events);
+var Collection = openerp.web.Class.extend(/** @lends Collection# */{
+ /**
+ * Smarter collections, with events, very strongly inspired by Backbone's.
+ *
+ * Using a "dumb" array of records makes synchronization between the
+ * various serious
+ *
+ * @constructs Collection
+ * @extends openerp.web.Class
+ *
+ * @mixes Events
+ * @param {Array} [records] records to initialize the collection with
+ * @param {Object} [options]
+ */
+ init: function (records, options) {
+ options = options || {};
+ _.bindAll(this, '_onRecordEvent');
+ this.length = 0;
+ this.records = [];
+ this._byId = {};
+ this._proxies = {};
+ this._key = options.key;
+ this._parent = options.parent;
+
+ if (records) {
+ this.add(records);
+ }
+ },
+ /**
+ * @param {Object|Array} record
+ * @param {Object} [options]
+ * @param {Number} [options.at]
+ * @param {Boolean} [options.silent=false]
+ * @returns this
+ */
+ add: function (record, options) {
+ options = options || {};
+ var records = record instanceof Array ? record : [record];
+
+ for(var i=0, length=records.length; i<length; ++i) {
+ var instance = (records[i] instanceof Record) ? records[i] : new Record(records[i]);
+ instance.bind(null, this._onRecordEvent);
+ this._byId[instance.get('id')] = instance;
+ if (options.at == undefined) {
+ this.records.push(instance);
+ if (!options.silent) {
+ this.trigger('add', this, instance, this.records.length-1);
+ }
+ } else {
+ var insertion_index = options.at + i;
+ this.records.splice(insertion_index, 0, instance);
+ if (!options.silent) {
+ this.trigger('add', this, instance, insertion_index);
+ }
+ }
+ this.length++;
+ }
+ return this;
+ },
+
+ /**
+ * Get a record by its index in the collection, can also take a group if
+ * the collection is not degenerate
+ *
+ * @param {Number} index
+ * @param {String} [group]
+ * @returns {Record|undefined}
+ */
+ at: function (index, group) {
+ if (group) {
+ var groups = group.split('.');
+ return this._proxies[groups[0]].at(index, groups.join('.'));
+ }
+ return this.records[index];
+ },
+ /**
+ * Get a record by its database id
+ *
+ * @param {Number} id
+ * @returns {Record|undefined}
+ */
+ get: function (id) {
+ if (!_(this._proxies).isEmpty()) {
+ var record = null;
+ _(this._proxies).detect(function (proxy) {
+ return record = proxy.get(id);
+ });
+ return record;
+ }
+ return this._byId[id];
+ },
+ /**
+ * Builds a proxy (insert/retrieve) to a subtree of the collection, by
+ * the subtree's group
+ *
+ * @param {String} section group path section
+ * @returns {Collection}
+ */
+ proxy: function (section) {
+ return this._proxies[section] = new Collection(null, {
+ parent: this,
+ key: section
+ }).bind(null, this._onRecordEvent);
+ },
+ /**
+ * @param {Array} [records]
+ * @returns this
+ */
+ reset: function (records) {
+ _(this._proxies).each(function (proxy) {
+ proxy.reset();
+ });
+ this._proxies = {};
+ this.length = 0;
+ this.records = [];
+ this._byId = {};
+ if (records) {
+ this.add(records);
+ }
+ this.trigger('reset', this);
+ return this;
+ },
+ /**
+ * Removes the provided record from the collection
+ *
+ * @param {Record} record
+ * @returns this
+ */
+ remove: function (record) {
+ var self = this;
+ var index = _(this.records).indexOf(record);
+ if (index === -1) {
+ _(this._proxies).each(function (proxy) {
+ proxy.remove(record);
+ });
+ return this;
+ }
+
+ this.records.splice(index, 1);
+ delete this._byId[record.get('id')];
+ this.length--;
+ this.trigger('remove', record, this);
+ return this;
+ },
+
+ _onRecordEvent: function (event, record, options) {
+ // don't propagate reset events
+ if (event === 'reset') { return; }
+ this.trigger.apply(this, arguments);
+ },
+
+ // underscore-type methods
+ each: function (callback) {
+ for(var section in this._proxies) {
+ if (this._proxies.hasOwnProperty(section)) {
+ this._proxies[section].each(callback);
+ }
+ }
+ for(var i=0; i<this.length; ++i) {
+ callback(this.records[i]);
+ }
+ },
+ map: function (callback) {
+ var results = [];
+ this.each(function (record) {
+ results.push(callback(record));
+ });
+ return results;
+ },
+ pluck: function (fieldname) {
+ return this.map(function (record) {
+ return record.get(fieldname);
+ });
+ },
+ indexOf: function (record) {
+ return _(this.records).indexOf(record);
+ }
+});
+Collection.include(Events);
+openerp.web.list = {
+ Events: Events,
+ Record: Record,
+ Collection: Collection
+}
+};
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
new file mode 100644
index 00000000000..f6c53b4ad17
--- /dev/null
+++ b/addons/web/static/src/js/search.js
@@ -0,0 +1,1220 @@
+openerp.web.search = function(openerp) {
+var QWeb = openerp.web.qweb;
+
+openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.SearchView# */{
+ /**
+ * @constructs openerp.web.SearchView
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ * @param dataset
+ * @param view_id
+ * @param defaults
+ */
+ init: function(parent, element_id, dataset, view_id, defaults) {
+ this._super(parent, element_id);
+ this.dataset = dataset;
+ this.model = dataset.model;
+ this.view_id = view_id;
+
+ this.defaults = defaults || {};
+
+ this.inputs = [];
+ this.enabled_filters = [];
+
+ this.has_focus = false;
+
+ this.ready = $.Deferred();
+ },
+ start: function() {
+ this.rpc("/web/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
+ return this.ready.promise();
+ },
+ show: function () {
+ this.$element.show();
+ },
+ hide: function () {
+ this.$element.hide();
+ },
+ /**
+ * Builds a list of widget rows (each row is an array of widgets)
+ *
+ * @param {Array} items a list of nodes to convert to widgets
+ * @param {Object} fields a mapping of field names to (ORM) field attributes
+ * @returns Array
+ */
+ make_widgets: function (items, fields) {
+ var rows = [],
+ row = [];
+ rows.push(row);
+ var filters = [];
+ _.each(items, function (item) {
+ if (filters.length && item.tag !== 'filter') {
+ row.push(
+ new openerp.web.search.FilterGroup(
+ filters, this));
+ filters = [];
+ }
+
+ if (item.tag === 'newline') {
+ row = [];
+ rows.push(row);
+ } else if (item.tag === 'filter') {
+ if (!this.has_focus) {
+ item.attrs.default_focus = '1';
+ this.has_focus = true;
+ }
+ filters.push(
+ new openerp.web.search.Filter(
+ item, this));
+ } else if (item.tag === 'separator') {
+ // a separator is a no-op
+ } else {
+ if (item.tag === 'group') {
+ // TODO: group and field should be fetched from registries, maybe even filters
+ row.push(
+ new openerp.web.search.Group(
+ item, this, fields));
+ } else if (item.tag === 'field') {
+ if (!this.has_focus) {
+ item.attrs.default_focus = '1';
+ this.has_focus = true;
+ }
+ row.push(
+ this.make_field(
+ item, fields[item['attrs'].name]));
+ }
+ }
+ }, this);
+ if (filters.length) {
+ row.push(new openerp.web.search.FilterGroup(filters, this));
+ }
+
+ return rows;
+ },
+ /**
+ * Creates a field for the provided field descriptor item (which comes
+ * from fields_view_get)
+ *
+ * @param {Object} item fields_view_get node for the field
+ * @param {Object} field fields_get result for the field
+ * @returns openerp.web.search.Field
+ */
+ make_field: function (item, field) {
+ try {
+ return new (openerp.web.search.fields.get_object(field.type))
+ (item, field, this);
+ } catch (e) {
+ if (! e instanceof openerp.web.KeyNotFound) {
+ throw e;
+ }
+ // KeyNotFound means unknown field type
+ console.group('Unknown field type ' + field.type);
+ console.error('View node', item);
+ console.info('View field', field);
+ console.info('In view', this);
+ console.groupEnd();
+ return null;
+ }
+ },
+ on_loaded: function(data) {
+ var self = this,
+ lines = this.make_widgets(
+ data.fields_view['arch'].children,
+ data.fields_view.fields);
+
+ // for extended search view
+ var ext = new openerp.web.search.ExtendedSearch(this, this.model);
+ lines.push([ext]);
+ this.inputs.push(ext);
+
+ var render = QWeb.render("SearchView", {
+ 'view': data.fields_view['arch'],
+ 'lines': lines,
+ 'defaults': this.defaults
+ });
+
+ // We don't understand why the following commented line does not work in Chrome but
+ // the non-commented line does. As far as we investigated, only God knows.
+ //this.$element.html(render);
+ jQuery(render).appendTo(this.$element);
+ this.$element.find(".oe_search-view-custom-filter-btn").click(ext.on_activate);
+
+ var f = this.$element.find('form');
+ this.$element.find('form')
+ .submit(this.do_search)
+ .bind('reset', this.do_clear);
+ // start() all the widgets
+ var widget_starts = _(lines).chain().flatten().map(function (widget) {
+ return widget.start();
+ }).value();
+
+ $.when.apply(null, widget_starts).then(function () {
+ self.ready.resolve();
+ });
+
+ this.reload_managed_filters();
+ },
+ reload_managed_filters: function() {
+ var self = this;
+ return this.rpc('/web/searchview/get_filters', {
+ model: this.dataset.model
+ }).then(function(result) {
+ self.managed_filters = result;
+ var filters = self.$element.find(".oe_search-view-filters-management");
+ filters.html(QWeb.render("SearchView.managed-filters", {filters: result}));
+ filters.change(self.on_filters_management);
+ });
+ },
+ /**
+ * Handle event when the user make a selection in the filters management select box.
+ */
+ on_filters_management: function(e) {
+ var self = this;
+ var select = this.$element.find(".oe_search-view-filters-management");
+ var val = select.val();
+
+ if (val.slice(0,1) == "_") { // useless action
+ select.val("_filters");
+ return;
+ }
+ if (val.slice(0, "get:".length) == "get:") {
+ val = val.slice("get:".length);
+ val = parseInt(val);
+ var filter = this.managed_filters[val];
+ this.on_search([filter.domain], [filter.context], []);
+ } else if (val == "save_filter") {
+ select.val("_filters");
+ var data = this.build_search_data();
+ var context = new openerp.web.CompoundContext();
+ _.each(data.contexts, function(x) {
+ context.add(x);
+ });
+ var domain = new openerp.web.CompoundDomain();
+ _.each(data.domains, function(x) {
+ domain.add(x);
+ });
+ var dial_html = QWeb.render("SearchView.managed-filters.add");
+ var $dial = $(dial_html);
+ $dial.dialog({
+ modal: true,
+ title: "Filter Entry",
+ buttons: {
+ Cancel: function() {
+ $(this).dialog("close");
+ },
+ OK: function() {
+ $(this).dialog("close");
+ var name = $(this).find("input").val();
+ self.rpc('/web/searchview/save_filter', {
+ model: self.dataset.model,
+ context_to_save: context,
+ domain: domain,
+ name: name
+ }).then(function() {
+ self.reload_managed_filters();
+ });
+ }
+ }
+ });
+ } else { // manage_filters
+ select.val("_filters");
+ this.do_action({
+ res_model: 'ir.filters',
+ views: [[false, 'list'], [false, 'form']],
+ type: 'ir.actions.act_window',
+ context: {"search_default_user_id": this.session.uid,
+ "search_default_model_id": this.dataset.model},
+ target: "current",
+ limit : 80,
+ auto_search : true
+ });
+ }
+ },
+ /**
+ * Performs the search view collection of widget data.
+ *
+ * If the collection went well (all fields are valid), then triggers
+ * :js:func:`openerp.web.SearchView.on_search`.
+ *
+ * If at least one field failed its validation, triggers
+ * :js:func:`openerp.web.SearchView.on_invalid` instead.
+ *
+ * @param e jQuery event object coming from the "Search" button
+ */
+ do_search: function (e) {
+ // reset filters management
+ var select = this.$element.find(".oe_search-view-filters-management");
+ select.val("_filters");
+
+ if (e && e.preventDefault) { e.preventDefault(); }
+
+ var data = this.build_search_data();
+
+ if (data.errors.length) {
+ this.on_invalid(data.errors);
+ return;
+ }
+
+ this.on_search(data.domains, data.contexts, data.groupbys);
+ },
+ build_search_data: function() {
+ var domains = [],
+ contexts = [],
+ errors = [];
+
+ _.each(this.inputs, function (input) {
+ try {
+ var domain = input.get_domain();
+ if (domain) {
+ domains.push(domain);
+ }
+
+ var context = input.get_context();
+ if (context) {
+ contexts.push(context);
+ }
+ } catch (e) {
+ if (e instanceof openerp.web.search.Invalid) {
+ errors.push(e);
+ } else {
+ throw e;
+ }
+ }
+ });
+
+ // TODO: do we need to handle *fields* with group_by in their context?
+ var groupbys = _(this.enabled_filters)
+ .chain()
+ .map(function (filter) { return filter.get_context();})
+ .compact()
+ .value();
+ return {domains: domains, contexts: contexts, errors: errors, groupbys: groupbys};
+ },
+ /**
+ * Triggered after the SearchView has collected all relevant domains and
+ * contexts.
+ *
+ * It is provided with an Array of domains and an Array of contexts, which
+ * may or may not be evaluated (each item can be either a valid domain or
+ * context, or a string to evaluate in order in the sequence)
+ *
+ * It is also passed an array of contexts used for group_by (they are in
+ * the correct order for group_by evaluation, which contexts may not be)
+ *
+ * @event
+ * @param {Array} domains an array of literal domains or domain references
+ * @param {Array} contexts an array of literal contexts or context refs
+ * @param {Array} groupbys ordered contexts which may or may not have group_by keys
+ */
+ on_search: function (domains, contexts, groupbys) {
+ },
+ /**
+ * Triggered after a validation error in the SearchView fields.
+ *
+ * Error objects have three keys:
+ * * ``field`` is the name of the invalid field
+ * * ``value`` is the invalid value
+ * * ``message`` is the (in)validation message provided by the field
+ *
+ * @event
+ * @param {Array} errors a never-empty array of error objects
+ */
+ on_invalid: function (errors) {
+ this.notification.notify("Invalid Search", "triggered from search view");
+ },
+ do_clear: function () {
+ $('.filter_label').removeClass('enabled');
+ var string = $('a.searchview_group_string');
+ _.each(string, function(str){
+ $(str).closest('div.searchview_group').removeClass("expanded").addClass('folded');
+ });
+ this.$element.find('table:last').hide();
+
+ $('.searchview_extended_groups_list').empty();
+ setTimeout(this.on_clear);
+ },
+ /**
+ * Triggered when the search view gets cleared
+ *
+ * @event
+ */
+ on_clear: function () {
+ this.do_search();
+ },
+ /**
+ * Called by a filter propagating its state changes
+ *
+ * @param {openerp.web.search.Filter} filter a filter which got toggled
+ * @param {Boolean} default_enabled filter got enabled through the default values, at render time.
+ */
+ do_toggle_filter: function (filter, default_enabled) {
+ if (default_enabled || filter.is_enabled()) {
+ this.enabled_filters.push(filter);
+ } else {
+ this.enabled_filters = _.without(
+ this.enabled_filters, filter);
+ }
+
+ if (!default_enabled) {
+ // selecting a filter after initial loading automatically
+ // triggers refresh
+ this.$element.find('form').submit();
+ }
+ }
+});
+
+/** @namespace */
+openerp.web.search = {};
+/**
+ * Registry of search fields, called by :js:class:`openerp.web.SearchView` to
+ * find and instantiate its field widgets.
+ */
+openerp.web.search.fields = new openerp.web.Registry({
+ 'char': 'openerp.web.search.CharField',
+ 'text': 'openerp.web.search.CharField',
+ 'boolean': 'openerp.web.search.BooleanField',
+ 'integer': 'openerp.web.search.IntegerField',
+ 'float': 'openerp.web.search.FloatField',
+ 'selection': 'openerp.web.search.SelectionField',
+ 'datetime': 'openerp.web.search.DateTimeField',
+ 'date': 'openerp.web.search.DateField',
+ 'many2one': 'openerp.web.search.ManyToOneField',
+ 'many2many': 'openerp.web.search.CharField',
+ 'one2many': 'openerp.web.search.CharField'
+});
+openerp.web.search.Invalid = openerp.web.Class.extend( /** @lends openerp.web.search.Invalid# */{
+ /**
+ * Exception thrown by search widgets when they hold invalid values,
+ * which they can not return when asked.
+ *
+ * @constructs openerp.web.search.Invalid
+ * @extends openerp.web.Class
+ *
+ * @param field the name of the field holding an invalid value
+ * @param value the invalid value
+ * @param message validation failure message
+ */
+ init: function (field, value, message) {
+ this.field = field;
+ this.value = value;
+ this.message = message;
+ },
+ toString: function () {
+ return ('Incorrect value for field ' + this.field +
+ ': [' + this.value + '] is ' + this.message);
+ }
+});
+openerp.web.search.Widget = openerp.web.Widget.extend( /** @lends openerp.web.search.Widget# */{
+ template: null,
+ /**
+ * Root class of all search widgets
+ *
+ * @constructs openerp.web.search.Widget
+ * @extends openerp.web.Widget
+ *
+ * @param view the ancestor view of this widget
+ */
+ init: function (view) {
+ this.view = view;
+ },
+ /**
+ * Sets and returns a globally unique identifier for the widget.
+ *
+ * If a prefix is specified, the identifier will be appended to it.
+ *
+ * @params prefix prefix sections, empty/falsy sections will be removed
+ */
+ make_id: function () {
+ this.element_id = _.uniqueId(
+ ['search'].concat(
+ _.compact(_.toArray(arguments)),
+ ['']).join('_'));
+ return this.element_id;
+ },
+ /**
+ * "Starts" the widgets. Called at the end of the rendering, this allows
+ * widgets to hook themselves to their view sections.
+ *
+ * On widgets, if they kept a reference to a view and have an element_id,
+ * will fetch and set their root element on $element.
+ */
+ start: function () {
+ this._super();
+ if (this.view && this.element_id) {
+ // id is unique, and no getElementById on elements
+ this.$element = $(document.getElementById(
+ this.element_id));
+ }
+ },
+ /**
+ * "Stops" the widgets. Called when the view destroys itself, this
+ * lets the widgets clean up after themselves.
+ */
+ stop: function () {
+ delete this.view;
+ this._super();
+ },
+ render: function (defaults) {
+ return QWeb.render(
+ this.template, _.extend(this, {
+ defaults: defaults
+ }));
+ }
+});
+openerp.web.search.FilterGroup = openerp.web.search.Widget.extend(/** @lends openerp.web.search.FilterGroup# */{
+ template: 'SearchView.filters',
+ /**
+ * Inclusive group of filters, creates a continuous "button" with clickable
+ * sections (the normal display for filters is to be a self-contained button)
+ *
+ * @constructs openerp.web.search.FilterGroup
+ * @extends openerp.web.search.Widget
+ *
+ * @param {Array<openerp.web.search.Filter>} filters elements of the group
+ * @param {openerp.web.SearchView} view view in which the filters are contained
+ */
+ init: function (filters, view) {
+ this._super(view);
+ this.filters = filters;
+ this.length = filters.length;
+ },
+ start: function () {
+ this._super();
+ _.each(this.filters, function (filter) {
+ filter.start();
+ });
+ }
+});
+openerp.web.search.add_expand_listener = function($root) {
+ $root.find('a.searchview_group_string').click(function (e) {
+ $root.toggleClass('folded expanded');
+ e.stopPropagation();
+ e.preventDefault();
+ });
+};
+openerp.web.search.Group = openerp.web.search.Widget.extend({
+ template: 'SearchView.group',
+ init: function (view_section, view, fields) {
+ this._super(view);
+ this.attrs = view_section.attrs;
+ this.lines = view.make_widgets(
+ view_section.children, fields);
+ this.make_id('group');
+ },
+ start: function () {
+ this._super();
+ openerp.web.search.add_expand_listener(this.$element);
+ var widget_starts = _(this.lines).chain().flatten()
+ .map(function (widget) { return widget.start(); })
+ .value();
+ return $.when.apply(null, widget_starts);
+ }
+});
+
+openerp.web.search.Input = openerp.web.search.Widget.extend( /** @lends openerp.web.search.Input# */{
+ /**
+ * @constructs openerp.web.search.Input
+ * @extends openerp.web.search.Widget
+ *
+ * @param view
+ */
+ init: function (view) {
+ this._super(view);
+ this.view.inputs.push(this);
+ },
+ get_context: function () {
+ throw new Error(
+ "get_context not implemented for widget " + this.attrs.type);
+ },
+ get_domain: function () {
+ throw new Error(
+ "get_domain not implemented for widget " + this.attrs.type);
+ }
+});
+openerp.web.search.Filter = openerp.web.search.Input.extend(/** @lends openerp.web.search.Filter# */{
+ template: 'SearchView.filter',
+ /**
+ * Implementation of the OpenERP filters (button with a context and/or
+ * a domain sent as-is to the search view)
+ *
+ * @constructs openerp.web.search.Filter
+ * @extends openerp.web.search.Input
+ *
+ * @param node
+ * @param view
+ */
+ init: function (node, view) {
+ this._super(view);
+ this.attrs = node.attrs;
+ this.classes = [this.attrs.string ? 'filter_label' : 'filter_icon'];
+ this.make_id('filter', this.attrs.name);
+ },
+ start: function () {
+ this._super();
+ var self = this;
+ this.$element.click(function (e) {
+ $(this).toggleClass('enabled');
+ self.view.do_toggle_filter(self);
+ });
+ },
+ /**
+ * Returns whether the filter is currently enabled (in use) or not.
+ *
+ * @returns a boolean
+ */
+ is_enabled:function () {
+ return this.$element.hasClass('enabled');
+ },
+ /**
+ * If the filter is present in the defaults (and has a truthy value),
+ * enable the filter.
+ *
+ * @param {Object} defaults the search view's default values
+ */
+ render: function (defaults) {
+ if (this.attrs.name && defaults[this.attrs.name]) {
+ this.classes.push('enabled');
+ this.view.do_toggle_filter(this, true);
+ }
+ return this._super(defaults);
+ },
+ get_context: function () {
+ if (!this.is_enabled()) {
+ return;
+ }
+ return this.attrs.context;
+ },
+ get_domain: function () {
+ if (!this.is_enabled()) {
+ return;
+ }
+ return this.attrs.domain;
+ }
+});
+openerp.web.search.Field = openerp.web.search.Input.extend( /** @lends openerp.web.search.Field# */ {
+ template: 'SearchView.field',
+ default_operator: '=',
+ /**
+ * @constructs openerp.web.search.Field
+ * @extends openerp.web.search.Input
+ *
+ * @param view_section
+ * @param field
+ * @param view
+ */
+ init: function (view_section, field, view) {
+ this._super(view);
+ this.attrs = _.extend({}, field, view_section.attrs);
+ this.filters = new openerp.web.search.FilterGroup(_.map(
+ view_section.children, function (filter_node) {
+ return new openerp.web.search.Filter(
+ filter_node, view);
+ }), view);
+ this.make_id('input', field.type, this.attrs.name);
+ },
+ start: function () {
+ this._super();
+ this.filters.start();
+ },
+ get_context: function () {
+ var val = this.get_value();
+ // A field needs a value to be "active", and a context to send when
+ // active
+ var has_value = (val !== null && val !== '');
+ var context = this.attrs.context;
+ if (!(has_value && context)) {
+ return;
+ }
+ return _.extend(
+ {}, context,
+ {own_values: {self: val}});
+ },
+ /**
+ * Function creating the returned domain for the field, override this
+ * methods in children if you only need to customize the field's domain
+ * without more complex alterations or tests (and without the need to
+ * change override the handling of filter_domain)
+ *
+ * @param {String} name the field's name
+ * @param {String} operator the field's operator (either attribute-specified or default operator for the field
+ * @param {Number|String} value parsed value for the field
+ * @returns {Array<Array>} domain to include in the resulting search
+ */
+ make_domain: function (name, operator, value) {
+ return [[name, operator, value]];
+ },
+ get_domain: function () {
+ var val = this.get_value();
+ if (val === null || val === '') {
+ return;
+ }
+
+ var domain = this.attrs['filter_domain'];
+ if (!domain) {
+ return this.make_domain(
+ this.attrs.name,
+ this.attrs.operator || this.default_operator,
+ val);
+ }
+ return _.extend({}, domain, {own_values: {self: val}});
+ }
+});
+/**
+ * Implementation of the ``char`` OpenERP field type:
+ *
+ * * Default operator is ``ilike`` rather than ``=``
+ *
+ * * The Javascript and the HTML values are identical (strings)
+ *
+ * @class
+ * @extends openerp.web.search.Field
+ */
+openerp.web.search.CharField = openerp.web.search.Field.extend( /** @lends openerp.web.search.CharField# */ {
+ default_operator: 'ilike',
+ get_value: function () {
+ return this.$element.val();
+ }
+});
+openerp.web.search.NumberField = openerp.web.search.Field.extend(/** @lends openerp.web.search.NumberField# */{
+ get_value: function () {
+ if (!this.$element.val()) {
+ return null;
+ }
+ var val = this.parse(this.$element.val()),
+ check = Number(this.$element.val());
+ if (isNaN(val) || val !== check) {
+ this.$element.addClass('error');
+ throw new openerp.web.search.Invalid(
+ this.attrs.name, this.$element.val(), this.error_message);
+ }
+ this.$element.removeClass('error');
+ return val;
+ }
+});
+/**
+ * @class
+ * @extends openerp.web.search.NumberField
+ */
+openerp.web.search.IntegerField = openerp.web.search.NumberField.extend(/** @lends openerp.web.search.IntegerField# */{
+ error_message: "not a valid integer",
+ parse: function (value) {
+ return parseInt(value, 10);
+ }
+});
+/**
+ * @class
+ * @extends openerp.web.search.NumberField
+ */
+openerp.web.search.FloatField = openerp.web.search.NumberField.extend(/** @lends openerp.web.search.FloatField# */{
+ error_message: "not a valid number",
+ parse: function (value) {
+ return parseFloat(value);
+ }
+});
+/**
+ * @class
+ * @extends openerp.web.search.Field
+ */
+openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends openerp.web.search.SelectionField# */{
+ template: 'SearchView.field.selection',
+ get_value: function () {
+ return this.$element.val();
+ }
+});
+openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @lends openerp.web.search.BooleanField# */{
+ /**
+ * @constructs openerp.web.search.BooleanField
+ * @extends openerp.web.search.BooleanField
+ */
+ init: function () {
+ this._super.apply(this, arguments);
+ this.attrs.selection = [
+ ['true', 'Yes'],
+ ['false', 'No']
+ ];
+ },
+ /**
+ * Search defaults likely to be boolean values (for a boolean field).
+ *
+ * In the HTML, we only want/get strings, and our strings here are ``true``
+ * and ``false``, so ensure we use precisely those by truth-testing the
+ * default value (iif there is one in the view's defaults).
+ *
+ * @param {Object} defaults default values for this search view
+ * @returns {String} rendered boolean field
+ */
+ render: function (defaults) {
+ var name = this.attrs.name;
+ if (name in defaults) {
+ defaults[name] = defaults[name] ? "true" : "false";
+ }
+ return this._super(defaults);
+ },
+ get_value: function () {
+ switch (this.$element.val()) {
+ case 'false': return false;
+ case 'true': return true;
+ default: return null;
+ }
+ }
+});
+/**
+ * @class
+ * @extends openerp.web.search.DateField
+ */
+openerp.web.search.DateField = openerp.web.search.Field.extend(/** @lends openerp.web.search.DateField# */{
+ /**
+ * enables date picker on the HTML widgets
+ */
+ start: function () {
+ this._super();
+ this.$element.addClass('field_date').datepicker({
+ dateFormat: 'yy-mm-dd'
+ });
+ },
+ stop: function () {
+ this.$element.datepicker('destroy');
+ },
+ get_value: function () {
+ return this.$element.val();
+ }
+});
+/**
+ * Implementation of the ``datetime`` openerp field type:
+ *
+ * * Uses the same widget as the ``date`` field type (a simple date)
+ *
+ * * Builds a slighly more complex, it's a datetime range (includes time)
+ * spanning the whole day selected by the date widget
+ *
+ * @class
+ * @extends openerp.web.DateField
+ */
+openerp.web.search.DateTimeField = openerp.web.search.DateField.extend(/** @lends openerp.web.search.DateTimeField# */{
+ make_domain: function (name, operator, value) {
+ return ['&', [name, '>=', value + ' 00:00:00'],
+ [name, '<=', value + ' 23:59:59']];
+ }
+});
+openerp.web.search.ManyToOneField = openerp.web.search.CharField.extend({
+ init: function (view_section, field, view) {
+ this._super(view_section, field, view);
+ var self = this;
+ this.got_name = $.Deferred().then(function () {
+ self.$element.val(self.name);
+ });
+ this.dataset = new openerp.web.DataSet(
+ this.view, this.attrs['relation']);
+ },
+ start: function () {
+ this._super();
+ this.setup_autocomplete();
+ var started = $.Deferred();
+ this.got_name.then(function () { started.resolve();},
+ function () { started.resolve(); });
+ return started.promise();
+ },
+ setup_autocomplete: function () {
+ var self = this;
+ this.$element.autocomplete({
+ source: function (req, resp) {
+ self.dataset.name_search(
+ req.term, self.attrs.domain, 'ilike', 8, function (data) {
+ resp(_.map(data, function (result) {
+ return {id: result[0], label: result[1]}
+ }));
+ });
+ },
+ select: function (event, ui) {
+ self.id = ui.item.id;
+ self.name = ui.item.label;
+ },
+ delay: 0
+ })
+ },
+ on_name_get: function (name_get) {
+ if (!name_get.length) {
+ delete this.id;
+ this.got_name.reject();
+ return;
+ }
+ this.name = name_get[0][1];
+ this.got_name.resolve();
+ },
+ render: function (defaults) {
+ if (defaults[this.attrs.name]) {
+ this.id = defaults[this.attrs.name];
+ if (this.id instanceof Array)
+ this.id = this.id[0];
+ // TODO: maybe this should not be completely removed
+ delete defaults[this.attrs.name];
+ this.dataset.name_get([this.id], $.proxy(this, 'on_name_get'));
+ } else {
+ this.got_name.reject();
+ }
+ return this._super(defaults);
+ },
+ make_domain: function (name, operator, value) {
+ if (this.id && this.name) {
+ if (value === this.name) {
+ return [[name, '=', this.id]];
+ } else {
+ delete this.id;
+ delete this.name;
+ }
+ }
+ return this._super(name, operator, value);
+ }
+});
+
+openerp.web.search.ExtendedSearch = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search',
+ identifier_prefix: 'extended-search',
+ init: function (parent, model) {
+ this._super(parent);
+ this.model = model;
+ },
+ add_group: function() {
+ var group = new openerp.web.search.ExtendedSearchGroup(this, this.fields);
+ group.appendTo(this.$element.find('.searchview_extended_groups_list'));
+ this.check_last_element();
+ },
+ start: function () {
+ this._super();
+ if (!this.$element) {
+ return; // not a logical state but sometimes it happens
+ }
+ this.$element.closest("table.oe-searchview-render-line").css("display", "none");
+ var self = this;
+ this.rpc("/web/searchview/fields_get",
+ {"model": this.model}, function(data) {
+ self.fields = data.fields;
+ openerp.web.search.add_expand_listener(self.$element);
+ self.$element.find('.searchview_extended_add_group').click(function (e) {
+ self.add_group();
+ });
+ });
+ },
+ get_context: function() {
+ return null;
+ },
+ get_domain: function() {
+ if (!this.$element) {
+ return null; // not a logical state but sometimes it happens
+ }
+ if(this.$element.closest("table.oe-searchview-render-line").css("display") == "none") {
+ return null;
+ }
+ return _.reduce(this.widget_children,
+ function(mem, x) { return mem.concat(x.get_domain());}, []);
+ },
+ on_activate: function() {
+ this.add_group();
+ var table = this.$element.closest("table.oe-searchview-render-line");
+ table.css("display", "");
+ if(this.$element.hasClass("folded")) {
+ this.$element.toggleClass("folded expanded");
+ }
+ },
+ hide: function() {
+ var table = this.$element.closest("table.oe-searchview-render-line");
+ table.css("display", "none");
+ if(this.$element.hasClass("expanded")) {
+ this.$element.toggleClass("folded expanded");
+ }
+ },
+ check_last_element: function() {
+ _.each(this.widget_children, function(x) {x.set_last_group(false);});
+ if (this.widget_children.length >= 1) {
+ this.widget_children[this.widget_children.length - 1].set_last_group(true);
+ }
+ }
+});
+
+openerp.web.search.ExtendedSearchGroup = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.group',
+ identifier_prefix: 'extended-search-group',
+ init: function (parent, fields) {
+ this._super(parent);
+ this.fields = fields;
+ },
+ add_prop: function() {
+ var prop = new openerp.web.search.ExtendedSearchProposition(this, this.fields);
+ var render = prop.render({'index': this.widget_children.length - 1});
+ this.$element.find('.searchview_extended_propositions_list').append(render);
+ prop.start();
+ },
+ start: function () {
+ this._super();
+ var _this = this;
+ this.add_prop();
+ this.$element.find('.searchview_extended_add_proposition').click(function () {
+ _this.add_prop();
+ });
+ this.$element.find('.searchview_extended_delete_group').click(function () {
+ _this.stop();
+ });
+ },
+ get_domain: function() {
+ var props = _(this.widget_children).chain().map(function(x) {
+ return x.get_proposition();
+ }).compact().value();
+ var choice = this.$element.find(".searchview_extended_group_choice").val();
+ var op = choice == "all" ? "&" : "|";
+ return choice == "none" ? ['!'] : [].concat(
+ _.map(_.range(_.max([0,props.length - 1])), function() { return op; }),
+ props);
+ },
+ stop: function() {
+ var parent = this.widget_parent;
+ if (this.widget_parent.widget_children.length == 1)
+ this.widget_parent.hide();
+ this._super();
+ parent.check_last_element();
+ },
+ set_last_group: function(is_last) {
+ this.$element.toggleClass('last_group', is_last);
+ }
+});
+
+openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend(/** @lends openerp.web.search.ExtendedSearchProposition# */{
+ template: 'SearchView.extended_search.proposition',
+ identifier_prefix: 'extended-search-proposition',
+ /**
+ * @constructs openerp.web.search.ExtendedSearchProposition
+ * @extends openerp.web.OldWidget
+ *
+ * @param parent
+ * @param fields
+ */
+ init: function (parent, fields) {
+ this._super(parent);
+ this.fields = _(fields).chain()
+ .map(function(val, key) { return _.extend({}, val, {'name': key}); })
+ .sortBy(function(field) {return field.string;})
+ .value();
+ this.attrs = {_: _, fields: this.fields, selected: null};
+ this.value = null;
+ },
+ start: function () {
+ this._super();
+ this.select_field(this.fields.length > 0 ? this.fields[0] : null);
+ var _this = this;
+ this.$element.find(".searchview_extended_prop_field").change(function() {
+ _this.changed();
+ });
+ this.$element.find('.searchview_extended_delete_prop').click(function () {
+ _this.stop();
+ });
+ },
+ stop: function() {
+ var parent;
+ if (this.widget_parent.widget_children.length == 1)
+ parent = this.widget_parent;
+ this._super();
+ if (parent)
+ parent.stop();
+ },
+ changed: function() {
+ var nval = this.$element.find(".searchview_extended_prop_field").val();
+ if(this.attrs.selected == null || nval != this.attrs.selected.name) {
+ this.select_field(_.detect(this.fields, function(x) {return x.name == nval;}));
+ }
+ },
+ /**
+ * Selects the provided field object
+ *
+ * @param field a field descriptor object (as returned by fields_get, augmented by the field name)
+ */
+ select_field: function(field) {
+ var _this = this;
+ if(this.attrs.selected != null) {
+ this.value.stop();
+ this.value = null;
+ this.$element.find('.searchview_extended_prop_op').html('');
+ }
+ this.attrs.selected = field;
+ if(field == null) {
+ return;
+ }
+
+ var type = field.type;
+ try {
+ openerp.web.search.custom_filters.get_object(type);
+ } catch (e) {
+ if (! e instanceof openerp.web.KeyNotFound) {
+ throw e;
+ }
+ type = "char";
+ console.log('Unknow field type ' + e.key);
+ }
+ this.value = new (openerp.web.search.custom_filters.get_object(type))
+ (this);
+ if(this.value.set_field) {
+ this.value.set_field(field);
+ }
+ _.each(this.value.operators, function(operator) {
+ var option = jQuery('<option>', {value: operator.value})
+ .text(operator.text)
+ .appendTo(_this.$element.find('.searchview_extended_prop_op'));
+ });
+ this.$element.find('.searchview_extended_prop_value').html(
+ this.value.render({}));
+ this.value.start();
+
+ },
+ get_proposition: function() {
+ if ( this.attrs.selected == null)
+ return null;
+ var field = this.attrs.selected.name;
+ var op = this.$element.find('.searchview_extended_prop_op').val();
+ var value = this.value.get_value();
+ return [field, op, value];
+ }
+});
+
+openerp.web.search.ExtendedSearchProposition.Char = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.char',
+ identifier_prefix: 'extended-search-proposition-char',
+ operators: [
+ {value: "ilike", text: "contains"},
+ {value: "not ilike", text: "doesn't contain"},
+ {value: "=", text: "is equal to"},
+ {value: "!=", text: "is not equal to"},
+ {value: ">", text: "greater than"},
+ {value: "<", text: "less than"},
+ {value: ">=", text: "greater or equal than"},
+ {value: "<=", text: "less or equal than"}
+ ],
+ get_value: function() {
+ return this.$element.val();
+ }
+});
+openerp.web.search.ExtendedSearchProposition.DateTime = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.datetime',
+ identifier_prefix: 'extended-search-proposition-datetime',
+ operators: [
+ {value: "=", text: "is equal to"},
+ {value: "!=", text: "is not equal to"},
+ {value: ">", text: "greater than"},
+ {value: "<", text: "less than"},
+ {value: ">=", text: "greater or equal than"},
+ {value: "<=", text: "less or equal than"}
+ ],
+ get_value: function() {
+ return this.$element.val();
+ },
+ start: function() {
+ this._super();
+ this.$element.datetimepicker({
+ dateFormat: 'yy-mm-dd',
+ timeFormat: 'hh:mm:ss'
+ });
+ }
+});
+openerp.web.search.ExtendedSearchProposition.Date = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.date',
+ identifier_prefix: 'extended-search-proposition-date',
+ operators: [
+ {value: "=", text: "is equal to"},
+ {value: "!=", text: "is not equal to"},
+ {value: ">", text: "greater than"},
+ {value: "<", text: "less than"},
+ {value: ">=", text: "greater or equal than"},
+ {value: "<=", text: "less or equal than"}
+ ],
+ get_value: function() {
+ return this.$element.val();
+ },
+ start: function() {
+ this._super();
+ this.$element.datepicker({
+ dateFormat: 'yy-mm-dd',
+ timeFormat: 'hh:mm:ss'
+ });
+ }
+});
+openerp.web.search.ExtendedSearchProposition.Integer = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.integer',
+ identifier_prefix: 'extended-search-proposition-integer',
+ operators: [
+ {value: "=", text: "is equal to"},
+ {value: "!=", text: "is not equal to"},
+ {value: ">", text: "greater than"},
+ {value: "<", text: "less than"},
+ {value: ">=", text: "greater or equal than"},
+ {value: "<=", text: "less or equal than"}
+ ],
+ get_value: function() {
+ var value = parseFloat(this.$element.val());
+ if(value != 0 && !value) {
+ return "";
+ }
+ return Math.round(value);
+ }
+});
+openerp.web.search.ExtendedSearchProposition.Float = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.float',
+ identifier_prefix: 'extended-search-proposition-float',
+ operators: [
+ {value: "=", text: "is equal to"},
+ {value: "!=", text: "is not equal to"},
+ {value: ">", text: "greater than"},
+ {value: "<", text: "less than"},
+ {value: ">=", text: "greater or equal than"},
+ {value: "<=", text: "less or equal than"}
+ ],
+ get_value: function() {
+ var value = parseFloat(this.$element.val());
+ if(value != 0 && !value) {
+ return "";
+ }
+ return value;
+ }
+});
+openerp.web.search.ExtendedSearchProposition.Selection = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.selection',
+ identifier_prefix: 'extended-search-proposition-selection',
+ operators: [
+ {value: "=", text: "is"},
+ {value: "!=", text: "is not"}
+ ],
+ set_field: function(field) {
+ this.field = field;
+ },
+ get_value: function() {
+ return this.$element.val();
+ }
+});
+openerp.web.search.ExtendedSearchProposition.Boolean = openerp.web.OldWidget.extend({
+ template: 'SearchView.extended_search.proposition.boolean',
+ identifier_prefix: 'extended-search-proposition-boolean',
+ operators: [
+ {value: "=", text: "is true"},
+ {value: "!=", text: "is false"}
+ ],
+ get_value: function() {
+ return true;
+ }
+});
+
+openerp.web.search.custom_filters = new openerp.web.Registry({
+ 'char': 'openerp.web.search.ExtendedSearchProposition.Char',
+ 'text': 'openerp.web.search.ExtendedSearchProposition.Char',
+ 'one2many': 'openerp.web.search.ExtendedSearchProposition.Char',
+ 'many2one': 'openerp.web.search.ExtendedSearchProposition.Char',
+ 'many2many': 'openerp.web.search.ExtendedSearchProposition.Char',
+
+ 'datetime': 'openerp.web.search.ExtendedSearchProposition.DateTime',
+ 'date': 'openerp.web.search.ExtendedSearchProposition.Date',
+ 'integer': 'openerp.web.search.ExtendedSearchProposition.Integer',
+ 'float': 'openerp.web.search.ExtendedSearchProposition.Float',
+ 'boolean': 'openerp.web.search.ExtendedSearchProposition.Boolean',
+ 'selection': 'openerp.web.search.ExtendedSearchProposition.Selection'
+});
+
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js
new file mode 100644
index 00000000000..22800facf9b
--- /dev/null
+++ b/addons/web/static/src/js/view_editor.js
@@ -0,0 +1,147 @@
+openerp.web.view_editor = function(openerp) {
+openerp.web.ViewEditor = openerp.web.Widget.extend({
+ init: function(parent, element_id, dataset, view, options) {
+ this._super(parent);
+ this.element_id = element_id
+ this.parent = parent
+ this.dataset = dataset;
+ this.model = dataset.model;
+ this.xml_id = 0;
+ },
+ start: function() {
+ this.View_editor();
+ },
+ View_editor : function(){
+ var self = this;
+ var action = {
+ name:'ViewEditor',
+ context:this.session.user_context,
+ domain: [["model", "=", this.dataset.model]],
+ res_model: 'ir.ui.view',
+ views : [[false, 'list']],
+ type: 'ir.actions.act_window',
+ target: "current",
+ limit : 80,
+ auto_search : true,
+ flags: {
+ sidebar: false,
+ views_switcher: false,
+ action_buttons:false,
+ search_view:false,
+ pager:false,
+ radio:true
+ },
+ };
+ var action_manager = new openerp.web.ActionManager(this);
+ this.dialog = new openerp.web.Dialog(this,{
+ modal: true,
+ title: 'ViewEditor',
+ width: 750,
+ height: 500,
+ buttons: {
+ "Create": function(){
+
+ },
+ "Edit": function(){
+ self.xml_id=0;
+ self.edit_view();
+ },
+ "Close": function(){
+ $(this).dialog('destroy');
+ }
+ },
+
+ });
+ this.dialog.start();
+ this.dialog.open();
+ action_manager.appendTo(this.dialog);
+ action_manager.do_action(action);
+
+
+ },
+ check_attr:function(xml,tag){
+ var obj = new Object();
+ obj.child_id = [];
+ obj.id = this.xml_id++;
+ var att_list = [];
+ var name1 = "<" + tag;
+ $(xml).each(function() {
+ att_list = this.attributes;
+ att_list = _.select(att_list, function(attrs){
+ if(attrs.nodeName == "string" || attrs.nodeName == "name" || attrs.nodeName == "index"){
+ name1 += ' ' +attrs.nodeName+'='+'"'+attrs.nodeValue+'"';}
+ });
+ name1+= ">";
+ });
+ obj.name = name1;
+ return obj;
+ },
+ recursiveFunction : function(main_object,parent_id,child_id){
+ var self = this;
+ var check = false;
+ var main_object = _.detect(main_object , function(node){
+ if(node.id == parent_id){
+ node.child_id = child_id;
+ check = true;
+ }
+ return main_object;
+ });
+ if(check){
+ return main_object;
+ }else{
+ //todo recursion for saving object into objects
+ }
+ },
+ children_function : function(xml,root,main_object,parent_id){
+ var self = this;
+ var child_obj_list = [];
+ var main_object = main_object;
+ var children_list = $(xml).filter(root).children();
+ _.each(children_list, function(child_node){
+ var string = self.check_attr(child_node,child_node.tagName.toLowerCase());
+ child_obj_list.push(string);
+ });
+ if(children_list.length != 0){
+ main_object = self.recursiveFunction(main_object,parent_id,child_obj_list);
+ }
+ for(var i=0;i<children_list.length;i++){
+ self.children_function(children_list[i],children_list[i].tagName.toLowerCase(),main_object,child_obj_list[i].id);
+ }
+ return child_obj_list;
+ },
+ edit_view : function(){
+ var self = this;
+ var view_id =(($("input[name='radiogroup']:checked").parent()).parent()).attr('data-id');
+ var ve_dataset = new openerp.web.DataSet(this,'ir.ui.view');
+ ve_dataset.read_ids([parseInt(view_id)],['arch'],function (arch) {
+ var arch = arch[0].arch;
+ var root = $(arch).filter(":first")[0];
+ var tag = root.tagName.toLowerCase();
+ var root_object = self.check_attr(root,tag);
+ var all_list = self.children_function(arch,tag,[root_object],root_object.id);
+
+ //todo render the final object of tree view so xml with it child node display...
+ });
+ this.dialog = new openerp.web.Dialog(this,{
+ modal: true,
+ title: 'Edit Xml',
+ width: 750,
+ height: 500,
+ buttons: {
+ "Inherited View": function(){
+
+ },
+ "Preview": function(){
+
+ },
+ "Close": function(){
+ $(this).dialog('destroy');
+ }
+ },
+
+ });
+ this.dialog.start().open();
+ }
+
+});
+};
diff --git a/addons/web/static/src/js/view_help.js b/addons/web/static/src/js/view_help.js
new file mode 100644
index 00000000000..f7e5f7c259e
--- /dev/null
+++ b/addons/web/static/src/js/view_help.js
@@ -0,0 +1,15 @@
+/*---------------------------------------------------------
+ * OpenERP web library
+ *---------------------------------------------------------*/
+
+openerp.web.view_help = function(openerp) {
+
+openerp.web.ProcessView = openerp.web.Widget.extend({
+});
+
+openerp.web.HelpView = openerp.web.Widget.extend({
+});
+
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
new file mode 100644
index 00000000000..2a314f57fa8
--- /dev/null
+++ b/addons/web/static/src/js/view_tree.js
@@ -0,0 +1,216 @@
+/*---------------------------------------------------------
+ * OpenERP web library
+ *---------------------------------------------------------*/
+
+openerp.web.view_tree = function(openerp) {
+var QWeb = openerp.web.qweb;
+
+openerp.web.views.add('tree', 'openerp.web.TreeView');
+openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView# */{
+ /**
+ * Indicates that this view is not searchable, and thus that no search
+ * view should be displayed (if there is one active).
+ */
+ searchable : false,
+ /**
+ * Genuine tree view (the one displayed as a tree, not the list)
+ *
+ * @constructs openerp.web.TreeView
+ * @extends openerp.web.View
+ *
+ * @param parent
+ * @param element_id
+ * @param dataset
+ * @param view_id
+ * @param options
+ */
+ init: function(parent, element_id, dataset, view_id, options) {
+ this._super(parent, element_id);
+ this.dataset = dataset;
+ this.model = dataset.model;
+ this.view_id = view_id;
+
+ this.records = {};
+
+ this.options = _.extend({}, this.defaults, options || {});
+ },
+
+ start: function () {
+ this._super();
+ return this.rpc("/web/treeview/load", {
+ model: this.model,
+ view_id: this.view_id,
+ view_type: "tree",
+ toolbar: this.view_manager ? !!this.view_manager.sidebar : false
+ }, this.on_loaded);
+ },
+ /**
+ * Returns the list of fields needed to correctly read objects.
+ *
+ * Gathers the names of all fields in fields_view_get, and adds the
+ * field_parent (children_field in the tree view) if it's not already one
+ * of the fields to fetch
+ *
+ * @returns {Array} an array of fields which can be provided to DataSet.read_slice and others
+ */
+ fields_list: function () {
+ var fields = _.keys(this.fields);
+ if (!_(fields).contains(this.children_field)) {
+ fields.push(this.children_field);
+ }
+ return fields;
+ },
+ on_loaded: function (fields_view) {
+ var self = this;
+ var has_toolbar = !!fields_view.arch.attrs.toolbar;
+ // field name in OpenERP is kinda stupid: this is the name of the field
+ // holding the ids to the children of the current node, why call it
+ // field_parent?
+ this.children_field = fields_view['field_parent'];
+ this.fields_view = fields_view;
+ _(this.fields_view.arch.children).each(function (field) {
+ if (field.attrs.modifiers) {
+ field.attrs.modifiers = JSON.parse(field.attrs.modifiers);
+ }
+ });
+ this.fields = fields_view.fields;
+ this.hook_row_click();
+ this.$element.html(QWeb.render('TreeView', {
+ 'title': this.fields_view.arch.attrs.string,
+ 'fields_view': this.fields_view.arch.children,
+ 'fields': this.fields,
+ 'toolbar': has_toolbar
+ }));
+
+ this.dataset.read_slice(this.fields_list(), {}, function (records) {
+ if (!has_toolbar) {
+ // WARNING: will do a second read on the same ids, but only on
+ // first load so not very important
+ self.getdata(null, _(records).pluck('id'));
+ return;
+ }
+
+ var $select = self.$element.find('select')
+ .change(function () {
+ var $option = $(this).find(':selected');
+ self.getdata($option.val(), $option.data('children'));
+ });
+ _(records).each(function (record) {
+ self.records[record.id] = record;
+ $('<option>')
+ .val(record.id)
+ .text(record.name)
+ .data('children', record[self.children_field])
+ .appendTo($select);
+ });
+
+ if (!_.isEmpty(records)) {
+ $select.change();
+ }
+ });
+ },
+ /**
+ * Sets up opening a row
+ */
+ hook_row_click: function () {
+ var self = this;
+ this.$element.delegate('.treeview-td span, .treeview-tr span', 'click', function (e) {
+ e.stopImmediatePropagation();
+ self.activate($(this).closest('tr').data('id'));
+ });
+
+ this.$element.delegate('.treeview-tr', 'click', function () {
+ var is_loaded = 0,
+ $this = $(this),
+ record_id = $this.data('id'),
+ record = self.records[record_id],
+ children_ids = record[self.children_field];
+
+ _(children_ids).each(function(childid) {
+ if (self.$element.find('#treerow_' + childid).length) {
+ if (self.$element.find('#treerow_' + childid).is(':hidden')) {
+ is_loaded = -1;
+ } else {
+ is_loaded++;
+ }
+ }
+ });
+ if (is_loaded === 0) {
+ if (!$this.parent().hasClass('oe-open')) {
+ self.getdata(record_id, children_ids);
+ }
+ } else {
+ self.showcontent(record_id, is_loaded < 0);
+ }
+ });
+ },
+ // get child data of selected value
+ getdata: function (id, children_ids) {
+ var self = this;
+
+ self.dataset.read_ids(children_ids, this.fields_list(), function (records) {
+ _(records).each(function (record) {
+ self.records[record.id] = record;
+ });
+
+ var $curr_node = self.$element.find('#treerow_' + id);
+ var children_rows = QWeb.render('TreeView.rows', {
+ 'records': records,
+ 'children_field': self.children_field,
+ 'fields_view': self.fields_view.arch.children,
+ 'fields': self.fields,
+ 'level': $curr_node.data('level') || 0,
+ 'render': openerp.web.format_value
+ });
+
+ if ($curr_node.length) {
+ $curr_node.addClass('oe-open');
+ $curr_node.after(children_rows);
+ } else {
+ self.$element.find('tbody').html(children_rows);
+ }
+ });
+ },
+
+ // Get details in listview
+ activate: function(id) {
+ var self = this;
+ this.rpc('/web/treeview/action', {
+ id: id,
+ model: this.dataset.model,
+ context: new openerp.web.CompoundContext(
+ this.dataset.get_context(), {
+ active_model: this.dataset.model,
+ active_id: id,
+ active_ids: [id]})
+ }, function (actions) {
+ if (!actions.length) { return; }
+ var action = actions[0][2];
+ self.do_action(action);
+ });
+ },
+
+ // show & hide the contents
+ showcontent: function (record_id, show) {
+ this.$element.find('#treerow_' + record_id)
+ .toggleClass('oe-open', show);
+
+ _(this.records[record_id][this.children_field]).each(function (child_id) {
+ var $child_row = this.$element.find('#treerow_' + child_id);
+ if ($child_row.hasClass('oe-open')) {
+ this.showcontent(child_id, false);
+ }
+ $child_row.toggle(show);
+ }, this);
+ },
+
+ do_show: function () {
+ this.$element.show();
+ },
+
+ do_hide: function () {
+ this.$element.hide();
+ this.hidden = true;
+ }
+});
+};
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
new file mode 100644
index 00000000000..39d02d221ff
--- /dev/null
+++ b/addons/web/static/src/js/views.js
@@ -0,0 +1,829 @@
+/*---------------------------------------------------------
+ * OpenERP web library
+ *---------------------------------------------------------*/
+
+openerp.web.views = function(openerp) {
+
+var _t = openerp.web._t;
+var QWeb = openerp.web.qweb;
+
+/**
+ * Registry for all the client actions key: tag value: widget
+ */
+openerp.web.client_actions = new openerp.web.Registry();
+
+openerp.web.ActionManager = openerp.web.Widget.extend({
+ identifier_prefix: "actionmanager",
+ init: function(parent) {
+ this._super(parent);
+ this.inner_viewmanager = null;
+ this.dialog = null;
+ this.dialog_viewmanager = null;
+ this.client_widget = null;
+ this.url = {}
+ },
+ render: function() {
+ return "<div id='"+this.element_id+"'></div>";
+ },
+ dialog_stop: function () {
+ if (this.dialog) {
+ this.dialog_viewmanager.stop();
+ this.dialog_viewmanager = null;
+ this.dialog.stop();
+ this.dialog = null;
+ }
+ },
+ content_stop: function () {
+ if (this.inner_viewmanager) {
+ this.inner_viewmanager.stop();
+ this.inner_viewmanager = null;
+ }
+ if (this.client_widget) {
+ this.client_widget.stop();
+ this.client_widget = null;
+ }
+ },
+ url_update: function(action) {
+ // this.url = {
+ // "model": action.model,
+ // "domain": action.domain,
+ // };
+ // action.res_model
+ // action.domain
+ // action.context
+ // after
+ // action.views
+ // action.res_id
+ // mode
+ // menu
+ },
+ url_stringify: function(action) {
+ },
+ url_parse: function(action) {
+ },
+ on_url_update: function(url) {
+ },
+ do_url_action: function(url) {
+ },
+ do_action: function(action, on_close) {
+ var type = action.type.replace(/\./g,'_');
+ var popup = action.target === 'new';
+ action.flags = _.extend({
+ views_switcher : !popup,
+ search_view : !popup,
+ action_buttons : !popup,
+ sidebar : !popup,
+ pager : !popup
+ }, action.flags || {});
+ if (!(type in this)) {
+ console.log("Action manager can't handle action of type " + action.type, action);
+ return;
+ }
+ this[type](action, on_close);
+ },
+ ir_actions_act_window: function (action, on_close) {
+ if (action.target === 'new') {
+ if (this.dialog == null) {
+ this.dialog = new openerp.web.Dialog(this, { title: action.name, width: '80%' });
+ if(on_close)
+ this.dialog.on_close.add(on_close);
+ this.dialog.start();
+ } else {
+ this.dialog_viewmanager.stop();
+ }
+ this.dialog_viewmanager = new openerp.web.ViewManagerAction(this, action);
+ this.dialog_viewmanager.appendTo(this.dialog.$element);
+ this.dialog.open();
+ } else {
+ this.dialog_stop();
+ this.content_stop();
+ this.inner_viewmanager = new openerp.web.ViewManagerAction(this, action);
+ this.inner_viewmanager.appendTo(this.$element);
+ this.url_update(action);
+ }
+ /* new window code
+ this.rpc("/web/session/save_session_action", { the_action : action}, function(key) {
+ var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "?" + jQuery.param({ s_action : "" + key });
+ window.open(url,'_blank');
+ });
+ */
+ },
+ ir_actions_act_window_close: function (action, on_closed) {
+ this.dialog_stop();
+ },
+ ir_actions_server: function (action, on_closed) {
+ var self = this;
+ this.rpc('/web/action/run', {
+ action_id: action.id,
+ context: action.context || {}
+ }).then(function (action) {
+ self.do_action(action, on_closed)
+ });
+ },
+ ir_actions_client: function (action) {
+ this.content_stop();
+ var ClientWidget = openerp.web.client_actions.get_object(action.tag);
+ (this.client_widget = new ClientWidget(this, action.params)).appendTo(this);
+ },
+ ir_actions_report_xml: function(action) {
+ $.blockUI();
+ this.session.get_file({
+ url: '/web/report',
+ data: {action: JSON.stringify(action)},
+ complete: $.unblockUI
+ });
+ }
+});
+
+openerp.web.ViewManager = openerp.web.Widget.extend(/** @lends openerp.web.ViewManager# */{
+ identifier_prefix: "viewmanager",
+ template: "ViewManager",
+ /**
+ * @constructs openerp.web.ViewManager
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param dataset
+ * @param views
+ */
+ init: function(parent, dataset, views) {
+ this._super(parent);
+ this.model = dataset.model;
+ this.dataset = dataset;
+ this.searchview = null;
+ this.active_view = null;
+ this.views_src = _.map(views, function(x) {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
+ this.views = {};
+ this.flags = this.flags || {};
+ this.registry = openerp.web.views;
+ },
+ render: function() {
+ return QWeb.render(this.template, {"prefix": this.element_id, views: this.views_src})
+ },
+ /**
+ * @returns {jQuery.Deferred} initial view loading promise
+ */
+ start: function() {
+ this._super();
+ var self = this;
+ this.dataset.start();
+ this.$element.find('.oe_vm_switch button').click(function() {
+ self.on_mode_switch($(this).data('view-type'));
+ });
+ var views_ids = {};
+ _.each(this.views_src, function(view) {
+ self.views[view.view_type] = $.extend({}, view, {
+ controller : null,
+ options : _.extend({
+ sidebar_id : self.element_id + '_sidebar_' + view.view_type,
+ action : self.action,
+ action_views_ids : views_ids
+ }, self.flags, view.options || {})
+ });
+ views_ids[view.view_type] = view.view_id;
+ });
+ if (this.flags.views_switcher === false) {
+ this.$element.find('.oe_vm_switch').hide();
+ }
+ // switch to the first one in sequence
+ return this.on_mode_switch(this.views_src[0].view_type);
+ },
+ /**
+ * Asks the view manager to switch visualization mode.
+ *
+ * @param {String} view_type type of view to display
+ * @returns {jQuery.Deferred} new view loading promise
+ */
+ on_mode_switch: function(view_type) {
+ var self = this,
+ view_promise;
+ this.active_view = view_type;
+ var view = this.views[view_type];
+ if (!view.controller) {
+ // Lazy loading of views
+ var controllerclass = this.registry.get_object(view_type);
+ var controller = new controllerclass(this, this.element_id + '_view_' + view_type,
+ this.dataset, view.view_id, view.options);
+ if (view.embedded_view) {
+ controller.set_embedded_view(view.embedded_view);
+ }
+ controller.do_switch_view.add_last(this.on_mode_switch);
+ if (view_type === 'list' && this.flags.search_view === false && this.action && this.action['auto_search']) {
+ // In case the search view is not instantiated: manually call ListView#search
+ var domains = !_(self.action.domain).isEmpty()
+ ? [self.action.domain] : [],
+ contexts = !_(self.action.context).isEmpty()
+ ? [self.action.context] : [];
+ controller.on_loaded.add({
+ callback: function () {
+ controller.do_search(domains, contexts, []);
+ },
+ position: 'last',
+ unique: true
+ });
+ }
+ view_promise = controller.start();
+ $.when(view_promise).then(function() {
+ self.on_controller_inited(view_type, controller);
+ });
+ this.views[view_type].controller = controller;
+ }
+
+
+ if (this.searchview) {
+ if (view.controller.searchable === false) {
+ this.searchview.hide();
+ } else {
+ this.searchview.show();
+ }
+ }
+
+ this.$element
+ .find('.views-switchers button').removeAttr('disabled')
+ .filter('[data-view-type="' + view_type + '"]')
+ .attr('disabled', true);
+
+ for (var view_name in this.views) {
+ if (!this.views.hasOwnProperty(view_name)) { continue; }
+ if (this.views[view_name].controller) {
+ if (view_name === view_type) {
+ $.when(view_promise).then(this.views[view_name].controller.do_show);
+ } else {
+ this.views[view_name].controller.do_hide();
+ }
+ }
+ }
+ return view_promise;
+ },
+ /**
+ * Event launched when a controller has been inited.
+ *
+ * @param {String} view_type type of view
+ * @param {String} view the inited controller
+ */
+ on_controller_inited: function(view_type, view) {
+ },
+ /**
+ * Sets up the current viewmanager's search view.
+ *
+ * @param {Number|false} view_id the view to use or false for a default one
+ * @returns {jQuery.Deferred} search view startup deferred
+ */
+ setup_search_view: function(view_id, search_defaults) {
+ var self = this;
+ if (this.searchview) {
+ this.searchview.stop();
+ }
+ this.searchview = new openerp.web.SearchView(
+ this, this.element_id + "_search", this.dataset,
+ view_id, search_defaults);
+
+ this.searchview.on_search.add(function(domains, contexts, groupbys) {
+ var controller = self.views[self.active_view].controller;
+ controller.do_search.call(controller, domains, contexts, groupbys);
+ });
+ return this.searchview.start();
+ },
+ /**
+ * Called when one of the view want to execute an action
+ */
+ on_action: function(action) {
+ },
+ on_create: function() {
+ },
+ on_remove: function() {
+ },
+ on_edit: function() {
+ }
+});
+
+openerp.web.ViewManagerAction = openerp.web.ViewManager.extend(/** @lends oepnerp.web.ViewManagerAction# */{
+ template:"ViewManagerAction",
+ /**
+ * @constructs openerp.web.ViewManagerAction
+ * @extends openerp.web.ViewManager
+ *
+ * @param {openerp.web.ActionManager} parent parent object/widget
+ * @param {Object} action descriptor for the action this viewmanager needs to manage its views.
+ */
+ init: function(parent, action) {
+ // dataset initialization will take the session from ``this``, so if we
+ // do not have it yet (and we don't, because we've not called our own
+ // ``_super()``) rpc requests will blow up.
+ this.session = parent.session;
+ this.action = action;
+ var dataset = new openerp.web.DataSetSearch(this, action.res_model, action.context, action.domain);
+ if (action.res_id) {
+ dataset.ids.push(action.res_id);
+ dataset.index = 0;
+ }
+ this._super(parent, dataset, action.views);
+ this.flags = this.action.flags || {};
+ if (action.res_model == 'board.board' && action.views.length == 1 && action.views) {
+ // Not elegant but allows to avoid form chrome (pager, save/new
+ // buttons, sidebar, ...) displaying
+ this.flags.search_view = this.flags.pager = this.flags.sidebar = this.flags.action_buttons = false;
+ }
+ },
+ /**
+ * Initializes the ViewManagerAction: sets up the searchview (if the
+ * searchview is enabled in the manager's action flags), calls into the
+ * parent to initialize the primary view and (if the VMA has a searchview)
+ * launches an initial search after both views are done rendering.
+ */
+ start: function() {
+ var searchview_loaded;
+ if (this.flags.search_view !== false) {
+ var search_defaults = {};
+ _.each(this.action.context, function (value, key) {
+ var match = /^search_default_(.*)$/.exec(key);
+ if (match) {
+ search_defaults[match[1]] = value;
+ }
+ });
+ // init search view
+ var searchview_id = this.action['search_view_id'] && this.action['search_view_id'][0];
+
+ searchview_loaded = this.setup_search_view(
+ searchview_id || false, search_defaults);
+ }
+
+ var main_view_loaded = this._super();
+
+ var manager_ready = $.when(searchview_loaded, main_view_loaded);
+ if (searchview_loaded && this.action['auto_search']) {
+ // schedule auto_search
+ manager_ready.then(this.searchview.do_search);
+ }
+ return manager_ready;
+ },
+ on_mode_switch: function (view_type) {
+ return $.when(
+ this._super(view_type),
+ this.shortcut_check(this.views[view_type]));
+ },
+ shortcut_check : function(view) {
+ var self = this;
+ var grandparent = this.widget_parent && this.widget_parent.widget_parent;
+ // display shortcuts if on the first view for the action
+ var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
+ if (!(grandparent instanceof openerp.web.WebClient) ||
+ !(view.view_type === this.views_src[0].view_type
+ && view.view_id === this.views_src[0].view_id)) {
+ $shortcut_toggle.hide();
+ return;
+ }
+ $shortcut_toggle.removeClass('oe-shortcut-remove').show();
+ if (_(this.session.shortcuts).detect(function (shortcut) {
+ return shortcut.res_id === self.session.active_id; })) {
+ $shortcut_toggle.addClass("oe-shortcut-remove");
+ }
+ this.shortcut_add_remove();
+ },
+ shortcut_add_remove: function() {
+ var self = this;
+ var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
+ $shortcut_toggle
+ .unbind("click")
+ .click(function() {
+ if ($shortcut_toggle.hasClass("oe-shortcut-remove")) {
+ $(self.session.shortcuts.binding).trigger('remove-current');
+ $shortcut_toggle.removeClass("oe-shortcut-remove");
+ } else {
+ $(self.session.shortcuts.binding).trigger('add', {
+ 'user_id': self.session.uid,
+ 'res_id': self.session.active_id,
+ 'resource': 'ir.ui.menu',
+ 'name': self.action.name
+ });
+ $shortcut_toggle.addClass("oe-shortcut-remove");
+ }
+ });
+ }
+});
+
+openerp.web.Sidebar = openerp.web.Widget.extend({
+ init: function(parent, element_id) {
+ this._super(parent, element_id);
+ this.items = {};
+ this.sections = {};
+ },
+ start: function() {
+ this._super(this);
+ var self = this;
+ this.$element.html(QWeb.render('Sidebar'));
+ this.$element.find(".toggle-sidebar").click(function(e) {
+ self.do_toggle();
+ });
+ },
+ add_toolbar: function(toolbar) {
+ var self = this;
+ _.each([['print', "Reports"], ['action', "Actions"], ['relate', "Links"]], function(type) {
+ var items = toolbar[type[0]];
+ if (items.length) {
+ for (var i = 0; i < items.length; i++) {
+ items[i] = {
+ label: items[i]['name'],
+ action: items[i],
+ classname: 'oe_sidebar_' + type[0]
+ }
+ }
+ self.add_section(type[0], type[1], items);
+ }
+ });
+ },
+ add_section: function(code, name, items) {
+ // For each section, we pass a name/label and optionally an array of items.
+ // If no items are passed, then the section will be created as a custom section
+ // returning back an element_id to be used by a custom controller.
+ // Else, the section is a standard section with items displayed as links.
+ // An item is a dictonary : {
+ // label: label to be displayed for the link,
+ // action: action to be launch when the link is clicked,
+ // callback: a function to be executed when the link is clicked,
+ // classname: optional dom class name for the line,
+ // title: optional title for the link
+ // }
+ // Note: The item should have one action or/and a callback
+ var self = this,
+ section_id = _.uniqueId(this.element_id + '_section_' + code + '_');
+ if (items) {
+ for (var i = 0; i < items.length; i++) {
+ items[i].element_id = _.uniqueId(section_id + '_item_');
+ this.items[items[i].element_id] = items[i];
+ }
+ }
+ var $section = $(QWeb.render("Sidebar.section", {
+ section_id: section_id,
+ name: name,
+ classname: 'oe_sidebar_' + code,
+ items: items
+ }));
+ if (items) {
+ $section.find('a.oe_sidebar_action_a').click(function() {
+ var item = self.items[$(this).attr('id')];
+ if (item.callback) {
+ item.callback();
+ }
+ if (item.action) {
+ var ids = self.widget_parent.get_selected_ids();
+ if (ids.length == 0) {
+ //TODO: make prettier warning?
+ $("<div />").text(_t("You must choose at least one record.")).dialog({
+ title: _t("Warning"),
+ modal: true
+ });
+ return false;
+ }
+ var additional_context = {
+ active_id: ids[0],
+ active_ids: ids,
+ active_model: self.widget_parent.dataset.model
+ };
+ self.rpc("/web/action/load", {
+ action_id: item.action.id,
+ context: additional_context
+ }, function(result) {
+ result.result.context = _.extend(result.result.context || {},
+ additional_context);
+ result.result.flags = result.result.flags || {};
+ result.result.flags.new_window = true;
+ self.do_action(result.result);
+ });
+ }
+ return false;
+ });
+ }
+ $section.appendTo(this.$element.find('div.sidebar-actions'));
+ this.sections[code] = $section;
+ return section_id;
+ },
+ do_fold: function() {
+ this.$element.addClass('closed-sidebar').removeClass('open-sidebar');
+ },
+ do_unfold: function() {
+ this.$element.addClass('open-sidebar').removeClass('closed-sidebar');
+ },
+ do_toggle: function() {
+ this.$element.toggleClass('open-sidebar closed-sidebar');
+ }
+});
+
+openerp.web.TranslateDialog = openerp.web.Dialog.extend({
+ dialog_title: _t("Translations"),
+ init: function(view) {
+ // TODO fme: should add the language to fields_view_get because between the fields view get
+ // and the moment the user opens the translation dialog, the user language could have been changed
+ this.view_language = view.session.user_context.lang;
+ this['on_button' + _t("Save")] = this.on_button_Save;
+ this['on_button' + _t("Close")] = this.on_button_Close;
+ this._super(view, {
+ width: '80%',
+ height: '80%'
+ });
+ this.view = view;
+ this.view_type = view.fields_view.type || '';
+ this.$fields_form = null;
+ this.$view_form = null;
+ this.$sidebar_form = null;
+ this.translatable_fields_keys = _.map(this.view.translatable_fields || [], function(i) { return i.name });
+ this.languages = null;
+ this.languages_loaded = $.Deferred();
+ (new openerp.web.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(),
+ [['translatable', '=', '1']])).read_slice(['code', 'name'], { sort: 'id' }, this.on_languages_loaded);
+ },
+ start: function() {
+ var self = this;
+ this._super();
+ $.when(this.languages_loaded).then(function() {
+ self.$element.html(QWeb.render('TranslateDialog', { widget: self }));
+ self.$element.tabs();
+ if (!(self.view.translatable_fields && self.view.translatable_fields.length)) {
+ self.hide_tabs('fields');
+ self.select_tab('view');
+ }
+ self.$fields_form = self.$element.find('.oe_translation_form');
+ self.$fields_form.find('.oe_trad_field').change(function() {
+ $(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value')));
+ });
+ });
+ return this;
+ },
+ on_languages_loaded: function(langs) {
+ this.languages = langs;
+ this.languages_loaded.resolve();
+ },
+ do_load_fields_values: function(callback) {
+ var self = this,
+ deffered = [];
+ this.$fields_form.find('.oe_trad_field').val('').removeClass('touched');
+ _.each(self.languages, function(lg) {
+ var deff = $.Deferred();
+ deffered.push(deff);
+ var callback = function(values) {
+ _.each(self.translatable_fields_keys, function(f) {
+ self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '').attr('data-value', values[0][f] || '');
+ });
+ deff.resolve();
+ };
+ if (lg.code === self.view_language) {
+ var values = {};
+ _.each(self.translatable_fields_keys, function(field) {
+ values[field] = self.view.fields[field].get_value();
+ });
+ callback([values]);
+ } else {
+ self.rpc('/web/dataset/get', {
+ model: self.view.dataset.model,
+ ids: [self.view.datarecord.id],
+ fields: self.translatable_fields_keys,
+ context: self.view.dataset.get_context({
+ 'lang': lg.code
+ })}, callback);
+ }
+ });
+ $.when.apply(null, deffered).then(callback);
+ },
+ show_tabs: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().show();
+ }
+ },
+ hide_tabs: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().hide();
+ }
+ },
+ select_tab: function(name) {
+ this.show_tabs(name);
+ var index = this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().index() - 1;
+ this.$element.tabs('select', index);
+ },
+ open: function(field) {
+ var self = this,
+ sup = this._super;
+ $.when(this.languages_loaded).then(function() {
+ if (self.view.translatable_fields && self.view.translatable_fields.length) {
+ self.do_load_fields_values(function() {
+ sup.call(self);
+ if (field) {
+ // TODO: focus and scroll to field
+ }
+ });
+ } else {
+ sup.call(self);
+ }
+ });
+ },
+ on_button_Save: function() {
+ var trads = {},
+ self = this;
+ self.$fields_form.find('.oe_trad_field.touched').each(function() {
+ var field = $(this).attr('name').split('-');
+ if (!trads[field[0]]) {
+ trads[field[0]] = {};
+ }
+ trads[field[0]][field[1]] = $(this).val();
+ });
+ _.each(trads, function(data, code) {
+ if (code === self.view_language) {
+ _.each(data, function(value, field) {
+ self.view.fields[field].set_value(value);
+ });
+ } else {
+ self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code });
+ }
+ });
+ this.close();
+ },
+ on_button_Close: function() {
+ this.close();
+ }
+});
+
+/**
+ * @class
+ * @extends openerp.web.Widget
+ */
+openerp.web.View = openerp.web.Widget.extend(/** @lends openerp.web.View# */{
+ set_default_options: function(options) {
+ this.options = options || {};
+ _.defaults(this.options, {
+ // All possible views options should be defaulted here
+ sidebar_id: null,
+ sidebar: true,
+ action: null,
+ action_views_ids: {}
+ });
+ },
+ open_translate_dialog: function(field) {
+ if (!this.translate_dialog) {
+ this.translate_dialog = new openerp.web.TranslateDialog(this).start();
+ }
+ this.translate_dialog.open(field);
+ },
+ /**
+ * Fetches and executes the action identified by ``action_data``.
+ *
+ * @param {Object} action_data the action descriptor data
+ * @param {String} action_data.name the action name, used to uniquely identify the action to find and execute it
+ * @param {String} [action_data.special=null] special action handlers (currently: only ``'cancel'``)
+ * @param {String} [action_data.type='workflow'] the action type, if present, one of ``'object'``, ``'action'`` or ``'workflow'``
+ * @param {Object} [action_data.context=null] additional action context, to add to the current context
+ * @param {openerp.web.DataSet} dataset a dataset object used to communicate with the server
+ * @param {Object} [record_id] the identifier of the object on which the action is to be applied
+ * @param {Function} on_closed callback to execute when dialog is closed or when the action does not generate any result (no new action)
+ */
+ execute_action: function (action_data, dataset, record_id, on_closed) {
+ var self = this;
+ var handler = function (r) {
+ var action = r.result;
+ if (action && action.constructor == Object) {
+ action.context = action.context || {};
+ _.extend(action.context, {
+ active_id: record_id || false,
+ active_ids: [record_id || false],
+ active_model: dataset.model
+ });
+ action.context = new openerp.web.CompoundContext(dataset.get_context(), action.context);
+ self.do_action(action, on_closed);
+ } else if (on_closed) {
+ on_closed(action);
+ }
+ };
+
+ var context = new openerp.web.CompoundContext(dataset.get_context(), action_data.context || {});
+
+ if (action_data.special) {
+ handler({result: {"type":"ir.actions.act_window_close"}});
+ } else if (action_data.type=="object") {
+ return dataset.call_button(action_data.name, [[record_id], context], handler);
+ } else if (action_data.type=="action") {
+ return this.rpc('/web/action/load', { action_id: parseInt(action_data.name, 10), context: context }, handler);
+ } else {
+ return dataset.exec_workflow(record_id, action_data.name, handler);
+ }
+ },
+ /**
+ * Directly set a view to use instead of calling fields_view_get. This method must
+ * be called before start(). When an embedded view is set, underlying implementations
+ * of openerp.web.View must use the provided view instead of any other one.
+ *
+ * @param embedded_view A view.
+ */
+ set_embedded_view: function(embedded_view) {
+ this.embedded_view = embedded_view;
+ this.options.sidebar = false;
+ },
+ do_switch_view: function(view) {
+ },
+ set_common_sidebar_sections: function(sidebar) {
+ sidebar.add_section('customize', "Customize", [
+ {
+ label: "Manage Views",
+ callback: this.on_sidebar_manage_view,
+ title: "Manage views of the current object"
+ }, {
+ label: "Edit Workflow",
+ callback: this.on_sidebar_edit_workflow,
+ title: "Manage views of the current object",
+ classname: 'oe_hide oe_sidebar_edit_workflow'
+ }, {
+ label: "Customize Object",
+ callback: this.on_sidebar_customize_object,
+ title: "Manage views of the current object"
+ }
+ ]);
+ sidebar.add_section('other', "Other Options", [
+ {
+ label: "Import",
+ callback: this.on_sidebar_import
+ }, {
+ label: "Export",
+ callback: this.on_sidebar_export
+ }, {
+ label: "Translate",
+ callback: this.on_sidebar_translate,
+ classname: 'oe_sidebar_translate oe_hide'
+ }, {
+ label: "View Log",
+ callback: this.on_sidebar_view_log,
+ classname: 'oe_hide oe_sidebar_view_log'
+ }
+ ]);
+ },
+ on_sidebar_manage_view: function() {
+ if (this.fields_view && this.fields_view.arch) {
+// $('<xmp>' + openerp.base.json_node_to_xml(this.fields_view.arch, true) + '</xmp>').dialog({ width: '95%', height: 600});
+ var view_editor = new openerp.base.ViewEditor(this, this.$element, this.dataset, this.fields_view.arch)
+ view_editor.start();
+ } else {
+ this.notification.warn("Manage Views", "Could not find current view declaration");
+ }
+ },
+ on_sidebar_edit_workflow: function() {
+ console.log('Todo');
+ },
+ on_sidebar_customize_object: function() {
+ console.log('Todo');
+ },
+ on_sidebar_import: function() {
+ },
+ on_sidebar_export: function() {
+ var export_view = new openerp.web.DataExport(this, this.dataset);
+ export_view.start();
+ },
+ on_sidebar_translate: function() {
+ this.open_translate_dialog();
+ },
+ on_sidebar_view_log: function() {
+ }
+});
+
+/**
+ * Registry for all the main views
+ */
+openerp.web.views = new openerp.web.Registry();
+
+openerp.web.json_node_to_xml = function(node, single_quote, indent) {
+ // For debugging purpose, this function will convert a json node back to xml
+ // Maybe usefull for xml view editor
+
+ if (typeof(node) === 'string') {
+ return node;
+ }
+ else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
+ throw("Node a json node");
+ }
+ indent = indent || 0;
+ var sindent = new Array(indent + 1).join('\t'),
+ r = sindent + '<' + node.tag;
+ for (var attr in node.attrs) {
+ var vattr = node.attrs[attr];
+ if (typeof(vattr) !== 'string') {
+ // domains, ...
+ vattr = JSON.stringify(vattr);
+ }
+ vattr = vattr.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ if (single_quote) {
+ vattr = vattr.replace(/&quot;/g, "'");
+ }
+ r += ' ' + attr + '="' + vattr + '"';
+ }
+ if (node.children && node.children.length) {
+ r += '>\n';
+ var childs = [];
+ for (var i = 0, ii = node.children.length; i < ii; i++) {
+ childs.push(openerp.web.json_node_to_xml(node.children[i], single_quote, indent + 1));
+ }
+ r += childs.join('\n');
+ r += '\n' + sindent + '</' + node.tag + '>';
+ return r;
+ } else {
+ return r + '/>';
+ }
+}
+
+};
+
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
new file mode 100644
index 00000000000..e55d56f5912
--- /dev/null
+++ b/addons/web/static/src/xml/base.xml
@@ -0,0 +1,1418 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vim:fdl=1:
+-->
+<templates id="template" xml:space="preserve">
+<t t-name="Interface">
+ <div id="oe_loading" class="loading"></div>
+ <div id="oe_notification" class="oe_notification">
+ <div id="oe_notification_default">
+ <a class="ui-notify-cross ui-notify-close" href="#">x</a>
+ <h1>#{title}</h1>
+ <p>#{text}</p>
+ </div>
+ <div id="oe_notification_alert" class="ui-state-error">
+ <a class="ui-notify-cross ui-notify-close" href="#">x</a>
+ <span style="float:left; margin:2px 5px 0 0;" class="ui-icon ui-icon-alert"></span>
+ <h1>#{title}</h1>
+ <p>#{text}</p>
+ </div>
+ </div>
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" class="main_table">
+ <tr>
+ <td colspan="2" valign="top">
+ <div id="oe_header" class="header"></div>
+ <div id="oe_menu" class="menu"></div>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" class="login-container" colspan="2">
+ <div id="oe_login" class="login"></div>
+ </td>
+ </tr>
+ <tr class="db_options_row">
+ <td valign="top" class="db_container">
+ <div id="oe_database" class="database"></div>
+ </td>
+ <td valign="top">
+ <div id="oe_db_options"></div>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" id="oe_secondary_menu" class="secondary_menu">
+ </td>
+ <td valign="top" class="oe-application-container">
+ <div id="oe_app" class="oe-application">
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <div id="oe_footer" class="oe_footer">
+ <p class="oe_footer_powered">Powered by <a href="http://www.openerp.com">openerp.com</a>.</p>
+ </div>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="Loading">
+ Loading...
+</t>
+<t t-name="Database">
+ <ul class="db_options" style="padding: 0px; display: inline;">
+ <li id="db-create">Create</li>
+ <li id="db-drop">Drop</li>
+ <li id="db-backup">Backup</li>
+ <li id="db-restore">Restore</li>
+ <li id="db-change-password">Password</li>
+ <li id="back-to-login">Back to Login</li>
+ </ul>
+</t>
+<t t-name="Database.CreateDB">
+ <form name="create_db_form" class="oe_forms" method="POST">
+ <table width="100%">
+ <tr>
+ <td class="option_string">
+ CREATE DATABASE
+ </td>
+ </tr>
+ </table>
+ <table align="center" class="db_option_table">
+ <tr>
+ <td><label for="super_admin_pwd">Master password:</label></td>
+ <td><input type="password" name="super_admin_pwd" class="required" value="admin"/></td>
+ </tr>
+ <tr>
+ <td><label for="db_name">New database name:</label></td>
+ <td><input type="text" name="db_name" class="required"/></td>
+ </tr>
+ <tr>
+ <td><label for="demo_data">Load Demonstration data:</label></td>
+ <td><input type="checkbox" name="demo_data"/></td>
+ </tr>
+ <tr>
+ <td><label for="db_lang">Default language:</label></td>
+ <td>
+ <select name="db_lang" t-if="lang_list">
+ <t t-foreach="lang_list" t-as="lang">
+ <option t-att-value="lang[0]" t-att-selected="lang[0] === 'en_US' ? 'selected' : undefined"><t t-esc="lang[1]"/></option>
+ </t>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="create_admin_pwd">Admin password:</label></td>
+ <td><input type="password" name="create_admin_pwd" class="required"/></td>
+ </tr>
+ <tr>
+ <td><label for="create_confirm_pwd">Confirm password:</label></td>
+ <td><input type="password" name="create_confirm_pwd" class="required"
+ equalTo="input[name=create_admin_pwd]"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right"><input type="submit" value="Create"/></td>
+ </tr>
+ </table>
+ </form>
+</t>
+<t t-name="DropDB">
+ <form name="drop_db_form" class="oe_forms" method="POST">
+ <table width="100%">
+ <tr>
+ <td class="option_string">
+ DROP DATABASE
+ </td>
+ </tr>
+ </table>
+ <table align="center" class="db_option_table">
+ <tr>
+ <td><label for="drop_db">Database:</label></td>
+ <td>
+ <select t-if="db_list" name="drop_db" autofocus="autofocus">
+ <t t-foreach="db_list" t-as="db">
+ <option t-att-value="db"><t t-esc="db"/></option>
+ </t>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="drop_password">Master Password:</label></td>
+ <td><input type="password" name="drop_pwd" class="required"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right"><input type="submit" value="Drop"/></td>
+ </tr>
+ </table>
+ </form>
+</t>
+<t t-name="BackupDB">
+ <form name="backup_db_form" class="oe_forms" method="POST" target="backup-target"
+ action="/web/database/backup">
+ <input type="hidden" name="token"/>
+ <table width="100%">
+ <tr>
+ <td class="option_string">
+ BACKUP DATABASE
+ </td>
+ </tr>
+ </table>
+ <table align="center" class="db_option_table">
+ <tr>
+ <td><label for="backup_db">Database:</label></td>
+ <td>
+ <select t-if="db_list" name="backup_db" autofocus="autofocus">
+ <t t-foreach="db_list" t-as="db">
+ <option t-att-value="db"><t t-esc="db"/></option>
+ </t>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="backup_pwd">Master Password:</label></td>
+ <td><input type="password" name="backup_pwd" class="required"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right"><input type="submit" value="Backup"/></td>
+ </tr>
+ </table>
+ </form>
+</t>
+<t t-name="RestoreDB">
+ <form name="restore_db_form" class="oe_forms" method="POST">
+ <table width="100%">
+ <tr>
+ <td class="option_string">
+ RESTORE DATABASE
+ </td>
+ </tr>
+ </table>
+ <table align="center" class="db_option_table">
+ <tr>
+ <td><label for="restore_db">File:</label></td>
+ <td><input type="file" name="db_file" class="required"
+ autofocus="autofocus"/></td>
+ </tr>
+ <tr>
+ <td><label for="restore_pwd">Master Password:</label></td>
+ <td><input type="password" name="restore_pwd" class="required"/></td>
+ </tr>
+ <tr>
+ <td><label for="new_db">New database name:</label></td>
+ <td><input type="text" name="new_db" class="required"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right"><input type="submit" value="Restore"/></td>
+ </tr>
+ </table>
+ </form>
+</t>
+<t t-name="Change_DB_Pwd">
+ <form name="change_pwd_form" class="oe_forms" method="POST">
+ <table width="100%">
+ <tr>
+ <td class="option_string">
+ CHANGE MASTER PASSWORD
+ </td>
+ </tr>
+ </table>
+ <table align="center" class="db_option_table">
+ <tr>
+ <td><label for="old_pwd">Master password:</label></td>
+ <td><input type="password" name="old_pwd" class="required"
+ minlength="1" autofocus="autofocus"/></td>
+ </tr>
+ <tr>
+ <td><label for="new_pwd">New master password:</label></td>
+ <td><input type="password" name="new_pwd" class="required"
+ minlength="1"/></td>
+ </tr>
+ <tr>
+ <td><label for="confirm_pwd">Confirm new master password:</label></td>
+ <td><input type="password" name="confirm_pwd" class="required"
+ equalTo="input[name=new_pwd]" minlength="1"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right"><input type="submit" value="Change Password"/></td>
+ </tr>
+ </table>
+ </form>
+</t>
+<t t-name="Login">
+ <form class="oe_forms">
+ <fieldset>
+ <legend style="">
+ <img src="/web/static/src/img/stock_person.png" alt="" />
+ </legend>
+ <div class="oe_box2">
+ <table align="center" cellspacing="2px" cellpadding="0">
+ <tr>
+ <td><label for="db">Database:</label></td>
+ <td>
+ <t t-if="!db_list">
+ <input type="text" name="db" t-att-value="selected_db || ''" autofocus="true"/>
+ </t>
+ <t t-if="db_list">
+ <select name="db">
+ <t t-foreach="db_list" t-as="db">
+ <t t-if="selected_db === db">
+ <option t-att-value="db" selected="true">
+ <t t-esc="db"/></option>
+ </t>
+ <t t-if="selected_db !== db">
+ <option t-att-value="db"><t t-esc="db"/></option>
+ </t>
+ </t>
+ </select>
+ </t>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="login">User:</label></td>
+ <td><input type="text" name="login"
+ t-att-value="selected_login || ''" autofocus="true"/></td>
+ </tr>
+ <tr>
+ <td><label for="password">Password:</label></td>
+ <td><input type="password" name="password"
+ t-att-value="selected_password || ''"/></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>
+ <button type="button" id="oe-db-config">Database</button>
+ <button type="submit" name="submit">Login</button>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ <div class="login_error_message">Bad username or password</div>
+ </form>
+ <div class="oe_login_right_pane">
+ <p>We think that daily job activities can be more intuitive, efficient, automated, .. and even fun.</p>
+ <h3>OpenERP's vision to be:</h3>
+
+ <table cellpadding="0" cellspacing="0" width="100%" style="border:none;">
+ <tbody>
+ <tr>
+ <td>
+ <img src="/web/static/src/img/product.png"/>
+ </td>
+ <td>
+ <strong>Full featured</strong><br />
+ Today's enterprise challenges are multiple. We provide one module for each need.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <img src="/web/static/src/img/accessories-archiver.png"/>
+ </td>
+ <td>
+ <strong>Open Source</strong><br />
+ To Build a great product, we rely on the knowledge of thousands of contributors.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <img src="/web/static/src/img/partner.png" />
+ </td>
+ <td>
+ <strong>User Friendly</strong><br />
+ In order to be productive, people need clean and easy to use interface.
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+</t>
+<t t-name="Header">
+ <div>
+ <a t-att-href="'/' + widget.qs" class="company_logo_link">
+ <div class="company_logo" />
+ </a>
+ </div>
+</t>
+<t t-name="Header-content">
+ <h1 class="header_title">
+ <t t-esc="user.company_id[1]"/> (<t t-esc="widget.session.db"/>)<br/>
+ <small class="username"><t t-esc="user.name"/></small>
+ </h1>
+ <div class="header_corner">
+ <ul class="block">
+ <li>
+ <a t-att-href="'/' + widget.qs" title="Home" class="home"><img src="/web/static/src/img/header-home.png" width="16" height="16" border="0"/></a>
+ </li>
+ <!--
+ <li>
+ <a href="#requests" title="Requests" class="requests"><img src="/web/static/src/img/header-requests.png" width="16" height="16" border="0"/><small>1</small></a>
+ </li>
+ -->
+ <li class="preferences">
+ <a href="#preferences" title="Preferences" class="preferences"><img src="/web/static/src/img/header-preferences.png" width="16" height="16" border="0"/></a>
+ </li>
+ <li>
+ <a href="#about" title="About" class="about"><img src="/web/static/src/img/header-about.png" width="16" height="16" border="0"/></a>
+ </li>
+ <!--
+ <li>
+ <a href="http://doc.openerp.com/v6.0/book?version=$version" title="Help" target="_blank" class="help"><img src="/web/static/src/img/header-help.png" width="16" height="16" border="0"/></a>
+ </li>
+ -->
+ </ul>
+ <div class="block">
+ <a href="#logout" class="logout">LOGOUT</a>
+ </div>
+
+ </div>
+ <div class="oe-shortcuts"> </div>
+</t>
+<ul t-name="Shortcuts">
+ <li t-foreach="shortcuts" t-as="shortcut"
+ t-att-data-id="shortcut.res_id"
+ t-att-data-shortcut-id="shortcut.id"
+ ><t t-esc="shortcut.name"/></li>
+</ul>
+<t t-name="Menu">
+ <table align="center">
+ <tr>
+ <t t-foreach="data.children" t-as="menu">
+ <td>
+ <a href="#" t-att-data-menu="menu.id">
+ <t t-esc="menu.name"/>
+ </a>
+ </td>
+ </t>
+ </tr>
+ </table>
+</t>
+<t t-name="Menu.secondary">
+ <div style="display: none" class="menu_accordion" t-att-data-menu-parent="menu.id">
+ <t t-foreach="menu.children" t-as="menu">
+ <t t-set="header">h3</t>
+ <t t-call="Menu.secondary.children"/>
+ </t>
+ </div>
+</t>
+<t t-name="Menu.secondary.children">
+ &lt;<t t-esc="header"/>&gt;
+ <a href="#" t-attf-id="menu_#{menu.id}">
+ <span><t t-esc="menu.name"/></span>
+ </a>
+ &lt;/<t t-esc="header"/>&gt;
+ <div class="menu_content">
+ <t t-foreach="menu.children" t-as="menu">
+ <t t-if="!menu.children.length">
+ <a href="#" class="leaf" t-att-data-menu="menu.id">
+ <span><t t-esc="menu.name"/></span>
+ </a>
+ </t>
+ <t t-if="menu.children.length">
+ <div class="submenu_accordion">
+ <t t-call="Menu.secondary.children">
+ <t t-set="header">h4</t>
+ </t>
+ </div>
+ </t>
+ </t>
+ </div>
+</t>
+<t t-name="ViewManager">
+ <table class="view-manager-main-table">
+ <tr>
+ <td class="view-manager-main-content">
+ <div class="oe_vm_switch">
+ <t t-if="views.length != 1" t-foreach="views" t-as="view">
+ <button type="button" t-att-data-view-type="view.view_type">
+ <t t-esc="view.view_type"/>
+ </button>
+ </t>
+ </div>
+ <div t-attf-id="#{prefix}_search" t-opentag="true"/>
+ <t t-foreach="views" t-as="view">
+ <div t-attf-id="#{prefix}_view_#{view.view_type}"/>
+ </t>
+ </td>
+ <td class="view-manager-main-sidebar" height="100%">
+ <t t-foreach="views" t-as="view">
+ <div t-attf-id="#{prefix}_sidebar_#{view.view_type}" class="sidebar-main-div closed-sidebar" style="display: none"/>
+ </t>
+ </td>
+ </tr>
+ </table>
+</t>
+
+<t t-extend="ViewManager" t-name="ViewManagerAction">
+ <t t-jquery=".view-manager-main-content" t-operation="prepend">
+ <a class="oe-shortcut-toggle" title="Add / Remove Shortcut..."
+ href="javascript: void(0)"> </a>
+ </t>
+</t>
+
+<t t-name="Sidebar">
+ <a class="toggle-sidebar"></a>
+ <div class="sidebar-content">
+ <div class="sidebar-actions">
+ </div>
+ </div>
+</t>
+<t t-name="Sidebar.section">
+ <h2><t t-esc="name"/></h2>
+ <div t-att-id="section_id" t-att-class="classname">
+ <ul t-if="items">
+ <li t-foreach="items" t-as="item" t-att-class="item.classname">
+ <a class="oe_sidebar_action_a" t-att-id="item.element_id" t-att-title="item.title" href="#">
+ <t t-esc="item.label"/>
+ </a>
+ </li>
+ </ul>
+ </div>
+</t>
+<t t-name="TranslateDialog">
+ <ul class="oe_translate_tabs">
+ <li><a t-attf-href="##{widget.element_id}_fields">Fields</a></li>
+ <li><a t-attf-href="##{widget.element_id}_view">View labels</a></li>
+ <li><a t-attf-href="##{widget.element_id}_sidebar">Sidebar Relates</a></li>
+ </ul>
+ <div t-attf-id="#{widget.element_id}_fields">
+ <table t-if="widget.view.translatable_fields" class="oe_frame oe_forms oe_translation_form" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td class="oe_form_separator" width="1%" nowrap="nowrap">
+ <div class="separator horizontal">Field</div>
+ </td>
+ <th t-foreach="widget.languages" align="left">
+ <div class="separator horizontal"><t t-esc="name"/></div>
+ </th>
+ </tr>
+ <tr t-foreach="widget.view.translatable_fields" t-as="field">
+ <td class="oe_form_frame_cell" width="1%" nowrap="nowrap">
+ <label class="oe_label"><t t-esc="field.string"/>:</label>
+ </td>
+ <td t-foreach="widget.languages" t-as="lg" class="oe_form_frame_cell">
+ <input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" data-value="" class="oe_trad_field" style="width: 100%"/>
+ <textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" data-value="" class="oe_trad_field" style="width: 100%"></textarea>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div t-attf-id="#{widget.element_id}_view">
+ Translate view
+ </div>
+ <div t-attf-id="#{widget.element_id}_sidebar">
+ Translate sidebar
+ </div>
+</t>
+<t t-name="TreeView">
+ <h2 class="oe_view_title"><t t-esc="title"/></h2>
+ <select t-if="toolbar" style="width: 30%">
+ </select>
+ <table class="oe-treeview-table">
+ <thead>
+ <tr>
+ <th t-foreach="fields_view" t-as="field"
+ t-if="!field.attrs.modifiers.tree_invisible"
+ class="treeview-header">
+ <t t-esc="fields[field.attrs.name].string" />
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+ </table>
+</t>
+<tr t-name="TreeView.rows"
+ t-foreach="records" t-as="record"
+ t-att-id="'treerow_' + record.id"
+ t-att-data-id="record.id" t-att-data-level="level + 1">
+ <t t-set="children" t-value="record[children_field]"/>
+ <t t-set="has_children" t-value="children and children.length"/>
+
+ <td t-foreach="fields_view" t-as="field"
+ t-if="!field.attrs.modifiers.tree_invisible"
+ t-att-data-id="record.id"
+ t-att-style="!field_index ? 'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px' : undefined"
+ t-att-class="!field_index and has_children ? 'treeview-tr' : 'treeview-td'">
+ <span t-if="!field.attrs.modifiers.invisible">
+ <t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" />
+ </span>
+ </td>
+</tr>
+<table t-name="ListView" class="oe-listview-content">
+ <t t-set="columns_count" t-value="visible_columns.length + (options.selectable ? 1 : 0) + (options.deletable ? 1 : 0)"/>
+ <thead class="ui-widget-header">
+ <tr t-if="options.action_buttons !== false or options.pager !== false">
+ <th t-att-colspan="columns_count">
+ <table>
+ <tr>
+ <td t-if="options.action_buttons !== false" class="oe-actions">
+ <button type="button" class="oe-list-add"
+ t-if="options.addable">
+ <t t-esc="options.addable"/>
+ </button>
+ <button type="button" class="oe-list-delete"
+ t-if="options.selectable and options.deletable">
+ Delete
+ </button>
+ </td>
+ <th t-if="options.pager !== false" class="oe-list-pager">
+ <button type="button" disabled="disabled"
+ data-pager-action="first">First</button>
+ <button type="button" disabled="disabled"
+ data-pager-action="previous"
+ >&lt;</button>
+
+ <span class="oe-pager-state">
+ </span>
+
+ <button type="button" disabled="disabled"
+ data-pager-action="next">&gt;</button>
+ <button type="button" disabled="disabled"
+ data-pager-action="last">Last</button>
+ </th>
+ </tr>
+ </table>
+ </th>
+ </tr>
+ <tr t-if="options.header" class="oe-listview-header-columns">
+ <t t-foreach="columns" t-as="column">
+ <th t-if="column.meta">
+ <t t-esc="column.string"/>
+ </th>
+ </t>
+ <th t-if="options.selectable" width="1"/>
+ <t t-foreach="columns" t-as="column">
+ <th t-if="!column.meta and column.invisible !== '1'" t-att-data-id="column.id"
+ t-att-class="((options.sortable and column.tag !== 'button') ? 'oe-sortable' : null)">
+ <t t-if="column.tag !== 'button'"
+ ><t t-esc="column.string"/></t>
+ </th>
+ </t>
+ <th t-if="options.deletable" width="1"/>
+ </tr>
+ </thead>
+ <tfoot class="ui-widget-header">
+ <tr>
+ <td t-if="options.selectable"/>
+ <td t-foreach="aggregate_columns" t-as="column" class="oe-list-footer oe-number"
+ t-att-data-field="column.id" t-att-title="column.label">
+ </td>
+ <td t-if="options.deletable"/>
+ </tr>
+ </tfoot>
+</table>
+<t t-name="ListView.rows" t-foreach="records.length" t-as="index">
+ <t t-call="ListView.row">
+ <t t-set="record" t-value="records.at(index)"/>
+ <t t-set="row_parity" t-value="index_parity"/>
+ </t>
+</t>
+<tr t-name="ListView.row" t-att-class="row_parity"
+ t-att-data-id="record.get('id')">
+ <t t-foreach="columns" t-as="column">
+ <td t-if="column.meta">
+
+ </td>
+ </t>
+ <t t-if="options.radio">
+ <th t-if="options.selectable" class="oe-record-selector" width="1">
+ <input type="radio" name ="radiogroup"/>
+ </th>
+ </t>
+ <t t-if="!options.radio">
+ <th t-if="options.selectable" class="oe-record-selector" width="1">
+ <input type="checkbox"/>
+ </th>
+ </t>
+
+
+ <t t-foreach="columns" t-as="column">
+ <t t-set="align" t-value="column.type === 'integer' or column.type == 'float'"/>
+ <td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help"
+ t-att-class="'oe-field-cell' + (align ? ' oe-number' : '')"
+ t-att-data-field="column.id">
+ <t t-raw="render_cell(record.toForm().data, column)"/>
+ </td>
+ </t>
+ <td t-if="options.deletable" class='oe-record-delete' width="1">
+ <button type="button" name="delete">♻</button>
+ </td>
+</tr>
+<t t-name="ListView.row.form">
+ <t t-raw="frame.render()"/>
+</t>
+<t t-name="FormView">
+ <div class="oe_form_header" t-att-id="view.element_id + '_header'">
+ <h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/> <button t-if="view.session.debug" class="oe_get_xml_view">View#<t t-esc="view.fields_view.view_id"/></button></h2>
+ <div class="oe_form_buttons" t-if="view.options.action_buttons !== false">
+ <!--<button type="button" class="oe_form_button_save">
+ <span class="oe_form_on_update">Save</span>
+ <span class="oe_form_on_create">Create</span>
+ </button>-->
+ <button type="button" class="oe_form_button_save_edit">
+ <span class="oe_form_on_update">Save &amp; Edit</span>
+ <span class="oe_form_on_create">Create &amp; Edit</span>
+ </button>
+ <!--<button type="button" class="oe_form_button_cancel">Cancel</button>-->
+ <button type="button" class="oe_form_button_new">New</button>
+ </div>
+ <div class="oe_form_pager" t-if="view.options.pager !== false">
+ <button type="button" data-pager-action="first">First</button>
+ <button type="button" data-pager-action="previous">&lt;&lt;</button>
+
+ <span class="oe_pager_index">0</span> / <span class="oe_pager_count">0</span>
+
+ <button type="button" data-pager-action="next">&gt;&gt;</button>
+ <button type="button" data-pager-action="last">Last</button>
+ </div>
+ </div>
+ <t t-raw="frame.render()"/>
+</t>
+<t t-name="FormView.sidebar.attachments">
+ <div class="oe-sidebar-attachments-toolbar">
+ <div class="oe-binary-file-set" style="float: right">
+ <form class="oe-binary-form" t-attf-target="#{element_id}_iframe"
+ method="post" enctype="multipart/form-data" action="/web/binary/upload_attachment">
+ <input type="hidden" name="session_id" t-att-value="session.session_id"/>
+ <input type="hidden" name="callback" t-attf-value="#{element_id}_iframe"/>
+ <input type="hidden" name="model" t-att-value="view.dataset.model"/>
+ <input type="hidden" name="id" t-att-value="view.datarecord.id"/>
+ <button class="button" type="button">
+ <img src="/web/static/src/img/throbber.gif" width="16" height="16" style="display: none"/>
+ <span>Add</span>
+ </button>
+ <input type="file" class="oe-binary-file" name="ufile" title="Add attachment"
+ t-att-onclick="view.datarecord.id ? null : 'alert(\'No record selected ! You can only attach to existing record.\'); return false;'"/>
+ </form>
+ <iframe t-attf-id="#{element_id}_iframe" t-attf-name="#{element_id}_iframe" style="display: none"> </iframe>
+ </div>
+ </div>
+ <br style="clear: both"/>
+ <ul class="oe-sidebar-attachments-items">
+ <li t-foreach="attachments" t-as="attachment">
+ <t t-if="attachment.type == 'binary'" t-set="attachment.url" t-value="'/web/binary/saveas?session_id='
+ + session.session_id + '&amp;model=ir.attachment&amp;id=' + attachment.id
+ + '&amp;field=datas&amp;fieldname=name&amp;t=' + (new Date().getTime())"/>
+ <a class="oe-sidebar-attachments-link" t-att-href="attachment.url" target="_blank">
+ <t t-esc="attachment.name"/>
+ </a>
+ <a href="#" class="oe-sidebar-attachment-delete" t-att-data-id="attachment.id" t-attf-title="Delete the attachment #{attachment.name}">
+ <img src="/web/static/src/img/attachments-close.png" width="15" height="15" border="0"/>
+ </a>
+ </li>
+ </ul>
+</t>
+<t t-name="Widget">
+ Unhandled widget
+ <t t-raw="console.log('Unhandled widget', widget)"/>
+</t>
+<t t-name="WidgetFrame">
+ <table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame oe_forms">
+ <tr t-foreach="widget.table" t-as="row">
+ <t t-foreach="row" t-as="td">
+ <td t-att-colspan="td.colspan gt 1 ? td.colspan : undefined"
+ t-att-width="td.width"
+ t-att-nowrap="td.nowrap or td.is_field_m2o? 'true' : undefined"
+ t-att-valign="td.table ? 'top' : undefined"
+ t-att-id="td.element_id"
+ t-attf-class="oe_form_frame_cell #{td.classname}"
+ >
+ <t t-raw="td.render()"/>
+ </td>
+ </t>
+ </tr>
+ </table>
+</t>
+<t t-name="WidgetNotebook">
+ <ul>
+ <li t-foreach="widget.pages" t-as="page" t-att-id="page.element_tab_id">
+ <a t-att-href="'#' + page.element_id">
+ <t t-esc="page.string"/>
+ </a>
+ </li>
+ </ul>
+ <t t-foreach="widget.pages" t-as="page">
+ <t t-raw="page.render()"/>
+ </t>
+</t>
+<t t-name="WidgetNotebookPage">
+ <div t-att-id="widget.element_id">
+ <t t-call="WidgetFrame"/>
+ </div>
+</t>
+<t t-name="WidgetSeparator">
+ <div t-if="widget.orientation !== 'vertical'" t-att-class="'separator ' + widget.orientation">
+ <t t-esc="widget.string"/>
+ </div>
+</t>
+<t t-name="WidgetLabel">
+ <label t-att-for="widget.element_id + '_field'"
+ t-att-class="'oe_label' + (widget.help ? '_help' : '')"
+ t-att-title="widget.help">
+ <t t-esc="widget.string"/>
+ <span t-if="widget.help">?</span>
+ <t t-if="widget.string and widget.node.tag != 'label'">:</t>
+ </label>
+</t>
+<t t-name="WidgetParagraph">
+ <p class="oe_form_paragraph"><t t-esc="widget.string"/></p>
+</t>
+<t t-name="FieldChar">
+ <input type="text" size="1"
+ t-att-name="widget.name"
+ t-att-id="widget.element_id + '_field'"
+ t-att-class="'field_' + widget.type"
+ t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
+ />
+ <img class="oe_field_translate" t-if="widget.field.translate" src="/web/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/>
+</t>
+<t t-name="FieldEmail">
+ <table cellpadding="0" cellspacing="0" border="0" width="100%">
+ <tr>
+ <td width="100%">
+ <t t-call="FieldChar"/>
+ </td>
+ <td width="16">
+ <button type="button" class="button" title="Send an e-mail with your default e-mail client">
+ <img src="/web/static/src/img/icons/terp-mail-message-new.png"/>
+ </button>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="FieldUrl">
+ <table cellpadding="0" cellspacing="0" border="0" width="100%">
+ <tr>
+ <td width="100%">
+ <t t-call="FieldChar"/>
+ </td>
+ <td width="16">
+ <button type="button" class="button" title="Open this resource">
+ <img src="/web/static/src/img/icons/gtk-ok.png"/>
+ </button>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="FieldText">
+ <textarea rows="6"
+ t-att-name="widget.name"
+ t-att-id="widget.element_id + '_field'"
+ t-att-class="'field_' + widget.type"
+ t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
+ ></textarea>
+ <img class="oe_field_translate" t-if="widget.field.translate" src="/web/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/>
+</t>
+<t t-name="FieldDate">
+ <input type="text" size="1" style="width: 100%"
+ t-att-name="widget.name"
+ t-att-id="widget.element_id + '_field'"
+ t-att-class="'field_' + widget.type"
+ />
+</t>
+<t t-name="FieldSelection">
+ <select
+ t-att-name="widget.name"
+ t-att-id="widget.element_id + '_field'"
+ t-att-class="'field_' + widget.type"
+ style="width: 100%">
+ <t t-foreach="widget.values" t-as="option">
+ <option><t t-esc="option[1]"/></option>
+ </t>
+ </select>
+</t>
+<t t-name="FieldMany2One">
+ <div t-att-id="widget.element_id" class="oe-m2o">
+ <input t-att-id="widget.element_id + '_input'" type="text" size="1" style="width: 100%;"/>
+ <span class="oe-m2o-drop-down-button" t-att-id="widget.element_id + '_drop_down'">
+ <img src="/web/static/src/img/down-arrow.png" /></span>
+ <span class="oe-m2o-cm-button" t-att-id="widget.name + '_open'">
+ <img src="/web/static/src/img/icons/gtk-index.png"/></span>
+ <div t-att-id="widget.cm_id" class="contextMenu" style="display:none">
+ </div>
+ </div>
+</t>
+<t t-name="FieldMany2One.context_menu">
+ <ul>
+ <li t-att-id="widget.cm_id + '_open'" style="color:grey">Open...</li>
+ <li t-att-id="widget.cm_id + '_create'">Create...</li>
+ <li t-att-id="widget.cm_id + '_search'" class="oe_m2o_menu_item_mandatory">Search...</li>
+ <t t-set="i" t-value="0"/>
+ <t t-foreach="widget.related_entries" t-as="entry">
+ <li t-att-id="widget.cm_id + '_related_' + i" style="color:grey" class="oe_m2o_menu_item_mandatory">
+ ... <t t-esc="(entry[2] || {})['name'] || ''"/>
+ </li>
+ <t t-set="i" t-value="i+1"/>
+ </t>
+ </ul>
+</t>
+<t t-name="FieldOne2Many">
+ <div t-att-id="widget.element_id">
+ </div>
+</t>
+<t t-name="FieldMany2Many">
+ <div t-att-id="widget.list_id"></div>
+</t>
+<t t-name="FieldReference">
+ <table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame oe_forms">
+ <tr>
+ <td t-att-id="widget.selection.element_id" class="oe_form_frame_cell oe_form_selection">
+ <t t-raw="widget.selection.render()"/>
+ </td>
+ <td t-att-id="widget.m2o.element_id" class="oe_form_frame_cell oe_form_many2one" nowrap="true">
+ <t t-raw="widget.m2o.render()"/>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="FieldBoolean">
+ <input type="checkbox"
+ t-att-name="widget.name"
+ t-att-id="widget.element_id + '_field'"
+ t-att-class="'field_' + widget.type"/>
+</t>
+<t t-name="FieldProgressBar">
+ <div t-opentag="true" class="oe-progressbar">
+ <span></span>
+ </div>
+</t>
+<t t-name="FieldBinaryImage">
+ <table cellpadding="0" cellspacing="0" border="0">
+ <tr>
+ <td align="center">
+ <img src="/web/static/src/img/placeholder.png" class="oe-binary-image"
+ t-att-border="widget.readonly ? 0 : 1"
+ t-att-id="widget.element_id + '_field'"
+ t-att-name="widget.name"
+ t-att-class="'field_' + widget.type"
+ t-att-width="widget.node.attrs.img_width || widget.node.attrs.width"
+ t-att-height="widget.node.attrs.img_height || widget.node.attrs.height"
+ />
+ </td>
+ </tr>
+ <tr>
+ <td align="center" valign="bottom" height="25">
+ <div class="oe-binary">
+ <table cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td>
+ <div class="oe-binary-file-set" style="width: 40px; height:22px;">
+ <form class="oe-binary-form" t-att-target="widget.iframe"
+ method="post" enctype="multipart/form-data" action="/web/binary/upload">
+ <input type="hidden" name="session_id" value=""/>
+ <input type="hidden" name="callback" t-att-value="widget.iframe"/>
+ <button class="button" type="button" title="Set Image">
+ <img src="/web/static/src/img/icons/STOCK_DIRECTORY.png"/>
+ </button>
+ <input type="file" class="oe-binary-file" name="ufile"/>
+ </form>
+ </div>
+ </td>
+ <td>
+ <button class="button oe-binary-file-clear" type="button" title="Clear">
+ <img src="/web/static/src/img/icons/STOCK_MISSING_IMAGE.png"/>
+ </button>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="oe-binary-progress" style="display: none">
+ <img src="/web/static/src/img/throbber.gif" width="16" height="16"/>
+ <b>Uploading ...</b>
+ </div>
+ <iframe t-att-id="widget.iframe" t-att-name="widget.iframe" style="display: none"> </iframe>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="FieldBinaryFile">
+ <table cellpadding="0" cellspacing="0" border="0" width="100%">
+ <tr>
+ <td width="100%">
+ <input type="text" size="1"
+ t-att-name="widget.name"
+ t-att-id="widget.element_id + '_field'"
+ t-att-class="'field_' + widget.type" style="width: 100%"
+ />
+ </td>
+ <td class="oe-binary" nowrap="true">
+ <table cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td>
+ <div class="oe-binary-file-set" style="width: 80px; height:22px;">
+ <form class="oe-binary-form" t-att-target="widget.iframe"
+ method="post" enctype="multipart/form-data" action="/web/binary/upload">
+ <input type="hidden" name="session_id" value=""/>
+ <input type="hidden" name="callback" t-att-value="widget.iframe"/>
+ <button class="button" type="button" title="Set Image">
+ <img src="/web/static/src/img/icons/STOCK_DIRECTORY.png"/>
+ <span>Select</span>
+ </button>
+ <input type="file" class="oe-binary-file" name="ufile"/>
+ </form>
+ </div>
+ </td>
+ <td>
+ <button class="button oe-binary-file-save" type="button" title="Save As">
+ <img src="/web/static/src/img/icons/gtk-save.png"/>
+ <span>Save As</span>
+ </button>
+ </td>
+ <td>
+ <button class="button oe-binary-file-clear" type="button" title="Clear">
+ <img src="/web/static/src/img/icons/STOCK_MISSING_IMAGE.png"/>
+ <span>Clear</span>
+ </button>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="oe-binary-progress" style="display: none" nowrap="true">
+ <img src="/web/static/src/img/throbber.gif" width="16" height="16"/>
+ <b>Uploading ...</b>
+ <iframe t-att-id="widget.iframe" t-att-name="widget.iframe" style="display: none"> </iframe>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="WidgetButton">
+ <button type="button"
+ t-att-id="widget.element_id + '_button'"
+ t-att-title="widget.help"
+ style="width: 100%" class="button">
+ <img t-if="widget.node.attrs.icon" t-att-src="'/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/>
+ <span t-if="widget.string"><t t-esc="widget.string"/></span>
+ </button>
+</t>
+<t t-name="SearchView">
+ <h2 class="oe_view_title"><t t-esc="view.attrs['string']"/></h2>
+ <form class="oe_forms">
+ <t t-call="SearchView.render_lines"/>
+ <div class="oe_search-view-buttons" style="text-align: right;">
+ <input type="submit" value="Search"/>
+ <input type="reset" value="Clear"/>
+ <button class="oe_search-view-custom-filter-btn"><span>Advanced Filter</span></button>
+ <select class="oe_search-view-filters-management">
+ </select>
+ </div>
+ </form>
+</t>
+<t t-name="SearchView.managed-filters">
+ <option value="_filters">-- Filters --</option>
+ <t t-set="i" t-value="0"/>
+ <t t-foreach="filters" t-as="filter">
+ <option t-att-value="'get:' + i"><t t-esc="filter.name"/></option>
+ <t t-set="i" t-value="i+1"/>
+ </t>
+ <option value="_actions">-- Actions --</option>
+ <option value="save_filter">Save Filter</option>
+ <option value="manage_filters">Manage Filters</option>
+</t>
+<t t-name="SearchView.managed-filters.add">
+ <div>
+ <p>Filter Name:</p>
+ <input type="text"/>
+ <p>(Any existing filter with the same name will be replaced)</p>
+ </div>
+</t>
+<t t-name="SearchView.render_lines">
+ <table class="oe-searchview-render-line" border="0" cellspacing="0" cellpadding="0"
+ t-foreach="lines" t-as="line">
+ <tr>
+ <td t-foreach="line" t-as="widget">
+ <t t-raw="widget.render(defaults)"/>
+ </td>
+ </tr>
+ </table>
+</t>
+<button t-name="SearchView.filter" type="button"
+ t-att-id="element_id"
+ t-att-title="attrs.help"
+ t-att-class="classes.join(' ')"
+ t-att-autofocus="attrs.default_focus === '1' ? 'autofocus' : undefined">
+ <img t-if="attrs.icon" t-att-src="'/web/static/src/img/icons/' + attrs.icon + '.png'" width="16" height="16"/>
+ <br t-if="attrs.icon and attrs.string"/>
+ <t t-esc="attrs.string"/>
+</button>
+<span t-name="SearchView.filters" class="filter_label_group"
+ ><t t-foreach="filters" t-as="filter"
+ ><t t-raw="filter.render(defaults)"/></t
+></span>
+<t t-name="SearchView.field">
+ <label t-att-class="'oe_label' + (attrs.help ? '_help' : '')"
+ t-att-title="attrs.help"
+ t-att-for="element_id">
+ <t t-esc="attrs.string || attrs.name"/>
+ <span t-if="attrs.help">?</span>
+ </label>
+ <div style="white-space: nowrap;">
+ <input type="text" size="15" t-att-name="attrs.name"
+ t-att-autofocus="attrs.default_focus === '1' ? 'autofocus' : undefined"
+ t-att-id="element_id"
+ t-att-value="defaults[attrs.name] || ''"/>
+ <t t-if="filters.length" t-raw="filters.render(defaults)"/>
+ </div>
+</t>
+<t t-name="SearchView.field.selection">
+ <label t-att-title="attrs.help"
+ t-att-class="'oe_label' + (attrs.help ? '_help' : '')"
+ t-att-for="element_id">
+ <t t-esc="attrs.string || attrs.name"/>
+ <span t-if="attrs.help">?</span>
+ </label>
+ <div style="white-space: nowrap;">
+ <select t-att-name="attrs.name" t-att-id="element_id"
+ t-att-autofocus="attrs.default_focus === '1' || undefined">
+ <option/>
+ <t t-foreach="attrs.selection" t-as="option">
+ <t t-set="selected" t-value="defaults[attrs.name] === option[0]"/>
+ <option t-if="selected"
+ t-att-value="option[0]" selected="selected">
+ <t t-esc="option[1]"/>
+ </option>
+ <option t-if="!selected" t-att-value="option[0]">
+ <t t-esc="option[1]"/>
+ </option>
+ </t>
+ </select>
+ <t t-if="filters.length" t-raw="filters.render(defaults)"/>
+ </div>
+</t>
+<t t-name="SearchView.util.expand">
+ <div t-att-class="'searchview_group ' + (expand == '0' ? 'folded' : 'expanded')"
+ t-att-id="element_id">
+ <a t-if="label" class="searchview_group_string" href="#">
+ <t t-esc="label"/>
+ </a>
+ <div class="searchview_group_content">
+ <t t-raw="content"/>
+ </div>
+ </div>
+</t>
+<t t-name="SearchView.group">
+ <t t-call="SearchView.util.expand">
+ <t t-set="expand" t-value="attrs.expand"/>
+ <t t-set="label" t-value="attrs.string"/>
+ <t t-set="content">
+ <t t-call="SearchView.render_lines"/>
+ </t>
+ </t>
+</t>
+<t t-name="SearchView.extended_search">
+ <t t-call="SearchView.util.expand">
+ <t t-set="expand" t-value="false"/>
+ <t t-set="label" t-value="'Advanced Filters'"/>
+ <t t-set="content">
+ <div class="searchview_extended_groups_list">
+ </div>
+ </t>
+ </t>
+</t>
+<t t-name="SearchView.extended_search.group">
+ <div t-att-id="element_id" class="searchview_extended_group">
+ <select class="searchview_extended_group_choice">
+ <option value="any">Any of the following conditions must match</option>
+ <option value="all">All the following conditions must match</option>
+ <option value="none">None of the following conditions must match</option>
+ </select>
+ <a class="searchview_extended_delete_group"
+ href="javascript:void(0)"><span></span></a>
+ <div class="searchview_extended_propositions_list">
+ </div>
+ <a class="searchview_extended_add_proposition" href="javascript:void(0)">
+ <span>Add condition</span></a>
+ <div class="oe_adv_filters_and"><span>and</span></div>
+ </div>
+</t>
+<t t-name="SearchView.extended_search.proposition">
+ <div t-att-id="element_id">
+ <select class="searchview_extended_prop_field">
+ <t t-foreach="attrs.fields" t-as="field">
+ <option t-if="typeof field.store === 'undefined' || field.store || field.fnct_search"
+ t-att="{'selected': field === attrs.selected ? 'selected' : null}"
+ t-att-value="field.name">
+ <t t-esc="field.string"/>
+ </option>
+ </t>
+ </select>
+ <select class="searchview_extended_prop_op"/>
+ <span class="searchview_extended_prop_value"/>
+ <a class="searchview_extended_delete_prop"
+ href="javascript:void(0)"><span> </span></a>
+ </div>
+</t>
+<t t-name="SearchView.extended_search.proposition.char">
+ <input t-att-id="element_id" class="field_char"/>
+</t>
+<t t-name="SearchView.extended_search.proposition.datetime">
+ <input t-att-id="element_id" class="field_datetime"/>
+</t>
+<t t-name="SearchView.extended_search.proposition.date">
+ <input t-att-id="element_id" class="field_date"/>
+</t>
+<t t-name="SearchView.extended_search.proposition.integer">
+ <input type="number" t-att-id="element_id" class="field_integer" step="1"/>
+</t>
+<t t-name="SearchView.extended_search.proposition.float">
+ <input type="number" t-att-id="element_id" class="field_float" step="0.01"/>
+</t>
+<t t-name="SearchView.extended_search.proposition.boolean">
+</t>
+<t t-name="SearchView.extended_search.proposition.selection">
+ <select t-att-id="element_id">
+ <t t-foreach="field.selection" t-as="element">
+ <option t-att-value="element[0]"><t t-esc="element[1]"/></option>
+ </t>
+ </select>
+</t>
+<t t-name="DialogWarning">
+ <table cellspacing="0" cellpadding="0" border="0" class="oe-dialog-warning">
+ <tr>
+ <td><img src="/web/static/src/img/warning.png" class="oe-dialog-icon"/></td>
+ <td>
+ <p>
+ <t t-js="d">
+ var message = d.message ? d.message : d.error.data.fault_code;
+ d.html_error = context.engine.tools.html_escape(message)
+ .replace(/\n/g, '<br/>');
+ </t>
+ <t t-raw="html_error"/>
+ </p>
+ </td>
+ </tr>
+ </table>
+</t>
+<t t-name="DialogTraceback">
+ <pre><t t-esc="error.message"/></pre>
+ <hr/>
+ <pre><t t-esc="error.data.debug"/></pre>
+</t>
+<t t-name="SelectCreatePopup">
+ <div t-att-id="element_id">
+ <table style="width:100%">
+ <tr style="width:100%">
+ <td style="width:100%">
+ <div t-att-id="element_id + '_search'" style="width:100%"></div>
+ </td>
+ </tr>
+ <tr style="width:100%">
+ <td style="width:100%">
+ <div t-att-id="element_id + '_view_list'" style="width:100%"></div>
+ </td>
+ </tr>
+ </table>
+ <div t-att-id="element_id + '_view_form'" style="width:100%"></div>
+ </div>
+</t>
+<t t-name="SelectCreatePopup.search.buttons">
+ <button type="button" class="oe_selectcreatepopup-search-select" disabled="disabled">Select</button>
+ <button type="button" class="oe_selectcreatepopup-search-close">Cancel</button>
+</t>
+<t t-name="SelectCreatePopup.form.buttons">
+ <t t-if="widget.options.disable_multiple_selection">
+ <button type="button" class="oe_selectcreatepopup-form-save">Save</button>
+ </t>
+ <t t-if="! widget.options.disable_multiple_selection">
+ <button type="button" class="oe_selectcreatepopup-form-save-new">Save &amp; New</button>
+ <button type="button" class="oe_selectcreatepopup-form-save">Save &amp; Close</button>
+ </t>
+ <button type="button" class="oe_selectcreatepopup-form-close">Cancel</button>
+</t>
+<t t-name="FormOpenPopup">
+ <div t-att-id="element_id">
+ <div t-att-id="element_id + '_view_form'" style="width:100%"></div>
+ </div>
+</t>
+<t t-name="FormOpenPopup.form.buttons">
+ <button type="button" class="oe_formopenpopup-form-save">Save</button>
+ <button type="button" class="oe_formopenpopup-form-close">Cancel</button>
+</t>
+<t t-name="ListView.row.frame" t-extend="WidgetFrame">
+ <t t-jquery="tr">
+ $(document.createElement('t'))
+ .append(this.contents())
+ .attr({
+ 't-foreach': this.attr('t-foreach'),
+ 't-as': this.attr('t-as')
+ })
+ .replaceAll(this)
+ .after($(document.createElement('td')).append(
+ $(document.createElement('button')).attr({
+ 'class': 'oe-edit-row-save', 'type': 'button'}).text('Save')))
+ .before($(document.createElement('td')).append(
+ $(document.createElement('button')).attr({
+ 'class': 'oe-edit-row-cancel', 'type': 'button'}).text('Cancel')))
+ .unwrap();
+ </t>
+</t>
+
+<t t-name="ExportView">
+ <a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a>
+</t>
+<table t-name="ExportTreeView" class="oe-export"
+ style="background-color: #F3F3F3;">
+ <tr>
+ <td colspan="3">
+ This wizard will export all data that matches the current search criteria to a CSV file.
+ You can export all data or only the fields that can be reimported after modification.
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3">
+ <label for="import_compat">Export Type:</label>
+ <select id="import_compat" name="import_compat">
+ <option value="yes">Import Compatible Export</option>
+ <option value="">Export all Data</option>
+ </select>
+
+ <label for="export_format">Export Formats</label>
+ <select id="export_format" name="export_format"></select>
+ </td>
+ </tr>
+
+ <tr>
+ <th>Available fields</th>
+ <th/>
+ <th>
+ Fields to export
+ <a style="color: blue; text-decoration: none;" href="#" id="export_new_list">Save fields list</a>
+ <div id="savenewlist"></div>
+ <div id="ExistsExportList"></div>
+ </th>
+ </tr>
+ <tr style="height: 400px;">
+ <td class="oe_export_fields_selector_left">
+ <div id="left_field_panel">
+ </div>
+ </td>
+ <td class="oe_export_fields_selector_center">
+ <button id="add_field">Add</button>
+ <button id="remove_field">Remove</button>
+ <button id="remove_all_field">Remove All</button>
+ </td>
+ <td class="oe_export_fields_selector_right">
+ <select name="fields_list" id="fields_list"
+ multiple="multiple"></select>
+ </td>
+ </tr>
+</table>
+
+<table t-name="ExportTreeView-Secondary"
+ id="field-tree-structure" class="oe_export_fields_selector_export"
+ cellspacing="0" cellpadding="0">
+ <tr><th class="oe_export_tree_header"> Name </th></tr>
+ <t t-call="ExportTreeView-Secondary.children"/>
+</table>
+<tr t-name="ExportTreeView-Secondary.children"
+ t-foreach="fields" t-as="field"
+ t-att-id="'treerow-' + field.id" class="oe_export_row">
+ <td>
+ <table class="tree_grid" border="0">
+ <tr class="oe_export_row">
+ <t t-foreach="(field.id).split('/')" t-as="level" >
+ <t t-if="(field.id).split('/')[0] != level">
+ <td width="18">&amp;nbsp;</td>
+ </t>
+ </t>
+ <td valign="top" align="left" style="cursor: pointer;" width="18">
+ <t t-if="field.children">
+ <t t-if="(field.id).split('/').length != 3">
+ <img t-att-id="'parentimg-' + field.id" src="/web/static/src/img/expand.gif" width="16" height="16" border="0"/>
+ </t>
+ </t>
+ </td>
+ <td id="tree-column" valign="middle" align="left" style="cursor: pointer;">
+ <a t-att-id="'export-' + field.id" t-att-string="field.string" href="javascript: void(0);" style="text-decoration: none;">
+ <t t-esc="field.string"/>
+ </a>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<t t-name="ExportNewList">
+ <tr>
+ <th><label>Save as:</label></th>
+ <td><input size="10" type="text" id="savelist_name"/></td>
+ <td><button class="oe_export_button_export" id="add_export_list">Ok</button></td>
+ </tr>
+</t>
+
+<t t-name="Exists.ExportList">
+ <label for="saved_export_list">Saved exports:</label>
+
+ <select id="saved_export_list">
+ <option></option>
+ <t t-foreach="existing_exports" t-as="export">
+ <option t-att-value="export.id"><t t-esc="export.name"/></option>
+ </t>
+ </select>
+ <button class="oe_export_button_export" id="delete_export_list" type="button">Delete</button>
+</t>
+<t t-name="Change_Pwd">
+ <form name="change_password_form" class="oe_forms" method="POST">
+ <table align="center">
+ <tr>
+ <td><label for="old_pwd">Old Password:</label></td>
+ <td><input type="password" name="old_pwd"
+ minlength="1" autofocus="autofocus"/></td>
+ </tr>
+ <tr>
+ <td><label for="new_password">New Password:</label></td>
+ <td><input type="password" name="new_password"
+ minlength="1" autofocus="autofocus"/></td>
+ </tr>
+ <tr>
+ <td><label for="confirm_pwd">Confirm Password:</label></td>
+ <td><input type="password" name="confirm_pwd"
+ minlength="1"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right"><input type="submit" value="Change Password"/></td>
+ </tr>
+ </table>
+ </form>
+</t>
+<t t-name="About-Page">
+ <div>
+ <h1>OpenERP Web</h1>
+ <h3 style="padding:0 5px 5px">Version <t t-esc="version_info.version"/></h3>
+ <p>
+ Copyright © 2011-TODAY OpenERP SA. All Rights Reserved.<br />
+ OpenERP is a trademark of the <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP SA Company</a>.
+ </p>
+ <p>
+ Licenced under the terms of <a target="_blank" href="http://www.gnu.org/licenses/agpl.html" style="text-decoration: underline;">GNU Affero General Public License</a>
+ </p>
+ <br />
+ <h1>About OpenERP</h1>
+ <p>
+ <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP</a> is a free enterprise-scale software system that is designed to boost
+ productivity and profit through data integration. It connects, improves and
+ manages business processes in areas such as sales, finance, supply chain,
+ project management, production, services, CRM, etc...
+ </p>
+ <p>
+ The system is platform-independent, and can be installed on Windows, Mac OS X,
+ and various Linux and other Unix-based distributions. Its architecture enables
+ new functionality to be rapidly created, modifications to be made to a
+ production system and migration to a new version to be straightforward.
+ </p>
+ <p>
+ Depending on your needs, OpenERP is available through a web or application client.
+ </p>
+ </div>
+</t>
+<t t-name="FieldStatus">
+ <div t-att-id="widget.element_id"></div>
+</t>
+<t t-name="FieldStatus.content">
+ <ul class="oe-arrow-list">
+ <t t-set="size" t-value="widget.to_show.length"/>
+ <t t-foreach="_.range(size)" t-as="i">
+ <li t-att-class="widget.to_show[i][0] === widget.selected_value ? 'oe-arrow-list-selected' : ''">
+ <span class="oe-arrow-list-before" t-if="i &gt; 0"></span><span><t t-esc="widget.to_show[i][1]"/></span><span class="oe-arrow-list-after" t-if="i &lt; size - 1"></span>
+ </li>
+ </t>
+ </ul>
+</t>
+</templates>
diff --git a/addons/web/static/test/class.js b/addons/web/static/test/class.js
new file mode 100644
index 00000000000..ed977635a5f
--- /dev/null
+++ b/addons/web/static/test/class.js
@@ -0,0 +1,138 @@
+$(document).ready(function () {
+ var openerp;
+ module('web-class', {
+ setup: function () {
+ openerp = window.openerp.init();
+ window.openerp.web.core(openerp);
+ }
+ });
+ test('Basic class creation', function () {
+ var C = openerp.web.Class.extend({
+ foo: function () {
+ return this.somevar;
+ }
+ });
+ var instance = new C();
+ instance.somevar = 3;
+
+ ok(instance instanceof C);
+ strictEqual(instance.foo(), 3);
+ });
+ test('Class initialization', function () {
+ var C1 = openerp.web.Class.extend({
+ init: function () {
+ this.foo = 3;
+ }
+ });
+ var C2 = openerp.web.Class.extend({
+ init: function (arg) {
+ this.foo = arg;
+ }
+ });
+
+ var i1 = new C1(),
+ i2 = new C2(42);
+
+ strictEqual(i1.foo, 3);
+ strictEqual(i2.foo, 42);
+ });
+ test('Inheritance', function () {
+ var C0 = openerp.web.Class.extend({
+ foo: function () {
+ return 1;
+ }
+ });
+ var C1 = C0.extend({
+ foo: function () {
+ return 1 + this._super();
+ }
+ });
+ var C2 = C1.extend({
+ foo: function () {
+ return 1 + this._super();
+ }
+ });
+
+ strictEqual(new C0().foo(), 1);
+ strictEqual(new C1().foo(), 2);
+ strictEqual(new C2().foo(), 3);
+ });
+ test('In-place extension', function () {
+ var C0 = openerp.web.Class.extend({
+ foo: function () {
+ return 3;
+ },
+ qux: function () {
+ return 3;
+ },
+ bar: 3
+ });
+ C0.include({
+ foo: function () {
+ return 5;
+ },
+ qux: function () {
+ return 2 + this._super();
+ },
+ bar: 5,
+ baz: 5
+ });
+
+ strictEqual(new C0().bar, 5);
+ strictEqual(new C0().baz, 5);
+ strictEqual(new C0().foo(), 5);
+ strictEqual(new C0().qux(), 5);
+ });
+ test('In-place extension and inheritance', function () {
+ var C0 = openerp.web.Class.extend({
+ foo: function () { return 1; },
+ bar: function () { return 1; }
+ });
+ var C1 = C0.extend({
+ foo: function () { return 1 + this._super(); }
+ });
+ strictEqual(new C1().foo(), 2);
+ strictEqual(new C1().bar(), 1);
+
+ C1.include({
+ foo: function () { return 2 + this._super(); },
+ bar: function () { return 1 + this._super(); }
+ });
+ strictEqual(new C1().foo(), 4);
+ strictEqual(new C1().bar(), 2);
+ });
+ test('In-place extensions alter existing instances', function () {
+ var C0 = openerp.web.Class.extend({
+ foo: function () { return 1; },
+ bar: function () { return 1; }
+ });
+ var instance = new C0();
+ strictEqual(instance.foo(), 1);
+ strictEqual(instance.bar(), 1);
+
+ C0.include({
+ foo: function () { return 2; },
+ bar: function () { return 2 + this._super(); }
+ });
+ strictEqual(instance.foo(), 2);
+ strictEqual(instance.bar(), 3);
+ });
+ test('In-place extension of subclassed types', function () {
+ var C0 = openerp.web.Class.extend({
+ foo: function () { return 1; },
+ bar: function () { return 1; }
+ });
+ var C1 = C0.extend({
+ foo: function () { return 1 + this._super(); },
+ bar: function () { return 1 + this._super(); }
+ });
+ var instance = new C1();
+ strictEqual(instance.foo(), 2);
+ C0.include({
+ foo: function () { return 2; },
+ bar: function () { return 2 + this._super(); }
+ });
+ strictEqual(instance.foo(), 3);
+ strictEqual(instance.bar(), 4);
+ });
+});
diff --git a/addons/web/static/test/form.js b/addons/web/static/test/form.js
new file mode 100644
index 00000000000..8317c7bfcd2
--- /dev/null
+++ b/addons/web/static/test/form.js
@@ -0,0 +1,58 @@
+$(document).ready(function () {
+ var openerp;
+ module("form.widget", {
+ setup: function () {
+ openerp = window.openerp.init(true);
+ window.openerp.web.core(openerp);
+ window.openerp.web.chrome(openerp);
+ // views loader stuff
+ window.openerp.web.data(openerp);
+ window.openerp.web.views(openerp);
+ window.openerp.web.list(openerp);
+ window.openerp.web.form(openerp);
+ }
+ });
+ test("compute_domain", function () {
+ var fields = {
+ 'a': {value: 3},
+ 'group_method': {value: 'line'},
+ 'select1': {value: 'day'},
+ 'rrule_type': {value: 'monthly'}
+ };
+ ok(openerp.web.form.compute_domain(
+ [['a', '=', 3]], fields));
+ ok(openerp.web.form.compute_domain(
+ [['group_method','!=','count']], fields));
+ ok(openerp.web.form.compute_domain(
+ [['select1','=','day'], ['rrule_type','=','monthly']], fields));
+ });
+ test("compute_domain or", function () {
+ var web = {
+ 'section_id': {value: null},
+ 'user_id': {value: null},
+ 'member_ids': {value: null}
+ };
+
+ var domain = ['|', ['section_id', '=', 42],
+ '|', ['user_id','=',3],
+ ['member_ids', 'in', [3]]];
+
+ ok(openerp.web.form.compute_domain(domain, _.extend(
+ {}, web, {'section_id': {value: 42}})));
+ ok(openerp.web.form.compute_domain(domain, _.extend(
+ {}, web, {'user_id': {value: 3}})));
+
+ ok(openerp.web.form.compute_domain(domain, _.extend(
+ {}, web, {'member_ids': {value: 3}})));
+ });
+ test("compute_domain not", function () {
+ var fields = {
+ 'a': {value: 5},
+ 'group_method': {value: 'line'}
+ };
+ ok(openerp.web.form.compute_domain(
+ ['!', ['a', '=', 3]], fields));
+ ok(openerp.web.form.compute_domain(
+ ['!', ['group_method','=','count']], fields));
+ });
+});
diff --git a/addons/web/static/test/formats.js b/addons/web/static/test/formats.js
new file mode 100644
index 00000000000..331725dd9a5
--- /dev/null
+++ b/addons/web/static/test/formats.js
@@ -0,0 +1,54 @@
+$(document).ready(function () {
+ var openerp;
+ module('web-formats', {
+ setup: function () {
+ openerp = window.openerp.init();
+ window.openerp.web.core(openerp);
+ window.openerp.web.dates(openerp);
+ window.openerp.web.formats(openerp);
+ }
+ });
+ test("format_datetime", function () {
+ var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
+ var str = openerp.web.format_value(date, {type:"datetime"});
+ equal(str, date.toString("M/d/yyyy h:mm:ss tt"));
+ });
+ test("format_date", function () {
+ var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
+ var str = openerp.web.format_value(date, {type:"date"});
+ equal(str, date.toString("M/d/yyyy"));
+ });
+ test("format_time", function () {
+ var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
+ var str = openerp.web.format_value(date, {type:"time"});
+ equal(str, date.toString("h:mm:ss tt"));
+ });
+ test("format_float", function () {
+ var fl = 12.1234;
+ var str = openerp.web.format_value(fl, {type:"float"});
+ equal(str, "12.12");
+ });
+ test("parse_datetime", function () {
+ var val = openerp.web.str_to_datetime("2009-05-04 12:34:23");
+ var res = openerp.web.parse_value(val.toString("M/d/yyyy h:mm:ss tt"), {type:"datetime"});
+ equal(val.toString("M/d/yyyy h:mm:ss tt"), res.toString("M/d/yyyy h:mm:ss tt"));
+ });
+ test("parse_date", function () {
+ var val = openerp.web.str_to_date("2009-05-04");
+ var res = openerp.web.parse_value(val.toString("M/d/yyyy"), {type:"date"});
+ equal(val.toString("M/d/yyyy"), res.toString("M/d/yyyy"));
+ });
+ test("parse_time", function () {
+ var val = openerp.web.str_to_time("12:34:23");
+ var res = openerp.web.parse_value(val.toString("h:mm:ss tt"), {type:"time"});
+ equal(val.toString("h:mm:ss tt"), res.toString("h:mm:ss tt"));
+ });
+ test("parse_float", function () {
+ var str = "134,112.1234";
+ var val = openerp.web.parse_value(str, {type:"float"});
+ equal(val, 134112.1234);
+ var str = "-134,112.1234";
+ var val = openerp.web.parse_value(str, {type:"float"});
+ equal(val, -134112.1234);
+ });
+}); \ No newline at end of file
diff --git a/addons/web/static/test/list-utils.js b/addons/web/static/test/list-utils.js
new file mode 100644
index 00000000000..f71da82a560
--- /dev/null
+++ b/addons/web/static/test/list-utils.js
@@ -0,0 +1,297 @@
+$(document).ready(function () {
+ var openerp,
+ create = function (o) {
+ if (typeof Object.create === 'function') {
+ return Object.create(o);
+ }
+ function Cls() {}
+ Cls.prototype = o;
+ return new Cls;
+ };
+ module('list-events', {
+ setup: function () {
+ openerp = window.openerp.init();
+ window.openerp.web.list(openerp);
+ }
+ });
+ test('Simple event triggering', function () {
+ var e = create(openerp.web.list.Events), passed = false;
+ e.bind('foo', function () { passed = true; });
+ e.trigger('foo');
+ ok(passed);
+ });
+ test('Bind all', function () {
+ var e = create(openerp.web.list.Events), event = null;
+ e.bind(null, function (ev) { event = ev; });
+ e.trigger('foo');
+ strictEqual(event, 'foo');
+ });
+ test('Propagate trigger params', function () {
+ var e = create(openerp.web.list.Events), p = false;
+ e.bind(null, function (_, param) { p = param });
+ e.trigger('foo', true);
+ strictEqual(p, true)
+ });
+ test('Bind multiple callbacks', function () {
+ var e = create(openerp.web.list.Events), count;
+ e.bind('foo', function () { count++; })
+ .bind('bar', function () { count++; })
+ .bind(null, function () { count++; })
+ .bind('foo', function () { count++; })
+ .bind(null, function () { count++; })
+ .bind(null, function () { count++; });
+
+ count = 0;
+ e.trigger('foo');
+ strictEqual(count, 5);
+
+ count = 0;
+ e.trigger('bar');
+ strictEqual(count, 4);
+
+ count = 0;
+ e.trigger('baz');
+ strictEqual(count, 3);
+ });
+ test('Mixin events', function () {
+ var cls = openerp.web.Class.extend({
+ method: function () { this.trigger('e'); }
+ });
+ cls.include(openerp.web.list.Events);
+ var instance = new cls, triggered = false;
+
+ instance.bind('e', function () { triggered = true; });
+ instance.method();
+
+ ok(triggered);
+ });
+ test('Unbind all handlers', function () {
+ var e = create(openerp.web.list.Events), passed = 0;
+ e.bind('foo', function () { passed++; });
+ e.trigger('foo');
+ strictEqual(passed, 1);
+ e.unbind('foo');
+ e.trigger('foo');
+ strictEqual(passed, 1);
+ });
+ test('Unbind one handler', function () {
+ var e = create(openerp.web.list.Events), p1 = 0, p2 = 0,
+ h1 = function () { p1++; }, h2 = function () { p2++; };
+ e.bind('foo', h1);
+ e.bind('foo', h2);
+ e.trigger('foo');
+ strictEqual(p1, 1);
+ strictEqual(p2, 1);
+ e.unbind('foo', h1);
+ e.trigger('foo');
+ strictEqual(p1, 1);
+ strictEqual(p2, 2);
+ });
+
+ module('list-records', {
+ setup: function () {
+ openerp = window.openerp.init();
+ window.openerp.web.list(openerp);
+ }
+ });
+ test('Basic record initialization', function () {
+ var r = new openerp.web.list.Record({qux: 3});
+ r.set('foo', 1);
+ r.set('bar', 2);
+ strictEqual(r.get('foo'), 1);
+ strictEqual(r.get('bar'), 2);
+ strictEqual(r.get('qux'), 3);
+ });
+ test('Change all the things', function () {
+ var r = new openerp.web.list.Record(), changed = false, field;
+ r.bind('change', function () { changed = true; });
+ r.bind(null, function (e) { field = field || e.split(':')[1]});
+ r.set('foo', 1);
+ strictEqual(r.get('foo'), 1);
+ ok(changed);
+ strictEqual(field, 'foo');
+ });
+ test('Change single field', function () {
+ var r = new openerp.web.list.Record(), changed = 0;
+ r.bind('change:foo', function () { changed++; });
+ r.set('foo', 1);
+ r.set('bar', 1);
+ strictEqual(r.get('foo'), 1);
+ strictEqual(r.get('bar'), 1);
+ strictEqual(changed, 1);
+ });
+
+ module('list-collections-degenerate', {
+ setup: function () {
+ openerp = window.openerp.init();
+ window.openerp.web.list(openerp);
+ }
+ });
+ test('Fetch from collection', function () {
+ var c = new openerp.web.list.Collection();
+ strictEqual(c.length, 0);
+ c.add({id: 1, value: 2});
+ c.add({id: 2, value: 3});
+ c.add({id: 3, value: 5});
+ c.add({id: 4, value: 7});
+ strictEqual(c.length, 4);
+ var r = c.at(2), r2 = c.get(1);
+
+ ok(r instanceof openerp.web.list.Record);
+ strictEqual(r.get('id'), 3);
+ strictEqual(r.get('value'), 5);
+
+ ok(r2 instanceof openerp.web.list.Record);
+ strictEqual(r2.get('id'), 1);
+ strictEqual(r2.get('value'), 2);
+ });
+ test('Add at index', function () {
+ var c = new openerp.web.list.Collection([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]);
+ strictEqual(c.at(1).get('value'), 10);
+ equal(c.at(3), undefined);
+ c.add({id:4, value: 55}, {at: 1});
+ strictEqual(c.at(1).get('value'), 55);
+ strictEqual(c.at(3).get('value'), 20);
+ });
+ test('Remove record', function () {
+ var c = new openerp.web.list.Collection([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]);
+ var record = c.get(2);
+ strictEqual(c.length, 3);
+ c.remove(record);
+ strictEqual(c.length, 2);
+ equal(c.get(2), undefined);
+ strictEqual(c.at(1).get('value'), 20);
+ });
+ test('Reset', function () {
+ var event, obj, c = new openerp.web.list.Collection([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]);
+ c.bind(null, function (e, instance) { event = e; obj = instance; });
+ c.reset();
+ strictEqual(c.length, 0);
+ strictEqual(event, 'reset');
+ strictEqual(obj, c);
+ c.add([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]);
+ c.reset([{id: 42, value: 55}]);
+ strictEqual(c.length, 1);
+ strictEqual(c.get(42).get('value'), 55);
+ });
+
+ test('Events propagation', function () {
+ var values = [];
+ var c = new openerp.web.list.Collection([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]);
+ c.bind('change:value', function (e, record, value) {
+ values.push(value);
+ });
+ c.get(1).set('value', 6);
+ c.get(2).set('value', 11);
+ c.get(3).set('value', 21);
+ deepEqual(values, [6, 11, 21]);
+ });
+ test('BTree', function () {
+ var root = new openerp.web.list.Collection(),
+ c = root.proxy('admin'),
+ total = 0;
+ c.add({id: 1, name: "Administrator", login: 'admin'});
+ c.add({id: 3, name: "Demo", login: 'demo'});
+ root.bind('change:wealth', function () {
+ total = (root.get(1).get('wealth') || 0) + (root.get(3).get('wealth') || 0);
+ });
+
+ strictEqual(total, 0);
+ c.at(0).set('wealth', 42);
+ strictEqual(total, 42);
+ c.at(1).set('wealth', 5);
+ strictEqual(total, 47);
+ });
+
+ module('list-hofs', {
+ setup: function () {
+ openerp = window.openerp.init();
+ window.openerp.web.list(openerp);
+ }
+ });
+ test('each, degenerate', function () {
+ var c = new openerp.web.list.Collection([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]), ids = [];
+ c.each(function (record) {
+ ids.push(record.get('id'));
+ });
+ deepEqual(
+ ids, [1, 2, 3],
+ 'degenerate collections should be iterated in record order');
+ });
+ test('each, deep', function () {
+ var root = new openerp.web.list.Collection(),
+ ids = [];
+ root.proxy('foo').add([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}]);
+ root.proxy('bar').add([
+ {id: 10, value: 5},
+ {id: 20, value: 10},
+ {id: 30, value: 20}]);
+ root.each(function (record) {
+ ids.push(record.get('id'));
+ });
+ // No contract on sub-collection iteration order (for now anyway)
+ ids.sort(function (a, b) { return a - b; });
+ deepEqual(
+ ids, [1, 2, 3, 10, 20, 30],
+ 'tree collections should be deeply iterated');
+ });
+ test('map, degenerate', function () {
+ var c = new openerp.web.list.Collection([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}
+ ]);
+ var ids = c.map(function (record) {
+ return record.get('id');
+ });
+ deepEqual(
+ ids, [1, 2, 3],
+ 'degenerate collections should be iterated in record order');
+ });
+ test('map, deep', function () {
+ var root = new openerp.web.list.Collection();
+ root.proxy('foo').add([
+ {id: 1, value: 5},
+ {id: 2, value: 10},
+ {id: 3, value: 20}]);
+ root.proxy('bar').add([
+ {id: 10, value: 5},
+ {id: 20, value: 10},
+ {id: 30, value: 20}]);
+ var ids = root.map(function (record) {
+ return record.get('id');
+ });
+ // No contract on sub-collection iteration order (for now anyway)
+ ids.sort(function (a, b) { return a - b; });
+ deepEqual(
+ ids, [1, 2, 3, 10, 20, 30],
+ 'tree collections should be deeply iterated');
+ });
+});
diff --git a/addons/web/static/test/qunit-doc.js b/addons/web/static/test/qunit-doc.js
new file mode 100644
index 00000000000..3667cc3eb40
--- /dev/null
+++ b/addons/web/static/test/qunit-doc.js
@@ -0,0 +1,143 @@
+/**
+ * Defines a module scope (which lasts until the next call to module).
+ *
+ * This module scopes implies setup and teardown callbacks running for each test.
+ *
+ * @function
+ * @param {String} name the name of the module
+ * @param {Object} [lifecycle] callbacks to run before and after each test of the module
+ * @param {Function} lifecycle.setup function running before each test of this module
+ * @param {Function} lifecycle.teardown function running after each test of this module
+ */
+var module;
+/**
+ * Defines a given test to run. Runs all the assertions present in the test
+ *
+ * @function
+ * @param {String} name the name of the test
+ * @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests)
+ * @param {Function} test the testing code to run, holding a sequence of assertions (at least one)
+ */
+var test;
+/**
+ * Defines an asynchronous test: equivalent to calling stop() at the start of
+ * a normal test().
+ *
+ * The test code needs to restart the test runner via start()
+ *
+ * @function
+ * @param {String} name the name of the test
+ * @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests)
+ * @param {Function} test the testing code to run, holding a sequence of assertions (at least one)
+ */
+var asyncTest;
+/**
+ * The most basic boolean assertion (~assertTrue or assert).
+ *
+ * Passes if its argument is truthy
+ *
+ * @function
+ * @param {Boolean} state an arbitrary expression, evaluated in a boolean context
+ * @param {String} [message] the message to output with the assertion result
+ */
+var ok;
+/**
+ * Equality assertion (~assertEqual)
+ *
+ * Passes if both arguments are equal (via <code>==</code>)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var equal;
+/**
+ * Inequality assertion (~assertNotEqual)
+ *
+ * Passes if the arguments are different (via <code>!=</code>)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var notEqual;
+/**
+ * Recursive equality assertion.
+ *
+ * Works on primitive types using <code>===</code> and traversing through
+ * Objects and Arrays as well checking their components
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var deepEqual;
+/**
+ * Recursive inequality assertion.
+ *
+ * Works on primitive types using <code>!==</code> and traversing through
+ * Objects and Arrays as well checking their components
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var notDeepEqual;
+/**
+ * Strict equality assertion (~assertEqual)
+ *
+ * Passes if both arguments are identical (via <code>===</code>)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var strictEqual;
+/**
+ * Strict inequality assertion (~assertNotEqual)
+ *
+ * Passes if both arguments are identical (via <code>!==</code>)
+ *
+ * @function
+ * @param {Object} actual the object to check for correctness (processing result)
+ * @param {Object} expected the object to check against
+ * @param {String} [message] message output with the assertion result
+ */
+var notStrictEqual;
+/**
+ * Passes if the provided block raised an exception.
+ *
+ * The <code>expect</code> argument can be provided to perform further assertion checks on the exception itself:
+ * * If it's a <code>RegExp</code> test the exception against the regexp (message?)
+ * * If it's a constructor, check if the exception is an instance of it
+ * * If it's an other type of function, call it with the exception as first parameter
+ * - If the function returns true, the assertion validates
+ * - Otherwise it fails
+ *
+ * @function
+ * @param {Function} block function which should raise an exception when called
+ * @param {Object} [expect] a RegExp, a constructor or a Function
+ * @param {String} [message] message output with the assertion result
+ */
+var raises;
+/**
+ * Starts running the test runner again from the point where it was
+ * <code>stop</code>ped.
+ *
+ * Used to resume testing after a callback.
+ *
+ * @function
+ */
+var start;
+/**
+ * Stops the test runner in order to wait for an asynchronous test to run
+ *
+ * @function
+ * @param {Number} [timeout] fails the test after the timeout triggers, only for debugging tests
+ */
+var stop;
diff --git a/addons/web/static/test/registry.js b/addons/web/static/test/registry.js
new file mode 100644
index 00000000000..0a3e65e9b1c
--- /dev/null
+++ b/addons/web/static/test/registry.js
@@ -0,0 +1,33 @@
+$(document).ready(function () {
+ var openerp;
+ module('Registry', {
+ setup: function () {
+ openerp = window.openerp.init(true);
+ window.openerp.web.core(openerp);
+ openerp.web.Foo = {};
+ openerp.web.Bar = {};
+ }
+ });
+ test('key fetch', function () {
+ var reg = new openerp.web.Registry({
+ foo: 'openerp.web.Foo',
+ bar: 'openerp.web.Bar',
+ quux: 'openerp.web.Quux'
+ });
+
+ strictEqual(reg.get_object('foo'), openerp.web.Foo);
+ raises(function () { reg.get_object('qux'); },
+ openerp.web.KeyNotFound,
+ "Unknown keys should raise KeyNotFound");
+ raises(function () { reg.get_object('quux'); },
+ openerp.web.ObjectNotFound,
+ "Incorrect file paths should raise ObjectNotFound");
+ });
+ test('key set', function () {
+ var reg = new openerp.web.Registry();
+
+ reg.add('foo', 'openerp.web.Foo')
+ .add('bar', 'openerp.web.Bar');
+ strictEqual(reg.get_object('bar'), openerp.web.Bar);
+ });
+});
diff --git a/addons/web/static/test/test.html b/addons/web/static/test/test.html
new file mode 100644
index 00000000000..38237a0600a
--- /dev/null
+++ b/addons/web/static/test/test.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html style="height: 100%">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>OpenERP</title>
+ <link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
+
+ <link rel="stylesheet" href="/web/static/lib/qunit/qunit-2011-23-22.css">
+ <script src="/web/static/lib/qunit/qunit-2011-23-22.js" type="text/javascript"></script>
+
+ <script src="/web/static/lib/underscore/underscore.js" type="text/javascript"></script>
+ <script src="/web/static/lib/underscore/underscore.string.js" type="text/javascript"></script>
+
+ <!-- jquery -->
+ <script src="/web/static/lib/jquery/jquery-1.6.2.js"></script>
+ <script src="/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
+
+ <script src="/web/static/lib/datejs/globalization/en-US.js"></script>
+ <script src="/web/static/lib/datejs/core.js"></script>
+ <script src="/web/static/lib/datejs/parser.js"></script>
+ <script src="/web/static/lib/datejs/sugarpak.js"></script>
+ <script src="/web/static/lib/datejs/extras.js"></script>
+
+ <script src="/web/static/lib/qweb/qweb.js"></script>
+
+ <script src="/web/static/src/js/boot.js"></script>
+ <script src="/web/static/src/js/core.js"></script>
+ <script src="/web/static/src/js/dates.js"></script>
+ <script src="/web/static/src/js/formats.js"></script>
+ <script src="/web/static/src/js/chrome.js"></script>
+ <script src="/web/static/src/js/data.js"></script>
+ <script src="/web/static/src/js/views.js"></script>
+ <script src="/web/static/src/js/search.js"></script>
+ <script src="/web/static/src/js/form.js"></script>
+ <script src="/web/static/src/js/list.js"></script>
+ <script type="text/javascript">
+ QWeb.add_template('/web/static/src/xml/web.xml');
+ </script>
+</head>
+ <body id="oe" class="openerp">
+ <h1 id="qunit-header">OpenERP web Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <div id="qunit-testrunner-toolbar"></div>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+ <div id="qunit-fixture"></div>
+ </body>
+ <script type="text/javascript" src="/web/static/test/class.js"></script>
+ <script type="text/javascript" src="/web/static/test/registry.js"></script>
+ <script type="text/javascript" src="/web/static/test/form.js"></script>
+ <script type="text/javascript" src="/web/static/test/list-utils.js"></script>
+ <script type="text/javascript" src="/web/static/test/formats.js"></script>
+</html>