diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ethiopian-date-picker-overrides.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ethiopian-date-picker-overrides.css new file mode 100644 index 000000000..e6b4d28d6 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ethiopian-date-picker-overrides.css @@ -0,0 +1,279 @@ +.ethiopian-picker-surface .calendars { + width: 100% !important; + border: 0; + border-radius: 0.5rem; + color: rgb(31 41 55); + font-family: inherit; + font-size: 0.875rem; + box-shadow: none; +} + +.ethiopian-picker-surface .calendars-nav, +.ethiopian-picker-surface .calendars-ctrl { + background: transparent; + border-bottom: 1px solid rgb(229 231 235); + padding: 0.35rem 0.4rem; +} + +.ethiopian-picker-surface .calendars-month { + width: 100%; + border: 0; +} + +.ethiopian-picker-surface .calendars-month-header, +.ethiopian-picker-surface .calendars-month-header select, +.ethiopian-picker-surface .calendars-month-header input { + height: 2.1rem; + background: transparent; + color: rgb(17 24 39); + font-weight: 600; +} + +.ethiopian-picker-surface .calendars-month th, +.ethiopian-picker-surface .calendars-month td { + border: 0; + padding: 0.2rem; +} + +.ethiopian-picker-surface .calendars-month th { + color: rgb(107 114 128); + font-weight: 500; + font-size: 0.75rem; +} + +.ethiopian-picker-surface .calendars-month a, +.ethiopian-picker-surface .calendars-month span { + border-radius: 0.35rem; + background: transparent; + color: rgb(17 24 39); + padding: 0.38rem 0; +} + +.ethiopian-picker-surface .calendars-month a:hover { + background: rgb(220 252 231); + color: rgb(22 101 52); +} + +.ethiopian-picker-surface .calendars-month td .calendars-today { + background: rgb(220 252 231); + color: rgb(22 101 52); +} + +.ethiopian-picker-surface .calendars-month td .calendars-selected { + background: rgb(34 197 94); + color: rgb(255 255 255); +} + +.ethiopian-picker-surface .calendars-month td .calendars-other-month { + color: rgb(156 163 175); +} + +.ethiopian-picker-surface .calendars-nav .calendars-cmd-prev, +.ethiopian-picker-surface .calendars-nav .calendars-cmd-next, +.ethiopian-picker-surface .calendars-nav .calendars-cmd-prevJump, +.ethiopian-picker-surface .calendars-nav .calendars-cmd-nextJump, +.calendars-popup .calendars-nav .calendars-cmd-prev, +.calendars-popup .calendars-nav .calendars-cmd-next, +.calendars-popup .calendars-nav .calendars-cmd-prevJump, +.calendars-popup .calendars-nav .calendars-cmd-nextJump { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 2rem; + height: 2rem; + border: 1px solid rgb(187 247 208); + border-radius: 0.5rem; + background: rgb(240 253 244); + color: rgb(21 128 61); + line-height: 1; + transition: all 0.2s ease; +} + +.ethiopian-picker-surface .calendars-nav .calendars-cmd-prev:hover, +.ethiopian-picker-surface .calendars-nav .calendars-cmd-next:hover, +.ethiopian-picker-surface .calendars-nav .calendars-cmd-prevJump:hover, +.ethiopian-picker-surface .calendars-nav .calendars-cmd-nextJump:hover, +.calendars-popup .calendars-nav .calendars-cmd-prev:hover, +.calendars-popup .calendars-nav .calendars-cmd-next:hover, +.calendars-popup .calendars-nav .calendars-cmd-prevJump:hover, +.calendars-popup .calendars-nav .calendars-cmd-nextJump:hover { + background: rgb(34 197 94); + border-color: rgb(34 197 94); + color: rgb(255 255 255); +} + +.ethiopian-picker-surface .calendars-nav, +.calendars-popup .calendars-nav { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; +} + +.ethiopian-picker-surface .calendars-nav .calendars-cmd, +.calendars-popup .calendars-nav .calendars-cmd { + float: none; + width: auto; + padding-left: 0; + padding-right: 0; +} + +.ethiopian-picker-surface .calendars-nav .calendars-cmd-today, +.calendars-popup .calendars-nav .calendars-cmd-today { + flex: 1; + border-radius: 0.5rem; + color: rgb(21 128 61); + font-weight: 600; + text-align: center; +} + +.ethiopian-picker-surface .calendars-nav .calendars-cmd.calendars-disabled, +.calendars-popup .calendars-nav .calendars-cmd.calendars-disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.dark .ethiopian-picker-surface .calendars, +[data-theme="dark"] .ethiopian-picker-surface .calendars, +.dark .calendars-popup .calendars, +[data-theme="dark"] .calendars-popup .calendars { + background: rgb(17 24 39); + color: rgb(229 231 235); + border-color: rgb(55 65 81); +} + +.dark .ethiopian-picker-surface .calendars-nav, +.dark .ethiopian-picker-surface .calendars-ctrl, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav, +[data-theme="dark"] .ethiopian-picker-surface .calendars-ctrl, +.dark .calendars-popup .calendars-nav, +.dark .calendars-popup .calendars-ctrl, +[data-theme="dark"] .calendars-popup .calendars-nav, +[data-theme="dark"] .calendars-popup .calendars-ctrl { + background: rgb(17 24 39); + border-color: rgb(55 65 81); +} + +.dark .ethiopian-picker-surface .calendars-month-header, +.dark .ethiopian-picker-surface .calendars-month-header select, +.dark .ethiopian-picker-surface .calendars-month-header input, +.dark .ethiopian-picker-surface .calendars-month a, +.dark .ethiopian-picker-surface .calendars-month span, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month-header, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month-header select, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month-header input, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month a, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month span, +.dark .calendars-popup .calendars-month-header, +.dark .calendars-popup .calendars-month-header select, +.dark .calendars-popup .calendars-month-header input, +.dark .calendars-popup .calendars-month a, +.dark .calendars-popup .calendars-month span, +[data-theme="dark"] .calendars-popup .calendars-month-header, +[data-theme="dark"] .calendars-popup .calendars-month-header select, +[data-theme="dark"] .calendars-popup .calendars-month-header input, +[data-theme="dark"] .calendars-popup .calendars-month a, +[data-theme="dark"] .calendars-popup .calendars-month span { + color: rgb(229 231 235); +} + +.dark .ethiopian-picker-surface .calendars-month th, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month th, +.dark .calendars-popup .calendars-month th, +[data-theme="dark"] .calendars-popup .calendars-month th { + color: rgb(156 163 175); +} + +.dark .ethiopian-picker-surface .calendars-month a:hover, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month a:hover, +.dark .calendars-popup .calendars-month a:hover, +[data-theme="dark"] .calendars-popup .calendars-month a:hover { + background: rgb(20 83 45); + color: rgb(187 247 208); +} + +.dark .ethiopian-picker-surface .calendars-month td .calendars-today, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month td .calendars-today, +.dark .calendars-popup .calendars-month td .calendars-today, +[data-theme="dark"] .calendars-popup .calendars-month td .calendars-today { + background: rgb(20 83 45); + color: rgb(187 247 208); +} + +.dark .ethiopian-picker-surface .calendars-month td .calendars-highlight, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month td .calendars-highlight, +.dark .calendars-popup .calendars-month td .calendars-highlight, +[data-theme="dark"] .calendars-popup .calendars-month td .calendars-highlight { + background: rgb(22 101 52); +} + +.dark .ethiopian-picker-surface .calendars-month td .calendars-selected, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month td .calendars-selected, +.dark .calendars-popup .calendars-month td .calendars-selected, +[data-theme="dark"] .calendars-popup .calendars-month td .calendars-selected { + background: rgb(34 197 94); + color: rgb(5 46 22); +} + +.dark .ethiopian-picker-surface .calendars-month td .calendars-other-month, +[data-theme="dark"] .ethiopian-picker-surface .calendars-month td .calendars-other-month, +.dark .calendars-popup .calendars-month td .calendars-other-month, +[data-theme="dark"] .calendars-popup .calendars-month td .calendars-other-month { + color: rgb(107 114 128); +} + +.dark .ethiopian-picker-surface .calendars a.calendars-disabled, +[data-theme="dark"] .ethiopian-picker-surface .calendars a.calendars-disabled, +.dark .calendars-popup .calendars a.calendars-disabled, +[data-theme="dark"] .calendars-popup .calendars a.calendars-disabled { + color: rgb(75 85 99); +} + +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-prev, +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-next, +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-prevJump, +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-nextJump, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-prev, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-next, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-prevJump, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-nextJump, +.dark .calendars-popup .calendars-nav .calendars-cmd-prev, +.dark .calendars-popup .calendars-nav .calendars-cmd-next, +.dark .calendars-popup .calendars-nav .calendars-cmd-prevJump, +.dark .calendars-popup .calendars-nav .calendars-cmd-nextJump, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-prev, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-next, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-prevJump, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-nextJump { + background: rgb(21 128 61 / 0.22); + border-color: rgb(34 197 94 / 0.45); + color: rgb(187 247 208); +} + +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-prev:hover, +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-next:hover, +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-prevJump:hover, +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-nextJump:hover, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-prev:hover, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-next:hover, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-prevJump:hover, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-nextJump:hover, +.dark .calendars-popup .calendars-nav .calendars-cmd-prev:hover, +.dark .calendars-popup .calendars-nav .calendars-cmd-next:hover, +.dark .calendars-popup .calendars-nav .calendars-cmd-prevJump:hover, +.dark .calendars-popup .calendars-nav .calendars-cmd-nextJump:hover, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-prev:hover, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-next:hover, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-prevJump:hover, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-nextJump:hover { + background: rgb(34 197 94); + border-color: rgb(34 197 94); + color: rgb(5 46 22); +} + +.dark .ethiopian-picker-surface .calendars-nav .calendars-cmd-today, +[data-theme="dark"] .ethiopian-picker-surface .calendars-nav .calendars-cmd-today, +.dark .calendars-popup .calendars-nav .calendars-cmd-today, +[data-theme="dark"] .calendars-popup .calendars-nav .calendars-cmd-today { + color: rgb(187 247 208); +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/flora.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/flora.calendars.picker.css new file mode 100644 index 000000000..3a359e149 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/flora.calendars.picker.css @@ -0,0 +1,208 @@ +/* Flora styling for jQuery Calendars Picker v2.0.0. */ +.calendars { + background-color: #e0f4d7; + color: #000; + border: 1px solid #f90; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-family: Arial,Helvetica,Sans-serif; + font-size: 90%; +} +.calendars-rtl { + direction: rtl; +} +.calendars-popup { + z-index: 1000; +} +.calendars-disable { + position: absolute; + z-index: 100; + background-color: white; + opacity: 0.5; + filter: alpha(opacity=50); +} +.calendars a { + color: #000; + text-decoration: none; +} +.calendars a.calendars-disabled { + color: #888; + cursor: auto; +} +.calendars button { + margin: 0.25em; + padding: 0.125em 0em; + background-color: #fc8; + border: none; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-weight: bold; +} +.calendars-nav, .calendars-ctrl { + float: left; + width: 100%; + background-color: #e0f4d7; + color: #fff; + font-size: 90%; + font-weight: bold; +} +.datepick-ctrl { + background-color: #f90; +} +.calendars-cmd { + width: 30%; +} +.calendars-cmd:hover { + background-color: #b1db87; +} +.calendars-ctrl .calendars-cmd:hover { + background-color: #fa4; +} +.calendars-cmd-prevJump, .calendars-cmd-nextJump { + width: 8%; +} +a.calendars-cmd { + height: 1.5em; +} +button.calendars-cmd { + text-align: center; +} +.calendars-cmd-prev, .calendars-cmd-prevJump, .calendars-cmd-clear { + float: left; + padding-left: 2%; +} +.calendars-cmd-current, .calendars-cmd-today { + float: left; + width: 35%; + text-align: center; +} +.calendars-cmd-next, .calendars-cmd-nextJump, .calendars-cmd-close { + float: right; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-prev, .calendars-rtl .calendars-cmd-prevJump, +.calendars-rtl .calendars-cmd-clear { + float: right; + padding-left: 0%; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-current, .calendars-rtl .calendars-cmd-today { + float: right; +} +.calendars-rtl .calendars-cmd-next, .calendars-rtl .calendars-cmd-nextJump, +.calendars-rtl .calendars-cmd-close { + float: left; + padding-left: 2%; + padding-right: 0%; + text-align: left; +} +.calendars-month-nav { + float: left; + background-color: #b1db87; + text-align: center; +} +.calendars-month-nav div { + float: left; + width: 12.5%; + margin: 1%; + padding: 1%; +} +.calendars-month-nav span { + color: #888; +} +.calendars-month-row { + clear: left; +} +.calendars-month { + float: left; + width: 15em; + border: 1px solid #83c948; + text-align: center; +} +.calendars-month-header, .calendars-month-header select, .calendars-month-header input { + height: 1.5em; + background-color: #83c948; + color: #fff; + font-weight: bold; +} +.calendars-month-header select, .calendars-month-header input { + height: 1.4em; + border: none; +} +.calendars-month-header input { + position: absolute; + display: none; +} +.calendars-month table { + width: 100%; + border-collapse: collapse; +} +.calendars-month thead { + border-bottom: 1px solid #aaa; +} +.calendars-month th, .calendars-month td { + margin: 0em; + padding: 0em; + font-weight: normal; + text-align: center; +} +.calendars-month th { + border: 1px solid #b1db87; +} +.calendars-month th, .calendars-month th a { + background-color: #b1db87; + color: #000; + border: 1px solid #b1db87; +} +.calendars-month td { + background-color: #fff; + color: #666; + border: 1px solid #b1db87; +} +.calendars-month td.calendars-week * { + background-color: #b1db87; + color: #666; + border: none; +} +.calendars-month a { + display: block; + width: 100%; + padding: 0.125em 0em; + text-decoration: none; +} +.calendars-month span { + display: block; + width: 100%; + padding: 0.125em 0em; +} +.calendars-month td span { + color: #888; +} +.calendars-month td .calendars-other-month { + background-color: #e0f4d7; +} +.calendars-month td .calendars-weekend { + background-color: #e0f4d7; +} +.calendars-month td .calendars-today { + background-color: #b1db87; +} +.calendars-month td .calendars-highlight { + background-color: #fc8; +} +.calendars-month td .calendars-selected { + background-color: #f90; + color: #fff; +} +.calendars-status { + clear: both; + background-color: #b1db87; + text-align: center; +} +.calendars-clear-fix { + clear: both; +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/humanity.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/humanity.calendars.picker.css new file mode 100644 index 000000000..cb69417a4 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/humanity.calendars.picker.css @@ -0,0 +1,197 @@ +/* Humanity styling for jQuery Calendars Picker v2.0.0. */ +.calendars { + background-color: #f4f0ec; + color: #1e1b1c; + border: 1px solid #cb842e; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-family: Arial,Helvetica,Sans-serif; + font-size: 90%; +} +.calendars-rtl { + direction: rtl; +} +.calendars-popup { + z-index: 1000; +} +.calendars-disable { + position: absolute; + z-index: 100; + background-color: white; + opacity: 0.5; + filter: alpha(opacity=50); +} +.calendars a { + color: #1e1b1c; + text-decoration: none; +} +.calendars a.calendars-disabled { + color: #888; + cursor: auto; +} +.calendars button { + margin: 0.25em; + padding: 0.125em 0em; + background-color: #ede4d4; + border: none; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-weight: bold; +} +.calendars-nav, .calendars-ctrl { + float: left; + width: 100%; + background-color: #ede4d4; + font-size: 90%; + font-weight: bold; +} +.calendars-ctrl { + background-color: #cb842e; +} +.calendars-cmd { + width: 30%; +} +.calendars-cmd:hover { + background-color: #f4f0ec; +} +.calendars-cmd-prevJump, .calendars-cmd-nextJump { + width: 8%; +} +a.calendars-cmd { + height: 1.5em; +} +button.calendars-cmd { + text-align: center; +} +.calendars-cmd-prev, .calendars-cmd-prevJump, .calendars-cmd-clear { + float: left; + padding-left: 2%; +} +.calendars-cmd-current, .calendars-cmd-today { + float: left; + width: 35%; + text-align: center; +} +.calendars-cmd-next, .calendars-cmd-nextJump, .calendars-cmd-close { + float: right; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-prev, .calendars-rtl .calendars-cmd-prevJump, +.calendars-rtl .calendars-cmd-clear { + float: right; + padding-left: 0%; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-current, .calendars-rtl .calendars-cmd-today { + float: right; +} +.calendars-rtl .calendars-cmd-next, .calendars-rtl .calendars-cmd-nextJump, +.calendars-rtl .calendars-cmd-close { + float: left; + padding-left: 2%; + padding-right: 0%; + text-align: left; +} +.calendars-month-nav { + float: left; + text-align: center; +} +.calendars-month-nav div { + float: left; + width: 12.5%; + margin: 1%; + padding: 1%; +} +.calendars-month-nav span { + color: #888; +} +.calendars-month-row { + clear: left; +} +.calendars-month { + float: left; + width: 17em; + border: 1px solid #e0cfc2; + text-align: center; +} +.calendars-month-header, .calendars-month-header select, .calendars-month-header input { + height: 1.5em; + background-color: #cb842e; + color: #fff; + font-weight: bold; +} +.calendars-month-header select, .calendars-month-header input { + height: 1.4em; + border: none; +} +.calendars-month-header input { + position: absolute; + display: none; +} +.calendars-month table { + width: 100%; + border: 2px solid transparent; + border-collapse: collapse; +} +.calendars-month th, .calendars-month td { + margin: 0em; + padding: 0.125em; + font-weight: normal; + text-align: center; +} +.calendars-month td.calendars-week, +.calendars-month td.calendars-week * { + background-color: #cb842e; + color: #fff; + border: 1px solid #cb842e; +} +.calendars-month a { + display: block; + width: 100%; + padding: 0.125em 0em; + background-color: #ede4d4; + color: #000; + border: 1px solid #cdc3b7; + text-decoration: none; +} +.calendars-month span { + display: block; + margin-top: 0.25em; +} +.calendars-month a { + background-color: #ede4d4; + color: #444; + border: 1px solid #cdc3b7; + text-decoration: none; +} +.calendars-month td span { + color: #888; +} +.calendars-month td .calendars-other-month { + background-color: #f4f0ec; +} +.calendars-month td .calendars-today { + background-color: #f5f5b5; + border: 1px solid #d9bb73; +} +.calendars-month td .calendars-highlight { + background-color: #f5f0e5; + color: #1e1b1c; + border: 1px solid #f5ad66; +} +.calendars-month td .calendars-selected { + background-color: #cb842e; + color: #fff; + border: 1px solid #cb842e; +} +.calendars-status { + clear: both; + text-align: center; +} +.calendars-clear-fix { + clear: both; +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/jquery.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/jquery.calendars.picker.css new file mode 100644 index 000000000..8b8ff6223 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/jquery.calendars.picker.css @@ -0,0 +1,215 @@ +/* Default styling for jQuery Calendars Picker v2.0.0. */ +.calendars { + background-color: #fff; + color: #000; + border: 1px solid #444; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-family: Arial,Helvetica,Sans-serif; + font-size: 90%; +} +.calendars-rtl { + direction: rtl; +} +.calendars-popup { + z-index: 1000; +} +.calendars-disable { + position: absolute; + z-index: 100; + background-color: white; + opacity: 0.5; + filter: alpha(opacity=50); +} +.calendars a { + color: #fff; + text-decoration: none; +} +.calendars a.calendars-disabled { + color: #888; + cursor: auto; +} +.calendars button { + margin: 0.25em; + padding: 0.125em 0em; + background-color: #fcc; + border: none; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-weight: bold; +} +.calendars-nav, .calendars-ctrl { + float: left; + width: 100%; + background-color: #000; + color: #fff; + font-size: 90%; + font-weight: bold; +} +.calendars-ctrl { + background-color: #600; +} +.calendars-cmd { + width: 30%; +} +.calendars-cmd:hover { + background-color: #777; +} +.calendars-ctrl .calendars-cmd:hover { + background-color: #f08080; +} +.calendars-cmd-prevJump, .calendars-cmd-nextJump { + width: 8%; +} +a.calendars-cmd { + height: 1.5em; +} +button.calendars-cmd { + text-align: center; +} +.calendars-cmd-prev, .calendars-cmd-prevJump, .calendars-cmd-clear { + float: left; + padding-left: 2%; +} +.calendars-cmd-current, .calendars-cmd-today { + float: left; + width: 35%; + text-align: center; +} +.calendars-cmd-next, .calendars-cmd-nextJump, .calendars-cmd-close { + float: right; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-prev, .calendars-rtl .calendars-cmd-prevJump, +.calendars-rtl .calendars-cmd-clear { + float: right; + padding-left: 0%; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-current, .calendars-rtl .calendars-cmd-today { + float: right; +} +.calendars-rtl .calendars-cmd-next, .calendars-rtl .calendars-cmd-nextJump, +.calendars-rtl .calendars-cmd-close { + float: left; + padding-left: 2%; + padding-right: 0%; + text-align: left; +} +.calendars-month-nav { + float: left; + background-color: #777; + text-align: center; +} +.calendars-month-nav div { + float: left; + width: 12.5%; + margin: 1%; + padding: 1%; +} +.calendars-month-nav span { + color: #888; +} +.calendars-month-row { + clear: left; +} +.calendars-month { + float: left; + width: 15em; + border: 1px solid #444; + text-align: center; +} +.calendars-month-header, .calendars-month-header select, .calendars-month-header input { + height: 1.5em; + background-color: #444; + color: #fff; + font-weight: bold; +} +.calendars-month-header select, .calendars-month-header input { + height: 1.4em; + border: none; +} +.calendars-month-header input { + position: absolute; + display: none; +} +.calendars-month table { + width: 100%; + border-collapse: collapse; +} +.calendars-month thead { + border-bottom: 1px solid #aaa; +} +.calendars-month th, .calendars-month td { + margin: 0em; + padding: 0em; + font-weight: normal; + text-align: center; +} +.calendars-month th { + border: 1px solid #777; +} +.calendars-month th, .calendars-month th a { + background-color: #777; + color: #fff; +} +.calendars-month td { + background-color: #eee; + border: 1px solid #aaa; +} +.calendars-month td.calendars-week { + border: 1px solid #777; +} +.calendars-month td.calendars-week * { + background-color: #777; + color: #fff; + border: none; +} +.calendars-month a { + display: block; + width: 100%; + padding: 0.125em 0em; + background-color: #eee; + color: #000; + text-decoration: none; +} +.calendars-month span { + display: block; + width: 100%; + padding: 0.125em 0em; +} +.calendars-month td span { + color: #888; +} +.calendars-month td .calendars-other-month { + background-color: #fff; +} +.calendars-month td .calendars-weekend { + background-color: #ddd; +} +.calendars-month td .calendars-today { + background-color: #f0c0c0; +} +.calendars-month td .calendars-highlight { + background-color: #f08080; +} +.calendars-month td .calendars-selected { + background-color: #777; + color: #fff; +} +.calendars-month th.calendars-week { + background-color: #777; + color: #fff; +} +.calendars-status { + clear: both; + background-color: #ddd; + text-align: center; +} +.calendars-clear-fix { + clear: both; +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/redmond.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/redmond.calendars.picker.css new file mode 100644 index 000000000..c105ace5e --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/redmond.calendars.picker.css @@ -0,0 +1,199 @@ +/* Redmond styling for jQuery Calendars Picker v2.0.0. */ +.calendars { + background-color: #fff; + color: #222; + border: 1px solid #4297d7; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-family: Arial,Helvetica,Sans-serif; + font-size: 90%; +} +.calendars-rtl { + direction: rtl; +} +.calendars-popup { + z-index: 1000; +} +.calendars-disable { + position: absolute; + z-index: 100; + background-color: white; + opacity: 0.5; + filter: alpha(opacity=50); +} +.calendars a { + color: #222; + text-decoration: none; +} +.calendars a.calendars-disabled { + color: #888; + cursor: auto; +} +.calendars button { + margin: 0.25em; + padding: 0.125em 0em; + background-color: #5c9ccc; + color: #fff; + border: none; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-weight: bold; +} +.calendars-nav, .calendars-ctrl { + float: left; + width: 100%; + background-color: #fff; + font-size: 90%; + font-weight: bold; +} +.calendars-ctrl { + background-color: #d0e5f5; +} +.calendars-cmd { + width: 30%; +} +.calendars-cmd:hover { + background-color: #dfeffc; +} +button.calendars-cmd:hover { + background-color: #79b7e7; +} +.calendars-cmd-prevJump, .calendars-cmd-nextJump { + width: 8%; +} +a.calendars-cmd { + height: 1.5em; +} +button.calendars-cmd { + text-align: center; +} +.calendars-cmd-prev, .calendars-cmd-prevJump, .calendars-cmd-clear { + float: left; + padding-left: 2%; +} +.calendars-cmd-current, .calendars-cmd-today { + float: left; + width: 35%; + text-align: center; +} +.calendars-cmd-next, .calendars-cmd-nextJump, .calendars-cmd-close { + float: right; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-prev, .calendars-rtl .calendars-cmd-prevJump, +.calendars-rtl .calendars-cmd-clear { + float: right; + padding-left: 0%; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-current, .calendars-rtl .calendars-cmd-today { + float: right; +} +.calendars-rtl .calendars-cmd-next, .calendars-rtl .calendars-cmd-nextJump, +.calendars-rtl .calendars-cmd-close { + float: left; + padding-left: 2%; + padding-right: 0%; + text-align: left; +} +.calendars-month-nav { + float: left; + text-align: center; +} +.calendars-month-nav div { + float: left; + width: 12.5%; + margin: 1%; + padding: 1%; +} +.calendars-month-nav span { + color: #888; +} +.calendars-month-row { + clear: left; +} +.calendars-month { + float: left; + width: 15em; + border: 1px solid #5c9ccc; + text-align: center; +} +.calendars-month-header, .calendars-month-header select, .calendars-month-header input { + height: 1.5em; + background-color: #5c9ccc; + color: #fff; + font-weight: bold; +} +.calendars-month-header select, .calendars-month-header input { + height: 1.4em; + border: none; +} +.calendars-month-header input { + position: absolute; + display: none; +} +.calendars-month table { + width: 100%; + border-collapse: collapse; +} +.calendars-month thead { + border-bottom: 1px solid #aaa; +} +.calendars-month th, .calendars-month td { + margin: 0em; + padding: 0em; + font-weight: normal; + text-align: center; +} +.calendars-month th { + border: 1px solid #fff; + border-bottom: 1px solid #c5dbec; +} +.calendars-month td { + border: 1px solid #c5dbec; +} +.calendars-month td.calendars-week * { + background-color: #d0e5f5; + color: #222; + border: none; +} +.calendars-month a { + display: block; + width: 100%; + padding: 0.125em 0em; + background-color: #dfeffc; + color: #000; + text-decoration: none; +} +.calendars-month span { + display: block; + width: 100%; + padding: 0.125em 0em; +} +.calendars-month td span { + color: #888; +} +.calendars-month td .calendars-other-month { + background-color: #fff; +} +.calendars-month td .calendars-today { + background-color: #fad42e; +} +.calendars-month td .calendars-highlight { + background-color: #79b7e7; +} +.calendars-month td .calendars-selected { + background-color: #4297d7; + color: #fff; +} +.calendars-status { + clear: both; + text-align: center; +} +.calendars-clear-fix { + clear: both; +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/smoothness.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/smoothness.calendars.picker.css new file mode 100644 index 000000000..8ffa6387d --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/smoothness.calendars.picker.css @@ -0,0 +1,200 @@ +/* Smoothness styling for jQuery Calendars Picker v2.0.0. */ +.calendars { + background-color: #fff; + color: #222; + border: 1px solid #aaa; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-family: Arial,Helvetica,Sans-serif; + font-size: 90%; +} +.calendars-rtl { + direction: rtl; +} +.calendars-popup { + z-index: 1000; +} +.calendars-disable { + position: absolute; + z-index: 100; + background-color: white; + opacity: 0.5; + filter: alpha(opacity=50); +} +.calendars a { + color: #222; + text-decoration: none; +} +.calendars a.calendars-disabled { + color: #888; + cursor: auto; +} +.calendars button { + margin: 0.25em; + padding: 0.125em 0em; + background-color: #fcc; + border: none; + -moz-border-radius: 0.25em; + -webkit-border-radius: 0.25em; + border-radius: 0.25em; + font-weight: bold; +} +.calendars-nav, .calendars-ctrl { + float: left; + width: 100%; + background-color: #fff; + font-size: 90%; + font-weight: bold; +} +.calendars-ctrl { + background-color: #fee6e3; +} +.calendars-cmd { + width: 30%; +} +.calendars-cmd:hover { + background-color: #e0e0e0; +} +.calendars-ctrl .calendars-cmd:hover { + background-color: #f08080; +} +.calendars-cmd-prevJump, .calendars-cmd-nextJump { + width: 8%; +} +a.calendars-cmd { + height: 1.5em; +} +button.calendars-cmd { + text-align: center; +} +.calendars-cmd-prev, .calendars-cmd-prevJump, .calendars-cmd-clear { + float: left; + padding-left: 2%; +} +.calendars-cmd-current, .calendars-cmd-today { + float: left; + width: 35%; + text-align: center; +} +.calendars-cmd-next, .calendars-cmd-nextJump, .calendars-cmd-close { + float: right; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-prev, .calendars-rtl .calendars-cmd-prevJump, +.calendars-rtl .calendars-cmd-clear { + float: right; + padding-left: 0%; + padding-right: 2%; + text-align: right; +} +.calendars-rtl .calendars-cmd-current, .calendars-rtl .calendars-cmd-today { + float: right; +} +.calendars-rtl .calendars-cmd-next, .calendars-rtl .calendars-cmd-nextJump, +.calendars-rtl .calendars-cmd-close { + float: left; + padding-left: 2%; + padding-right: 0%; + text-align: left; +} +.calendars-month-nav { + float: left; + text-align: center; +} +.calendars-month-nav div { + float: left; + width: 12.5%; + margin: 1%; + padding: 1%; +} +.calendars-month-nav span { + color: #888; +} +.calendars-month-row { + clear: left; +} +.calendars-month { + float: left; + width: 15em; + border: 1px solid #aaa; + text-align: center; +} +.calendars-month-header, .calendars-month-header select, .calendars-month-header input { + height: 1.5em; + background-color: #e0e0e0; + color: #222; + font-weight: bold; +} +.calendars-month-header select, .calendars-month-header input { + height: 1.4em; + border: none; +} +.calendars-month-header input { + position: absolute; + display: none; +} +.calendars-month table { + width: 100%; + border-collapse: collapse; +} +.calendars-month thead { + border-bottom: 1px solid #aaa; +} +.calendars-month th, .calendars-month td { + margin: 0em; + padding: 0em; + font-weight: normal; + text-align: center; +} +.calendars-month thead tr { + border: 1px solid #aaa; +} +.calendars-month td { + background-color: #eee; + border: 1px solid #aaa; +} +.calendars-month td.calendars-week * { + background-color: #e0e0e0; + color: #222; + border: none; +} +.calendars-month a { + display: block; + width: 100%; + padding: 0.125em 0em; + background-color: #eee; + color: #000; + text-decoration: none; +} +.calendars-month span { + display: block; + width: 100%; + padding: 0.125em 0em; +} +.calendars-month td span { + color: #888; +} +.calendars-month td .calendars-other-month { + background-color: #fff; +} +.calendars-month td .calendars-weekend { + background-color: #ddd; +} +.calendars-month td .calendars-today { + background-color: #fbf9ee; +} +.calendars-month td .calendars-highlight { + background-color: #dadada; +} +.calendars-month td .calendars-selected { + background-color: #fcc; +} +.calendars-status { + clear: both; + text-align: center; +} +.calendars-clear-fix { + clear: both; +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-black-tie.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-black-tie.calendars.picker.css new file mode 100644 index 000000000..8b2662bda --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-black-tie.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller Blacktie override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #eeeeee; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #1c1c1c; /* Set (.ui-state-hover) colours from theme here */ + color: #ffffff; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #333333; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #363636; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-blitzer.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-blitzer.calendars.picker.css new file mode 100644 index 000000000..8ba0b1bcf --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-blitzer.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller Blitzer override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #ffffff; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #f6f6f6; /* Set (.ui-state-hover) colours from theme here */ + color: #111111; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #cc0000; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #555555; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-cupertino.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-cupertino.calendars.picker.css new file mode 100644 index 000000000..422d05500 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-cupertino.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller Cupertino override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #222222; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #f0f0f0; /* Set (.ui-state-hover) colours from theme here */ + color: #0b5b98; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #e7eef3; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #363636; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-dark-hive.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-dark-hive.calendars.picker.css new file mode 100644 index 000000000..9e8ed89de --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-dark-hive.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller Dark Hive override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #ffffff; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #003147; /* Set (.ui-state-hover) colours from theme here */ + color: #ffffff;; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #444444; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #eeeeee; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-dot-luv.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-dot-luv.calendars.picker.css new file mode 100644 index 000000000..565ede68f --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-dot-luv.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller DotLuv override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #f6f6f6; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #00498f; /* Set (.ui-state-hover) colours from theme here */ + color: #ffffff; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #0b3e6f; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #ffffff; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-eggplant.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-eggplant.calendars.picker.css new file mode 100644 index 000000000..d2b61da9b --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-eggplant.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller Eggplant override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #ffffff; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #eae6ea; /* Set (.ui-state-hover) colours from theme here */ + color: #734d99; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #30273a; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #fafafa; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-excite-bike.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-excite-bike.calendars.picker.css new file mode 100644 index 000000000..4791e44bc --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-excite-bike.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller ExciteBike override style sheet for jQuery dCalendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #e69700; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #2293f7; /* Set (.ui-state-hover) colours from theme here */ + color: #ffffff; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #f9f9f9; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #333333; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-flick.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-flick.calendars.picker.css new file mode 100644 index 000000000..c133db1fe --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-flick.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller Flick override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #444444; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #0073ea; /* Set (.ui-state-hover) colours from theme here */ + color: #ffffff; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #dddddd; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #444444; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-hot-sneaks.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-hot-sneaks.calendars.picker.css new file mode 100644 index 000000000..c6a581429 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui-hot-sneaks.calendars.picker.css @@ -0,0 +1,18 @@ +/* ThemeRoller HotSneaks override style sheet for jQuery Calendars Picker v2.0.0. */ +@import "ui.calendars.picker.css"; + +.ui-widget-header a, +.ui-widget-header select { + color: #e1e463; /* Set (.ui-widget-header a) colour from theme here */ +} +.ui-widget-header a:hover { + background-color: #ccd232; /* Set (.ui-state-hover) colours from theme here */ + color: #212121; +} +.ui-widget-header select, +.ui-widget-header option { + background-color: #35414f; /* Set (.ui-widget-header) background colour from theme here */ +} +.ui-state-highlight a { + color: #363636; /* Set (.ui-state-highlight) colour from theme here */ +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui.calendars.picker.css b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui.calendars.picker.css new file mode 100644 index 000000000..2baeaa73d --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/css/ui.calendars.picker.css @@ -0,0 +1,107 @@ +/* ThemeRoller override style sheet for jQuery Calendars Picker v2.0.0. */ +.ui-datepicker { + display: block; +} +#ui-datepicker-div, +.ui-datepicker-inline { + width: 17em; + font-size: 75%; +} +#ui-datepicker-div { + z-index: 100; +} +.ui-datepicker-inline { + float: left; +} +.ui-datepicker-rtl { + direction: rtl; +} +#ui-datepicker-div a, +.ui-datepicker-inline a { + text-decoration: none; +} +.ui-datepicker-prompt { + height: 1.5em; + padding-top: 0.25em; + text-align: center; +} +button.ui-datepicker-cmd { + height: 2em; +} +.ui-datepicker-cmd-clear { + float: left; + margin-left: 0.25em; +} +.ui-datepicker-cmd-close { + float: right; + margin-right: 0.25em; +} +.ui-datepicker-cmd-prev { + position: static; + float: left; + width: 30%; + height: auto; + margin-left: 1%; +} +.ui-datepicker-cmd-next { + position: static; + float: right; + width: 30%; + height: auto; + margin-right: 1%; + text-align: right; +} +.ui-datepicker-cmd-current, +.ui-datepicker-cmd-today { + float: left; + width: 37%; + text-align: center; +} +.ui-datepicker-month-nav { + float: left; + text-align: center; +} +.ui-datepicker-month-nav div { + float: left; + width: 12.5%; + margin: 1%; + padding: 1%; +} +.ui-datepicker-month-nav span { + color: #888; +} +.ui-datepicker-row-break { + width: 100%; + font-size: 100%; +} +.ui-datepicker-group { + float: left; + width: 17em; +} +.ui-datepicker-group .ui-datepicker-header { + height: 1.5em; + text-align: center; +} +.ui-datepicker select, +.ui-datepicker-inline select { + width: auto; + height: 1.66em; + border: none; + font-weight: bold; +} +.ui-datepicker th { + padding: 0.5em 0.3em; +} +.ui-datepicker td, +.ui-datepicker td a, +.ui-datepicker td span { + border: 1px solid transparent; + text-align: center; +} +.ui-datepicker-status { + padding: 0.25em 0em; + text-align: center; +} +.ui-datepicker .ui-helper-clearfix { + clear: both; +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/AmharicDatePicker.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/AmharicDatePicker.tsx new file mode 100644 index 000000000..7f3b226f9 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/AmharicDatePicker.tsx @@ -0,0 +1,457 @@ +import $ from "@/shared/common/jquery-global"; +import React, { useEffect, useRef, useState } from "react"; +import { cn } from "@/shared/lib/utils"; + +// CSS and plugins +import "@/shared/common/css/redmond.calendars.picker.css"; +import "@/shared/common/css/ethiopian-date-picker-overrides.css"; +import "@/shared/common/js/jquery.plugin.js"; +import "@/shared/common/js/jquery.calendars.js"; +import "@/shared/common/js/jquery.calendars.plus.js"; +import "@/shared/common/js/jquery.calendars.picker.js"; +import "@/shared/common/js/jquery.calendars.ethiopian.js"; +import "@/shared/common/js/jquery.calendars.ethiopian-am.js"; + +interface CalendarsDate { + toString(): string; +} + +interface CalendarsDateFactory { + toJSDate(): Date; +} + +interface CalendarsInstance { + newDate: (year: number, month: number, day: number) => CalendarsDateFactory; + fromJSDate: (jsDate: Date) => unknown; + formatDate: ( + format: string, + date: unknown, + settings?: { localNumbers?: boolean }, + ) => string; +} + +interface CalendarsApi { + instance: (calendarType: string, language: string) => CalendarsInstance; +} + +interface CalendarsPickerOptions { + calendar: CalendarsInstance; + dateFormat: string; + onSelect: (dates: CalendarsDate[]) => void; +} + +type CalendarsPickerElement = JQuery & { + calendarsPicker: (...args: unknown[]) => unknown; +}; + +declare global { + interface JQueryStatic { + calendars: CalendarsApi; + } +} + +interface EthiopianDatePickerModalProps { + value?: string | Date; + onChange: (value: string) => void; +} + +const ETHIOPIAN_UTC_OFFSET_HOURS = 3; + +const toEthiopianTimeInput = (date: Date): string => { + if (!(date instanceof Date) || isNaN(date.getTime())) { + return "00:00"; + } + + const totalMinutesUtc = date.getUTCHours() * 60 + date.getUTCMinutes(); + const totalMinutesEthiopian = + (totalMinutesUtc + ETHIOPIAN_UTC_OFFSET_HOURS * 60 + 1440) % 1440; + + const hh = Math.floor(totalMinutesEthiopian / 60) + .toString() + .padStart(2, "0"); + const mm = (totalMinutesEthiopian % 60).toString().padStart(2, "0"); + + return `${hh}:${mm}`; +}; + +const getCurrentEthiopianTimeInput = (): string => { + return toEthiopianTimeInput(new Date()); +}; + +/** + * Ethiopian 12-hour clock parts. The Ethiopian day starts at 6:00 EAT, so EAT + * 6:00 AM is clock 12 (day) and EAT 6:00 PM is clock 12 (night). + * + * `period` is purely a display concern — the stored value is always derived + * from the EAT 24-hour time, so the backend payload is unaffected. + */ +type EthiopianClockPeriod = "day" | "night"; + +interface EthiopianClockParts { + hour: number; // 1-12 + minute: number; // 0-59 + period: EthiopianClockPeriod; +} + +const ETHIOPIAN_HOUR_OPTIONS = Array.from({ length: 12 }, (_, i) => i + 1); + +// EAT 24h "HH:mm" -> Ethiopian 12h clock parts (day starts at 6:00 EAT). +const eatTimeToEthiopianClock = (eatTime: string): EthiopianClockParts => { + const [hhRaw, mmRaw] = (eatTime || "").split(":"); + const parsedHour = Number(hhRaw); + const parsedMinute = Number(mmRaw); + const eatHour = Number.isFinite(parsedHour) + ? ((parsedHour % 24) + 24) % 24 + : 0; + const minute = Number.isFinite(parsedMinute) + ? ((parsedMinute % 60) + 60) % 60 + : 0; + + const hour = (eatHour + 6) % 12 || 12; + const period: EthiopianClockPeriod = + eatHour >= 6 && eatHour < 18 ? "day" : "night"; + + return { hour, minute, period }; +}; + +// Ethiopian 12h clock parts -> EAT 24h "HH:mm". +const ethiopianClockToEatTime = ({ + hour, + minute, + period, +}: EthiopianClockParts): string => { + const base = (hour % 12) + 6; // day window: 6..17 + const eatHour = (period === "night" ? base + 12 : base) % 24; + const hh = eatHour.toString().padStart(2, "0"); + const mm = (((minute % 60) + 60) % 60).toString().padStart(2, "0"); + return `${hh}:${mm}`; +}; + +const normalizeDigits = (value: string): string => + value + .replace(/[٠-٩]/g, (digit) => String(digit.charCodeAt(0) - 1632)) + .replace(/[۰-۹]/g, (digit) => String(digit.charCodeAt(0) - 1776)); + +const toEthiopianDateInput = (date: Date): string => { + if ( + !(date instanceof Date) || + Number.isNaN(date.getTime()) || + !$ || + !$.calendars + ) { + return ""; + } + + try { + const calendar = $.calendars.instance("ethiopian", "am"); + const ethiopianDate = calendar.fromJSDate( + new Date(date.getTime() + ETHIOPIAN_UTC_OFFSET_HOURS * 60 * 60 * 1000), + ); + + return calendar.formatDate("yyyy-mm-dd", ethiopianDate, { + localNumbers: false, + }); + } catch { + return ""; + } +}; + +const EthiopianDatePickerModal: React.FC = ({ + value, + onChange, +}) => { + const datePickerRef = useRef(null); + const pickerElementRef = useRef(null); + const isSyncingRef = useRef(false); + const lastSyncedDateRef = useRef(""); + const onChangeRef = useRef(onChange); + const initialValueRef = useRef(value); + const [selectedDate, setSelectedDate] = useState(""); + const [selectedTime, setSelectedTime] = useState( + getCurrentEthiopianTimeInput, + ); + const selectedTimeRef = useRef(selectedTime); + + useEffect(() => { + onChangeRef.current = onChange; + }, [onChange]); + + useEffect(() => { + selectedTimeRef.current = selectedTime; + }, [selectedTime]); + + useEffect(() => { + if (!(value instanceof Date) || Number.isNaN(value.getTime())) { + return; + } + + const nextDate = toEthiopianDateInput(value); + // selectedTime is stored as EAT 24h "HH:mm"; the Ethiopian clock shown in + // the picker is derived from it via eatTimeToEthiopianClock. Seed it with + // EAT 24h here so the picker (and the trigger placeholder) agree. + const nextTime = toEthiopianTimeInput(value); + + setSelectedDate(nextDate); + setSelectedTime(nextTime); + + if ( + !pickerElementRef.current || + !$ || + !$.calendars || + !nextDate || + lastSyncedDateRef.current === nextDate + ) { + return; + } + + try { + const calendar = $.calendars.instance("ethiopian", "am"); + const [year, month, day] = nextDate.split("-").map(Number); + if ( + Number.isFinite(year) && + Number.isFinite(month) && + Number.isFinite(day) + ) { + const ethDate = calendar.newDate(year, month, day); + isSyncingRef.current = true; + try { + pickerElementRef.current.calendarsPicker("setDate", ethDate); + lastSyncedDateRef.current = nextDate; + } finally { + isSyncingRef.current = false; + } + } + } catch { + // ignore third-party plugin errors when syncing selection + } + }, [value]); + + useEffect(() => { + if (!$ || !$.calendars || !datePickerRef.current) { + return; + } + + const pickerHost = datePickerRef.current; + const calendar = $.calendars.instance("ethiopian", "am"); + const picker = $(pickerHost) as unknown as CalendarsPickerElement; + pickerElementRef.current = picker; + + picker.calendarsPicker({ + calendar, + dateFormat: "yyyy-mm-dd", + onSelect: (dates: CalendarsDate[]) => { + if (isSyncingRef.current) return; + if (!dates?.length) return; + + const date = dates[0].toString(); + lastSyncedDateRef.current = date; + setSelectedDate(date); + onChangeRef.current(`${date} ${selectedTimeRef.current}`); + }, + } as CalendarsPickerOptions); + + const initialValue = initialValueRef.current; + if (initialValue instanceof Date && !Number.isNaN(initialValue.getTime())) { + try { + const initialEth = toEthiopianDateInput(initialValue); + if (initialEth) { + const [y, m, d] = initialEth.split("-").map(Number); + if (Number.isFinite(y) && Number.isFinite(m) && Number.isFinite(d)) { + isSyncingRef.current = true; + try { + picker.calendarsPicker("setDate", calendar.newDate(y, m, d)); + lastSyncedDateRef.current = initialEth; + } finally { + isSyncingRef.current = false; + } + } + } + } catch { + // ignore third-party plugin errors when seeding initial date + } + } + + return () => { + try { + picker.calendarsPicker("destroy"); + } catch { + // ignore cleanup errors from third-party plugin + } + pickerElementRef.current = null; + lastSyncedDateRef.current = ""; + }; + }, []); + + // selectedTime is always EAT 24h "HH:mm"; the Ethiopian clock is a display-only + // projection so the stored value (and backend payload) stays unchanged. + const ethiopianClock = eatTimeToEthiopianClock(selectedTime); + + const applyEthiopianClock = (next: EthiopianClockParts) => { + const eatTime = ethiopianClockToEatTime(next); + setSelectedTime(eatTime); + + if (selectedDate) { + onChange(`${selectedDate} ${eatTime}`); + } + }; + + const handleHourChange = (e: React.ChangeEvent) => { + const hour = Number(e.target.value); + applyEthiopianClock({ + ...ethiopianClock, + hour: Number.isFinite(hour) ? hour : ethiopianClock.hour, + }); + }; + + const handleMinuteChange = (e: React.ChangeEvent) => { + const parsed = Number(e.target.value); + const minute = Number.isFinite(parsed) + ? Math.max(0, Math.min(59, Math.trunc(parsed))) + : 0; + applyEthiopianClock({ ...ethiopianClock, minute }); + }; + + const handlePeriodChange = (period: EthiopianClockPeriod) => { + applyEthiopianClock({ ...ethiopianClock, period }); + }; + + return ( +
+
+
+

+ ሰዓት +

+
+ + + : + + +
+ + +
+
+
+
+ ); +}; + +export function convertEthiopianToGregorian(ethiopianDateTime: string): Date { + if (!ethiopianDateTime || typeof ethiopianDateTime !== "string") { + return new Date(NaN); + } + + const normalizedDateTime = normalizeDigits(ethiopianDateTime.trim()); + const [datePart, timePart = "00:00"] = normalizedDateTime.split(" "); + + if (!datePart || !datePart.match(/^\d{4}-\d{2}-\d{2}$/)) { + return new Date(NaN); + } + + const cal = $.calendars.instance("ethiopian", "am"); + const [year, month, day] = datePart.split("-").map(Number); + + if (isNaN(year) || isNaN(month) || isNaN(day)) { + return new Date(NaN); + } + + try { + const ethDate = cal.newDate(year, month, day); + const gregDate = ethDate.toJSDate(); + + const [hours, minutes] = timePart.split(":").map(Number); + + if ( + isNaN(hours) || + isNaN(minutes) || + hours < 0 || + hours > 23 || + minutes < 0 || + minutes > 59 + ) { + return new Date(NaN); + } + + const utcDate = new Date( + Date.UTC( + gregDate.getFullYear(), + gregDate.getMonth(), + gregDate.getDate(), + hours - ETHIOPIAN_UTC_OFFSET_HOURS, + minutes, + 0, + 0, + ), + ); + + return utcDate; + } catch (error) { + console.error( + "[convertEthiopianToGregorian] Error during conversion:", + error, + ); + return new Date(NaN); + } +} + +export function formatEthiopianDate(ethiopianDate: string | Date): string { + if (!ethiopianDate) return ""; + + if (ethiopianDate instanceof Date) { + const day = ethiopianDate.getDate().toString().padStart(2, "0"); + const month = (ethiopianDate.getMonth() + 1).toString().padStart(2, "0"); + const year = ethiopianDate.getFullYear(); + return `${day}/${month}/${year}`; + } + + const parts = ethiopianDate.split("-"); + if (parts.length !== 3) return ethiopianDate; + + const [year, month, day] = parts; + return `${day.padStart(2, "0")}/${month.padStart(2, "0")}/${year}`; +} + +export default EthiopianDatePickerModal; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/DateField.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/DateField.tsx new file mode 100644 index 000000000..28824a1c5 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/DateField.tsx @@ -0,0 +1,233 @@ +import { useState } from "react"; +import { Control, FieldValues } from "react-hook-form"; +import $ from "@/shared/common/jquery-global"; +import { FormField, FormItem, FormLabel, FormMessage } from "../../ui/form"; +import EthiopianDatePickerModal, { + convertEthiopianToGregorian, +} from "./AmharicDatePicker"; +import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover"; +import { Button } from "../../ui/button"; +import { cn } from "@/shared/lib/utils"; +import { format } from "date-fns"; +import { CalendarIcon } from "lucide-react"; +import { Calendar } from "../../ui/calendar"; +import { Input } from "../../ui/input"; +import { useTranslation } from "react-i18next"; +import { + formatEthiopianClockTime, + utcToEthiopian, +} from "@/shared/common/utils/ethiopianTimeZone"; + +interface DateFieldProps { + name: "startDate" | "endDate"; + label: string; + control: Control; + isEthiopian: boolean; + minDate?: Date | null; +} + +interface EthiopianCalendarFormatter { + fromJSDate: (jsDate: Date) => unknown; + formatDate: ( + format: string, + date: unknown, + settings?: { localNumbers?: boolean }, + ) => string; +} + +const DateField: React.FC = ({ + name, + label, + control, + isEthiopian, + minDate, +}) => { + const [gregorianTimeFallback, setGregorianTimeFallback] = useState( + () => format(new Date(), "HH:mm"), + ); + const { t } = useTranslation(); + + return ( + { + const getGregorianTimeValue = (): string => { + if ( + field.value instanceof Date && + !Number.isNaN(field.value.getTime()) + ) { + return format(field.value, "HH:mm"); + } + return gregorianTimeFallback; + }; + + const handleEthiopianChange = (ethiopianDate: string) => { + const gregorianDate = convertEthiopianToGregorian(ethiopianDate); + if (!Number.isNaN(gregorianDate.getTime())) { + field.onChange(gregorianDate); + } + }; + + const getDisplayText = (): string => { + if (isEthiopian) { + if ( + field.value instanceof Date && + !Number.isNaN(field.value.getTime()) + ) { + const ethiopianTime = utcToEthiopian(field.value); + const timeStr = formatEthiopianClockTime(field.value); + + try { + const ethiopianCalendar = $.calendars.instance( + "ethiopian", + "am", + ) as unknown as EthiopianCalendarFormatter; + const ethiopianDate = + ethiopianCalendar.fromJSDate(ethiopianTime); + const dateStr = ethiopianCalendar.formatDate( + "yyyy-mm-dd", + ethiopianDate, + { localNumbers: true }, + ); + return `${dateStr} ${timeStr}`; + } catch { + const fallbackDate = format(ethiopianTime, "yyyy-MM-dd"); + return `${fallbackDate} ${timeStr}`; + } + } + return t("delegation.pickDate"); + } + if ( + field.value instanceof Date && + !Number.isNaN(field.value.getTime()) + ) { + const dateText = format(field.value, "PPP"); + const timeText = format(field.value, "HH:mm"); + return `${dateText} ${timeText}`; + } + return t("delegation.pickDate"); + }; + + return ( + + + {label} + + + + + + + + + {isEthiopian ? ( +
+ +
+ ) : ( +
+ { + if (!selectedDate) { + field.onChange(null); + return; + } + + const [hours, minutes] = getGregorianTimeValue() + .split(":") + .map(Number); + const nextDate = new Date(selectedDate); + nextDate.setHours(hours || 0, minutes || 0, 0, 0); + field.onChange(nextDate); + }} + initialFocus + className="w-full p-2" + disabled={(date) => { + const startOfToday = new Date( + new Date().setHours(0, 0, 0, 0), + ); + if (date < startOfToday) return true; + if ( + minDate instanceof Date && + !Number.isNaN(minDate.getTime()) + ) { + const startOfMin = new Date(minDate); + startOfMin.setHours(0, 0, 0, 0); + if (date < startOfMin) return true; + } + return false; + }} + /> +
+

+ {t("common.Time", "Time")} +

+ { + const newTime = event.target.value; + setGregorianTimeFallback(newTime); + + if ( + field.value instanceof Date && + !Number.isNaN(field.value.getTime()) + ) { + const [hours, minutes] = newTime + .split(":") + .map(Number); + const nextDate = new Date(field.value); + nextDate.setHours(hours || 0, minutes || 0, 0, 0); + field.onChange(nextDate); + } + }} + className="h-10" + /> +
+
+ )} +
+
+ + +
+ ); + }} + /> + ); +}; + +export default DateField; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/DateTimeField.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/DateTimeField.tsx new file mode 100644 index 000000000..7b51b0341 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/DateTimeField.tsx @@ -0,0 +1,242 @@ +import { useState } from "react"; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "../../ui/form"; +import EthiopianDatePickerModal, { + convertEthiopianToGregorian, +} from "./AmharicDatePicker"; +import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover"; +import { Button } from "../../ui/button"; +import { Input } from "../../ui/input"; +import { cn } from "@/shared/lib/utils"; +import { format } from "date-fns"; +import { CalendarIcon, Clock } from "lucide-react"; +import { Calendar } from "../../ui/calendar"; +import { useTranslation } from "react-i18next"; +import $ from "@/shared/common/jquery-global"; +import { + formatEthiopianClockTime, + utcToEthiopian, +} from "@/shared/common/utils/ethiopianTimeZone"; + +interface DateTimeFieldProps { + name: "startDate" | "endDate"; + label: string; + control: any; + isEthiopian: boolean; + isEditing: boolean; + fieldValue?: Date | null; +} + +interface EthiopianCalendarFormatter { + fromJSDate: (jsDate: Date) => unknown; + formatDate: ( + format: string, + date: unknown, + settings?: { localNumbers?: boolean }, + ) => string; +} + +const DateTimeField: React.FC = ({ + name, + label, + control, + isEthiopian, + isEditing, + fieldValue, +}) => { + const [ethiopianDisplay, setEthiopianDisplay] = useState(""); + const [showTimeInput, setShowTimeInput] = useState(false); + const { t } = useTranslation(); + + return ( + { + const handleEthiopianChange = (ethiopianDate: string) => { + setEthiopianDisplay(ethiopianDate); + const gregorianDate = convertEthiopianToGregorian(ethiopianDate); + field.onChange(gregorianDate); + }; + + const handleTimeChange = (hours: string, minutes: string) => { + if (field.value) { + const date = new Date(field.value); + date.setHours(parseInt(hours) || 0, parseInt(minutes) || 0, 0, 0); + field.onChange(date); + } + }; + + const getTimeString = () => { + if (!field.value) return ""; + const date = new Date(field.value); + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); + return `${hours}:${minutes}`; + }; + + const getDateTimeDisplay = () => { + if (!field.value) return t("delegation.pickDate"); + const date = new Date(field.value); + if (Number.isNaN(date.getTime())) return t("delegation.pickDate"); + const timeStr = isEthiopian + ? formatEthiopianClockTime(date) + : getTimeString(); + + const dateStr = (() => { + if (!isEthiopian) return format(date, "PPP"); + if (ethiopianDisplay) return ethiopianDisplay.split(" ")[0]; + + try { + const ethiopianCalendar = $.calendars.instance( + "ethiopian", + "am", + ) as unknown as EthiopianCalendarFormatter; + const ethiopianDate = ethiopianCalendar.fromJSDate( + utcToEthiopian(date), + ); + return ethiopianCalendar.formatDate( + "yyyy-mm-dd", + ethiopianDate, + { localNumbers: true }, + ); + } catch { + return format(utcToEthiopian(date), "yyyy-MM-dd"); + } + })(); + return `${dateStr} ${timeStr}`; + }; + + return ( + + + {label} + + + + + + + + + + +
+ {/* Date Picker */} + {isEthiopian ? ( +
+ + + +
+ ) : ( + + date < new Date(new Date().setHours(0, 0, 0, 0)) + } + /> + )} + + {/* Time Picker — Ethiopian mode uses the Ethiopian-clock + picker inside EthiopianDatePickerModal above, so this + Gregorian-local time picker is only shown otherwise. */} + {!isEthiopian && field.value && ( +
+
+ + +
+
+
+ + + handleTimeChange( + e.target.value, + String( + new Date(field.value).getMinutes(), + ).padStart(2, "0"), + ) + } + className="text-center text-sm" + placeholder="00" + /> +
+
+ : +
+
+ + + handleTimeChange( + String( + new Date(field.value).getHours(), + ).padStart(2, "0"), + e.target.value, + ) + } + className="text-center text-sm" + placeholder="00" + /> +
+
+
+ )} +
+
+
+ + +
+ ); + }} + /> + ); +}; + +export default DateTimeField; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/EthiopianDatePicker.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/EthiopianDatePicker.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/FormFields.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/FormFields.tsx new file mode 100644 index 000000000..d2a0e58a3 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/form/fields/FormFields.tsx @@ -0,0 +1,806 @@ +import React, { JSX, useRef, useState } from "react"; +import { Trash2, X, ChevronDown, Search } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "../../ui/form"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "../../ui/select"; +import { MultiSelect } from "../../ui/multi-select"; +import { Input } from "../../ui/input"; +import { Button } from "../../ui/button"; +import TreeView, { TreeViewItem } from "@/shared/common/ui/treeSelect"; + +import { Controller } from "react-hook-form"; +import { SingleSelect } from "../../ui/single-select"; +import { useLocalizedName } from "../../localizedName"; +import i18next from "i18next"; +import { getCheckedLeafNodes } from "@/record-management/components/userRecords/common/treeUtils"; + +type BaseSelectOption = { + label: string; + value: string; + unitId?: string; +}; +interface CustomSelectProps { + form: any; // your react-hook-form instance + name: string; + label: string; + placeholder: string; + options: { id: string; name: { en: string; am: string } }[]; + localizedName: (name: { en: string; am: string }) => string; +} + +// 1️⃣ Form Select Field +export const FormSelectField = ({ + control, + name, + label, + options, + placeholder, + className, + customLabel, + disabled, + onCustomChange, +}: { + control: any; + name: string; + label: string; + options: BaseSelectOption[]; + placeholder?: string; + className?: string; + customLabel?: React.ReactNode; + disabled?: boolean; + onCustomChange?: (value: string) => void; +}) => ( + ( + + {customLabel ? ( + customLabel + ) : ( + + {name === "headerId" || + name === "footerId" || + name === "recordType" || + name === "initiationType" || + name === "initiatedAs" ? ( + + {label} * + + ) : ( + label + )} + + )} + + + + + + )} + /> +); + +export const FormSingleSelectField = ({ + control, + name, + label, + options, + placeholder = "Select option", + onCustomChange, +}: { + control: any; + name: string; + label: string; + options: BaseSelectOption[]; + placeholder?: string; + onCustomChange?: (selectedValue: string) => void; +}) => ( + { + const handleChange = (value: string) => { + field.onChange(value); + if (onCustomChange) onCustomChange(value); + }; + + return ( + + {label} + + + + + + ); + }} + /> +); +// 2️⃣ Multi Select Field +export const FormMultiSelectField = ({ + control, + name, + label, + options, + placeholder = "Select options", + maxCount, + disabled, + onCustomChange, +}: { + control: any; + name: string; + label: string; + options: BaseSelectOption[]; + placeholder?: string; + maxCount?: number; + disabled?: boolean; + onCustomChange?: (selectedValues: string[]) => void; +}) => ( + { + const handleChange = (values: string[]) => { + field.onChange(values); + if (onCustomChange) onCustomChange(values); + }; + + const fieldValue = Array.isArray(field.value) + ? field.value + : field.value + ? [field.value] + : []; + + return ( + + + {name === "toPositions" || + name === "toEmployees" || + name === "collaborators" || + name === "receivingDepartments" || + name === "assignedEmployees" ? ( + + {label} * + + ) : ( + label + )} + + + + + + + ); + }} + /> +); + +export const FormTreeSelectField = ({ + control, + name, + label, + options, + handleCheckChange, + collapsible = false, + localizedName, + selectedCountResolver, +}: { + control: any; + name: string; + label: string; + options: TreeViewItem[]; + handleCheckChange?: + | ((item: TreeViewItem | TreeViewItem[], checked: boolean) => void) + | undefined; + collapsible?: boolean; + localizedName: ( + name?: + | { + am: string; + en: string; + } + | undefined, + ) => string; + selectedCountResolver?: (value: unknown) => number; +}) => { + const { t } = useTranslation(); + const [isOpen, setIsOpen] = React.useState(!collapsible); + const containerRef = React.useRef(null); + + // Close dropdown on outside click + React.useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + setIsOpen(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); + + if (collapsible) { + return ( + { + const selectedCount = selectedCountResolver + ? selectedCountResolver(field.value) + : getCheckedLeafNodes(Array.isArray(field.value) ? field.value : []) + .length; + + return ( + + + {name === "receivingUnitIds" ? ( + + {label} * + + ) : ( + label + )} + +
+ + + {isOpen && ( +
+ +
+ )} +
+ +
+ ); + }} + /> + ); + } + + return ( + ( + + {label} + + + + )} + /> + ); +}; + +// 3️⃣ Addable List Field (string-based) +export const FormAddableList = ({ + form, + name, + label, + placeholder = "", + valueAdapter, +}: { + form: any; + name: string; + label: string; + placeholder?: string; + valueAdapter?: { + getDisplayItems: (fieldValue: unknown) => string[]; + onItemsChange: (items: string[], fieldValue: unknown) => unknown; + }; +}) => { + const { t } = useTranslation(); + const [pendingValue, setPendingValue] = useState(""); + + return ( + { + const items = valueAdapter + ? valueAdapter.getDisplayItems(field.value) + : Array.isArray(field.value) + ? field.value + : []; + + const handleAdd = () => { + const value = pendingValue.trim(); + if (value && !items.includes(value)) { + const updatedItems = [...items, value]; + field.onChange( + valueAdapter + ? valueAdapter.onItemsChange(updatedItems, field.value) + : updatedItems, + ); + setPendingValue(""); + } + }; + + const handleDelete = (index: number) => { + const updatedItems = items.filter( + (_: string, i: number) => i !== index, + ); + field.onChange( + valueAdapter + ? valueAdapter.onItemsChange(updatedItems, field.value) + : updatedItems, + ); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.preventDefault(); + handleAdd(); + } + }; + + return ( + + {label} +
+ + setPendingValue(e.target.value)} + onKeyDown={handleKeyDown} + onBlur={handleAdd} + /> + + +
+ + {items.length > 0 && ( +
+ {items.map((unit: string, index: number) => ( +
+ + {unit} + + handleDelete(index)} + /> +
+ ))} +
+ )} + + +
+ ); + }} + /> + ); +}; +export const ClearableSelect = ({ + form, + name, + label, + placeholder = "", + options, + localizedName, +}: { + form: any; + name: string; + label: string; + placeholder?: string; + options: { id: string; name: any }[]; + localizedName: (name: any) => string; +}) => { + return ( + + {label} + ( + <> + {field.value ? ( + // Selected value with X to clear +
+ + {localizedName( + options.find((o) => o.id === field.value)?.name, + )} + + field.onChange("")} + /> +
+ ) : ( + // Select dropdown + + )} + + + )} + /> +
+ ); +}; + +export const CustomSelect = ({ + form, + name, + label, + placeholder, + options, + localizedName, +}: CustomSelectProps) => { + const { t } = useTranslation(); + return ( +
+ + { + const matchingOption = options.find((opt) => { + const english = opt.name?.en ?? ""; + const amharic = opt.name?.am ?? ""; + return ( + field.value === opt.id || + field.value === english || + field.value === amharic + ); + }); + + // Treat undefined, null, and empty string as no selection + const hasValue = field.value !== undefined && field.value !== null && field.value !== ""; + const resolvedValue = matchingOption && hasValue + ? matchingOption.id + : ""; + + return ( + + ); + }} + /> +
+ ); +}; + +export interface TreeViewItemO { + id: string; + name: string | { en: string; am: string }; // allow localized or raw + value?: string; + children?: TreeViewItem[]; +} + +interface SimpleTreeSelectProps { + label: string; + options: TreeViewItemO[]; + value: string | null; + onChange: (id: string | null) => void; + collapsible?: boolean; + localizedName?: (name?: { en?: string; am?: string } | undefined) => string; + className?: string; +} + +export const SimpleTreeSelect = ({ + label, + options, + value, + onChange, + collapsible = false, + localizedName, + className, +}: SimpleTreeSelectProps) => { + const [isOpen, setIsOpen] = useState(!collapsible); + const [expandedItems, setExpandedItems] = useState>(new Set()); + + const toggleExpand = (id: string) => { + const newSet = new Set(expandedItems); + if (newSet.has(id)) newSet.delete(id); + else newSet.add(id); + setExpandedItems(newSet); + }; + + const handleSelect = (id: string) => { + onChange(id); + // Optional: close dropdown after selection + // setIsOpen(false); + }; + + // Get full path for a selected item + const findSelectedPath = ( + items: TreeViewItemO[], + parentPath: string[] = [], + ): string | null => { + for (const item of items) { + const name = + typeof item.name === "string" + ? item.name + : (localizedName?.(item.name) ?? item.name.en); + + if (item.id === value) { + return [...parentPath, name].join(" / "); + } + + if (item.children && item.children.length > 0) { + const childPath = findSelectedPath(item.children, [ + ...parentPath, + name, + ]); + if (childPath) return childPath; + } + } + return null; + }; + + const renderTree = (items: TreeViewItemO[]): JSX.Element[] => { + return items.flatMap((item) => { + const hasChildren = item.children && item.children.length > 0; + const isExpanded = expandedItems.has(item.id); + + // Determine if any child is selected to highlight parent + const isParentSelected = hasChildren + ? item.children!.some((child) => child.id === value) + : false; + + // Skip single-unit org + if (hasChildren && item.children!.length === 1) { + return renderTree(item.children!); + } + + const itemLabel = + typeof item.name === "string" + ? item.name + : (localizedName?.(item.name) ?? item.name.en); + + return ( +
+
+ {hasChildren && ( + + )} + + +
+ + {hasChildren && isExpanded && ( +
{renderTree(item.children!)}
+ )} +
+ ); + }); + }; + + const selectedPathLabel = findSelectedPath(options); + + return ( +
+ + + {collapsible && ( + + )} + + {isOpen && ( +
+ {renderTree(options)} +
+ )} +
+ ); +}; + +export const SelectedItemsChips = ({ + items, + onRemove, + label, + localizedName, +}: { + items: TreeViewItem[]; + onRemove: (value: string) => void; + label?: string; + localizedName: ( + name?: + | { + am: string; + en: string; + } + | undefined, + ) => string; +}) => { + if (!items?.length) return null; + + return ( +
+ {label &&

{label}

} +
+ {items.map((item) => ( +
+ + {localizedName(item.name)} + + +
+ ))} +
+
+ ); +}; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar-blue.gif b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar-blue.gif new file mode 100644 index 000000000..601cbd55d Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar-blue.gif differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar-green.gif b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar-green.gif new file mode 100644 index 000000000..9dae1a3b2 Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar-green.gif differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar.gif b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar.gif new file mode 100644 index 000000000..d0abaa7c0 Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/calendar.gif differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view.png b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view.png new file mode 100644 index 000000000..2660a2289 Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view.png differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view2.png b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view2.png new file mode 100644 index 000000000..cf415098e Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view2.png differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view3.png b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view3.png new file mode 100644 index 000000000..b9d0e41e2 Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view3.png differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view4.png b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view4.png new file mode 100644 index 000000000..8cf2995c3 Binary files /dev/null and b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/img/view4.png differ diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/jquery-global.ts b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/jquery-global.ts new file mode 100644 index 000000000..9ad8997dd --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/jquery-global.ts @@ -0,0 +1,7 @@ +import jQuery from "jquery"; + +// Make jQuery global for legacy plugins +(window as any).jQuery = jQuery; +(window as any).$ = jQuery; + +export default jQuery; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian-am.ts b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian-am.ts new file mode 100644 index 000000000..17c5f3531 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian-am.ts @@ -0,0 +1,46 @@ +import $ from "jquery"; + +(function ($: any) { + "use strict"; + $.calendars.calendars.ethiopian.prototype.regionalOptions.am = { + name: "የኢትዮጵያ ዘመን አቆጣጠር", + epochs: ["BEE", "EE"], + monthNames: [ + "መስከረም", + "ጥቅምት", + "ኅዳር", + "ታህሣሥ", + "ጥር", + "የካቲት", + "መጋቢት", + "ሚያዝያ", + "ግንቦት", + "ሰኔ", + "ሐምሌ", + "ነሐሴ", + "ጳጉሜ", + ], + monthNamesShort: [ + "መስከ", + "ጥቅም", + "ኅዳር", + "ታህሣ", + "ጥር", + "የካቲ", + "መጋቢ", + "ሚያዝ", + "ግንቦ", + "ሰኔ", + "ሐምሌ", + "ነሐሴ", + "ጳጉሜ", + ], + dayNames: ["እሑድ", "ሰኞ", "ማክሰኞ", "ረቡዕ", "ሓሙስ", "ዓርብ", "ቅዳሜ"], + dayNamesShort: ["እሑድ", "ሰኞ", "ማክሰ", "ረቡዕ", "ሓሙስ", "ዓርብ", "ቅዳሜ"], + dayNamesMin: ["እሑ", "ሰኞ", "ማክ", "ረቡ", "ሐሙ", "ዓር", "ቅዳ"], + digits: null, + dateFormat: "dd/mm/yyyy", + firstDay: 0, + isRTL: false, + }; +})(jQuery); diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.js b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.js new file mode 100644 index 000000000..04cdb1e38 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.js @@ -0,0 +1,171 @@ +/* http://keith-wood.name/calendars.html + Ethiopian calendar for jQuery v2.1.0. + Written by Keith Wood (wood.keith{at}optusnet.com.au) February 2010. + Available under the MIT (http://keith-wood.name/licence.html) license. + Please attribute the author if you use it. */ + +(function($) { // Hide scope, no $ conflict + 'use strict'; + + /** Implementation of the Ethiopian calendar. + See http://en.wikipedia.org/wiki/Ethiopian_calendar. + See also Calendrical Calculations: The Millennium Edition + (http://emr.cs.iit.edu/home/reingold/calendar-book/index.shtml). + @class EthiopianCalendar + @param {string} [language=''] The language code (default English) for localisation. */ + function EthiopianCalendar(language) { + this.local = this.regionalOptions[language || ''] || this.regionalOptions['']; + } + + EthiopianCalendar.prototype = new $.calendars.baseCalendar(); + + $.extend(EthiopianCalendar.prototype, { + /** The calendar name. + @memberof EthiopianCalendar */ + name: 'Ethiopian', + /** Julian date of start of Ethiopian epoch: 27 August 8 CE (Gregorian). + @memberof EthiopianCalendar */ + jdEpoch: 1724220.5, + /** Days per month in a common year. + @memberof EthiopianCalendar */ + daysPerMonth: [30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 5], + /** true if has a year zero, false if not. + @memberof EthiopianCalendar */ + hasYearZero: false, + /** The minimum month number. + @memberof EthiopianCalendar */ + minMonth: 1, + /** The first month in the year. + @memberof EthiopianCalendar */ + firstMonth: 1, + /** The minimum day number. + @memberof EthiopianCalendar */ + minDay: 1, + + /** Localisations for the plugin. + Entries are objects indexed by the language code ('' being the default US/English). + Each object has the following attributes. + @memberof EthiopianCalendar + @property {string} name The calendar name. + @property {string[]} epochs The epoch names (before/after year 0). + @property {string[]} monthNames The long names of the months of the year. + @property {string[]} monthNamesShort The short names of the months of the year. + @property {string[]} dayNames The long names of the days of the week. + @property {string[]} dayNamesShort The short names of the days of the week. + @property {string[]} dayNamesMin The minimal names of the days of the week. + @property {string} dateFormat The date format for this calendar. + See the options on formatDate for details. + @property {number} firstDay The number of the first day of the week, starting at 0. + @property {boolean} isRTL true if this localisation reads right-to-left. */ + regionalOptions: { // Localisations + '': { + name: 'Ethiopian', + epochs: ['BEE', 'EE'], + monthNames: ['Meskerem', 'Tikemet', 'Hidar', 'Tahesas', 'Tir', 'Yekatit', + 'Megabit', 'Miazia', 'Genbot', 'Sene', 'Hamle', 'Nehase', 'Pagume'], + monthNamesShort: ['Mes', 'Tik', 'Hid', 'Tah', 'Tir', 'Yek', + 'Meg', 'Mia', 'Gen', 'Sen', 'Ham', 'Neh', 'Pag'], + dayNames: ['Ehud', 'Segno', 'Maksegno', 'Irob', 'Hamus', 'Arb', 'Kidame'], + dayNamesShort: ['Ehu', 'Seg', 'Mak', 'Iro', 'Ham', 'Arb', 'Kid'], + dayNamesMin: ['Eh', 'Se', 'Ma', 'Ir', 'Ha', 'Ar', 'Ki'], + digits: null, + dateFormat: 'dd/mm/yyyy', + firstDay: 0, + isRTL: false + } + }, + + /** Determine whether this date is in a leap year. + @memberof EthiopianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @return {boolean} true if this is a leap year, false if not. + @throws Error if an invalid year or a different calendar used. */ + leapYear: function(year) { + var date = this._validate(year, this.minMonth, this.minDay, $.calendars.local.invalidYear); + year = date.year() + (date.year() < 0 ? 1 : 0); // No year zero + return year % 4 === 3 || year % 4 === -1; + }, + + /** Retrieve the number of months in a year. + @memberof EthiopianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @return {number} The number of months. + @throws Error if an invalid year or a different calendar used. */ + monthsInYear: function(year) { + this._validate(year, this.minMonth, this.minDay, + $.calendars.local.invalidYear || $.calendars.regionalOptions[''].invalidYear); + return 13; + }, + + /** Determine the week of the year for a date. + @memberof EthiopianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if only year specified above). + @param {number} [day] The day to examine (if only year specified above). + @return {number} The week of the year. + @throws Error if an invalid date or a different calendar used. */ + weekOfYear: function(year, month, day) { + // Find Sunday of this week starting on Sunday + var checkDate = this.newDate(year, month, day); + checkDate.add(-checkDate.dayOfWeek(), 'd'); + return Math.floor((checkDate.dayOfYear() - 1) / 7) + 1; + }, + + /** Retrieve the number of days in a month. + @memberof EthiopianCalendar + @param {CDate|number} year The date to examine or the year of the month. + @param {number} [month] The month (if only year specified above). + @return {number} The number of days in this month. + @throws Error if an invalid month/year or a different calendar used. */ + daysInMonth: function(year, month) { + var date = this._validate(year, month, this.minDay, $.calendars.local.invalidMonth); + return this.daysPerMonth[date.month() - 1] + + (date.month() === 13 && this.leapYear(date.year()) ? 1 : 0); + }, + + /** Determine whether this date is a week day. + @memberof EthiopianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if only year specified above). + @param {number} [day] The day to examine (if only year specified above). + @return {boolean} true if a week day, false if not. + @throws Error if an invalid date or a different calendar used. */ + weekDay: function(year, month, day) { + return (this.dayOfWeek(year, month, day) || 7) < 6; + }, + + /** Retrieve the Julian date equivalent for this date, + i.e. days since January 1, 4713 BCE Greenwich noon. + @memberof EthiopianCalendar + @param {CDate|number} year The date to convert or the year to convert. + @param {number} [month] The month to convert (if only year specified above). + @param {number} [day] The day to convert (if only year specified above). + @return {number} The equivalent Julian date. + @throws Error if an invalid date or a different calendar used. */ + toJD: function(year, month, day) { + var date = this._validate(year, month, day, $.calendars.local.invalidDate); + year = date.year(); + if (year < 0) { year++; } // No year zero + return date.day() + (date.month() - 1) * 30 + + (year - 1) * 365 + Math.floor(year / 4) + this.jdEpoch - 1; + }, + + /** Create a new date from a Julian date. + @memberof EthiopianCalendar + @param {number} jd the Julian date to convert. + @return {CDate} the equivalent date. */ + fromJD: function(jd) { + var c = Math.floor(jd) + 0.5 - this.jdEpoch; + var year = Math.floor((c - Math.floor((c + 366) / 1461)) / 365) + 1; + if (year <= 0) { year--; } // No year zero + c = Math.floor(jd) + 0.5 - this.newDate(year, 1, 1).toJD(); + var month = Math.floor(c / 30) + 1; + var day = c - (month - 1) * 30 + 1; + return this.newDate(year, month, day); + } + }); + + // Ethiopian calendar implementation + $.calendars.calendars.ethiopian = EthiopianCalendar; + +})(jQuery); \ No newline at end of file diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.min.js b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.min.js new file mode 100644 index 000000000..833bc2aac --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.min.js @@ -0,0 +1,2 @@ +!function(a){"use strict";function b(a){this.local=this.regionalOptions[a||""]||this.regionalOptions[""]}b.prototype=new a.calendars.baseCalendar,a.extend(b.prototype,{name:"Ethiopian",jdEpoch:1724220.5,daysPerMonth:[30,30,30,30,30,30,30,30,30,30,30,30,5],hasYearZero:!1,minMonth:1,firstMonth:1,minDay:1,regionalOptions:{"":{name:"Ethiopian",epochs:["BEE","EE"],monthNames:["Meskerem","Tikemet","Hidar","Tahesas","Tir","Yekatit","Megabit","Miazia","Genbot","Sene","Hamle","Nehase","Pagume"],monthNamesShort:["Mes","Tik","Hid","Tah","Tir","Yek","Meg","Mia","Gen","Sen","Ham","Neh","Pag"],dayNames:["Ehud","Segno","Maksegno","Irob","Hamus","Arb","Kidame"],dayNamesShort:["Ehu","Seg","Mak","Iro","Ham","Arb","Kid"],dayNamesMin:["Eh","Se","Ma","Ir","Ha","Ar","Ki"],digits:null,dateFormat:"dd/mm/yyyy",firstDay:0,isRTL:!1}},leapYear:function(b){var c=this._validate(b,this.minMonth,this.minDay,a.calendars.local.invalidYear);return b=c.year()+(c.year()<0?1:0),b%4===3||b%4===-1},monthsInYear:function(b){return this._validate(b,this.minMonth,this.minDay,a.calendars.local.invalidYear||a.calendars.regionalOptions[""].invalidYear),13},weekOfYear:function(a,b,c){var d=this.newDate(a,b,c);return d.add(-d.dayOfWeek(),"d"),Math.floor((d.dayOfYear()-1)/7)+1},daysInMonth:function(b,c){var d=this._validate(b,c,this.minDay,a.calendars.local.invalidMonth);return this.daysPerMonth[d.month()-1]+(13===d.month()&&this.leapYear(d.year())?1:0)},weekDay:function(a,b,c){return(this.dayOfWeek(a,b,c)||7)<6},toJD:function(b,c,d){var e=this._validate(b,c,d,a.calendars.local.invalidDate);return b=e.year(),b<0&&b++,e.day()+30*(e.month()-1)+365*(b-1)+Math.floor(b/4)+this.jdEpoch-1},fromJD:function(a){var b=Math.floor(a)+.5-this.jdEpoch,c=Math.floor((b-Math.floor((b+366)/1461))/365)+1;c<=0&&c--,b=Math.floor(a)+.5-this.newDate(c,1,1).toJD();var d=Math.floor(b/30)+1,e=b-30*(d-1)+1;return this.newDate(c,d,e)}}),a.calendars.calendars.ethiopian=b}(jQuery); +//# sourceMappingURL=jquery.calendars.ethiopian.min.map \ No newline at end of file diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.min.map b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.min.map new file mode 100644 index 000000000..c4be63f74 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.ethiopian.min.map @@ -0,0 +1 @@ +{"version":3,"sources":["..\\..\\src\\js\\jquery.calendars.ethiopian.js"],"names":["$","EthiopianCalendar","language","this","local","regionalOptions","prototype","calendars","baseCalendar","extend","name","jdEpoch","daysPerMonth","hasYearZero","minMonth","firstMonth","minDay","","epochs","monthNames","monthNamesShort","dayNames","dayNamesShort","dayNamesMin","digits","dateFormat","firstDay","isRTL","leapYear","year","date","_validate","invalidYear","monthsInYear","weekOfYear","month","day","checkDate","newDate","add","dayOfWeek","Math","floor","dayOfYear","daysInMonth","invalidMonth","weekDay","toJD","invalidDate","fromJD","jd","c","ethiopian","jQuery"],"mappings":"CAMA,SAAUA,GACT,YAQA,SAASC,GAAkBC,GAC1BC,KAAKC,MAAQD,KAAKE,gBAAgBH,GAAY,KAAOC,KAAKE,gBAAgB,IAG3EJ,EAAkBK,UAAY,GAAIN,GAAEO,UAAUC,aAE9CR,EAAES,OAAOR,EAAkBK,WAG1BI,KAAM,YAGNC,QAAS,UAGTC,cAAe,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAG/DC,aAAa,EAGbC,SAAU,EAGVC,WAAY,EAGZC,OAAQ,EAiBRX,iBACCY,IACCP,KAAM,YACNQ,QAAS,MAAO,MAChBC,YAAa,WAAY,UAAW,QAAS,UAAW,MAAO,UAC/D,UAAW,SAAU,SAAU,OAAQ,QAAS,SAAU,UAC1DC,iBAAkB,MAAO,MAAO,MAAO,MAAO,MAAO,MACrD,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OAC1CC,UAAW,OAAQ,QAAS,WAAY,OAAQ,QAAS,MAAO,UAChEC,eAAgB,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OAC1DC,aAAc,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAClDC,OAAQ,KACRC,WAAY,aACZC,SAAU,EACVC,OAAO,IASTC,SAAU,SAASC,GAClB,GAAIC,GAAO3B,KAAK4B,UAAUF,EAAM1B,KAAKW,SAAUX,KAAKa,OAAQhB,EAAEO,UAAUH,MAAM4B,YAE9E,OADAH,GAAOC,EAAKD,QAAUC,EAAKD,OAAS,EAAI,EAAI,GACrCA,EAAO,IAAM,GAAKA,EAAO,KAAM,GAQvCI,aAAc,SAASJ,GAGtB,MAFA1B,MAAK4B,UAAUF,EAAM1B,KAAKW,SAAUX,KAAKa,OACxChB,EAAEO,UAAUH,MAAM4B,aAAehC,EAAEO,UAAUF,gBAAgB,IAAI2B,aAC3D,IAURE,WAAY,SAASL,EAAMM,EAAOC,GAEjC,GAAIC,GAAYlC,KAAKmC,QAAQT,EAAMM,EAAOC,EAE1C,OADAC,GAAUE,KAAKF,EAAUG,YAAa,KAC/BC,KAAKC,OAAOL,EAAUM,YAAc,GAAK,GAAK,GAStDC,YAAa,SAASf,EAAMM,GAC3B,GAAIL,GAAO3B,KAAK4B,UAAUF,EAAMM,EAAOhC,KAAKa,OAAQhB,EAAEO,UAAUH,MAAMyC,aACtE,OAAO1C,MAAKS,aAAakB,EAAKK,QAAU,IACrB,KAAjBL,EAAKK,SAAkBhC,KAAKyB,SAASE,EAAKD,QAAU,EAAI,IAU3DiB,QAAS,SAASjB,EAAMM,EAAOC,GAC9B,OAAQjC,KAAKqC,UAAUX,EAAMM,EAAOC,IAAQ,GAAK,GAWlDW,KAAM,SAASlB,EAAMM,EAAOC,GAC3B,GAAIN,GAAO3B,KAAK4B,UAAUF,EAAMM,EAAOC,EAAKpC,EAAEO,UAAUH,MAAM4C,YAG9D,OAFAnB,GAAOC,EAAKD,OACRA,EAAO,GAAKA,IACTC,EAAKM,MAA6B,IAApBN,EAAKK,QAAU,GACtB,KAAZN,EAAO,GAAWY,KAAKC,MAAMb,EAAO,GAAK1B,KAAKQ,QAAU,GAO3DsC,OAAQ,SAASC,GAChB,GAAIC,GAAIV,KAAKC,MAAMQ,GAAM,GAAM/C,KAAKQ,QAChCkB,EAAOY,KAAKC,OAAOS,EAAIV,KAAKC,OAAOS,EAAI,KAAO,OAAS,KAAO,CAC9DtB,IAAQ,GAAKA,IACjBsB,EAAIV,KAAKC,MAAMQ,GAAM,GAAM/C,KAAKmC,QAAQT,EAAM,EAAG,GAAGkB,MACpD,IAAIZ,GAAQM,KAAKC,MAAMS,EAAI,IAAM,EAC7Bf,EAAMe,EAAkB,IAAbhB,EAAQ,GAAU,CACjC,OAAOhC,MAAKmC,QAAQT,EAAMM,EAAOC,MAKnCpC,EAAEO,UAAUA,UAAU6C,UAAYnD,GAEhCoD","file":"jquery.calendars.ethiopian.min.js"} \ No newline at end of file diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.js b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.js new file mode 100644 index 000000000..8480948ef --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.js @@ -0,0 +1,982 @@ +/* http://keith-wood.name/calendars.html + Calendars for jQuery v2.1.0. + Written by Keith Wood (wood.keith{at}optusnet.com.au) August 2009. + Available under the MIT (http://keith-wood.name/licence.html) license. + Please attribute the author if you use it. */ + +(function($) { // Hide scope, no $ conflict + 'use strict'; + + function Calendars() { + this.regionalOptions = []; + /** Localised values. + @memberof Calendars + @property {string} [invalidCalendar='Calendar {0} not found'] + Error message for an unknown calendar. + @property {string} [invalidDate='Invalid {0} date'] + Error message for an invalid date for this calendar. + @property {string} [invalidMonth='Invalid {0} month'] + Error message for an invalid month for this calendar. + @property {string} [invalidYear='Invalid {0} year'] + Error message for an invalid year for this calendar. + @property {string} [differentCalendars='Cannot mix {0} and {1} dates'] + Error message for mixing different calendars. */ + this.regionalOptions[''] = { + invalidCalendar: 'Calendar {0} not found', + invalidDate: 'Invalid {0} date', + invalidMonth: 'Invalid {0} month', + invalidYear: 'Invalid {0} year', + differentCalendars: 'Cannot mix {0} and {1} dates' + }; + this.local = this.regionalOptions['']; + this.calendars = {}; + this._localCals = {}; + } + + /** Create the calendars plugin. +

Provides support for various world calendars in a consistent manner.

+

Use the global instance, $.calendars, to access the functionality.

+ @class Calendars + @example $.calendars.instance('julian').newDate(2014, 12, 25) */ + $.extend(Calendars.prototype, { + + /** Obtain a calendar implementation and localisation. + @memberof Calendars + @param {string} [name='gregorian'] The name of the calendar, e.g. 'gregorian', 'persian', 'islamic'. + @param {string} [language=''] The language code to use for localisation (default is English). + @return {Calendar} The calendar and localisation. + @throws Error if calendar not found. + @example $.calendars.instance() +$.calendars.instance('persian') +$.calendars.instance('hebrew', 'he') */ + instance: function(name, language) { + name = (name || 'gregorian').toLowerCase(); + language = language || ''; + var cal = this._localCals[name + '-' + language]; + if (!cal && this.calendars[name]) { + cal = new this.calendars[name](language); + this._localCals[name + '-' + language] = cal; + } + if (!cal) { + throw (this.local.invalidCalendar || this.regionalOptions[''].invalidCalendar). + replace(/\{0\}/, name); + } + return cal; + }, + + /** Create a new date - for today if no other parameters given. + @memberof Calendars + @param {CDate|number} [year] The date to copy or the year for the date. + @param {number} [month] The month for the date (if numeric year specified above). + @param {number} [day] The day for the date (if numeric year specified above). + @param {BaseCalendar|string} [calendar='gregorian'] The underlying calendar or the name of the calendar. + @param {string} [language=''] The language to use for localisation (default English). + @return {CDate} The new date. + @throws Error if an invalid date. + @example $.calendars.newDate() +$.calendars.newDate(otherDate) +$.calendars.newDate(2001, 1, 1) +$.calendars.newDate(1379, 10, 12, 'persian') */ + newDate: function(year, month, day, calendar, language) { + calendar = ((typeof year !== 'undefined' && year !== null) && year.year ? year.calendar() : + (typeof calendar === 'string' ? this.instance(calendar, language) : calendar)) || this.instance(); + return calendar.newDate(year, month, day); + }, + + /** A simple digit substitution function for localising numbers via the + {@linkcode GregorianCalendar.regionalOptions|Calendar digits} option. + @memberof Calendars + @param {string[]} digits The substitute digits, for 0 through 9. + @return {CalendarsDigits} The substitution function. + @example digits: $.calendars.substituteDigits(['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']) */ + substituteDigits: function(digits) { + return function(value) { + return (value + '').replace(/[0-9]/g, function(digit) { + return digits[digit]; + }); + }; + }, + + /** Digit substitution function for localising Chinese style numbers via the + {@linkcode GregorianCalendar.regionalOptions|Calendar digits} option. + @memberof Calendars + @param {string[]} digits The substitute digits, for 0 through 9. + @param {string[]} powers The characters denoting powers of 10, i.e. 1, 10, 100, 1000. + @return {CalendarsDigits} The substitution function. + @example digits: $.calendars.substituteChineseDigits( + ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九'], ['', '十', '百', '千']) */ + substituteChineseDigits: function(digits, powers) { + return function(value) { + var localNumber = ''; + var power = 0; + while (value > 0) { + var units = value % 10; + localNumber = (units === 0 ? '' : digits[units] + powers[power]) + localNumber; + power++; + value = Math.floor(value / 10); + } + if (localNumber.indexOf(digits[1] + powers[1]) === 0) { + localNumber = localNumber.substr(1); + } + return localNumber || digits[0]; + }; + } + }); + + /** Generic date, based on a particular calendar. + @class CDate + @param {BaseCalendar} calendar The underlying calendar implementation. + @param {number} year The year for this date. + @param {number} month The month for this date. + @param {number} day The day for this date. + @return {CDate} The date object. + @throws Error if an invalid date. */ + function CDate(calendar, year, month, day) { + this._calendar = calendar; + this._year = year; + this._month = month; + this._day = day; + if (this._calendar._validateLevel === 0 && + !this._calendar.isValid(this._year, this._month, this._day)) { + throw ($.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate). + replace(/\{0\}/, this._calendar.local.name); + } + } + + /** Pad a numeric value with leading zeroes. + @private + @param {number} value The number to format. + @param {number} length The minimum length. + @return {string} The formatted number. */ + function pad(value, length) { + value = '' + value; + return '000000'.substring(0, length - value.length) + value; + } + + $.extend(CDate.prototype, { + + /** Create a new date. + @memberof CDate + @param {CDate|number} [year] The date to copy or the year for the date (default to this date). + @param {number} [month] The month for the date (if numeric year specified above). + @param {number} [day] The day for the date (if numeric year specified above). + @return {CDate} The new date. + @throws Error if an invalid date. + @example date.newDate() +date.newDate(otherDate) +date.newDate(2001, 1, 1) */ + newDate: function(year, month, day) { + return this._calendar.newDate((typeof year === 'undefined' || year === null ? this : year), month, day); + }, + + /** Set or retrieve the year for this date. + @memberof CDate + @param {number} [year] The year for the date. + @return {number|CDate} The date's year (if no parameter) or the updated date. + @throws Error if an invalid date. + @example date.year(2001) +var year = date.year() */ + year: function(year) { + return (arguments.length === 0 ? this._year : this.set(year, 'y')); + }, + + /** Set or retrieve the month for this date. + @memberof CDate + @param {number} [month] The month for the date. + @return {number|CDate} The date's month (if no parameter) or the updated date. + @throws Error if an invalid date. + @example date.month(1) +var month = date.month() */ + month: function(month) { + return (arguments.length === 0 ? this._month : this.set(month, 'm')); + }, + + /** Set or retrieve the day for this date. + @memberof CDate + @param {number} [day] The day for the date. + @return {number|CData} The date's day (if no parameter) or the updated date. + @throws Error if an invalid date. + @example date.day(1) +var day = date.day() */ + day: function(day) { + return (arguments.length === 0 ? this._day : this.set(day, 'd')); + }, + + /** Set new values for this date. + @memberof CDate + @param {number} year The year for the date. + @param {number} month The month for the date. + @param {number} day The day for the date. + @return {CDate} The updated date. + @throws Error if an invalid date. + @example date.date(2001, 1, 1) */ + date: function(year, month, day) { + if (!this._calendar.isValid(year, month, day)) { + throw ($.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate). + replace(/\{0\}/, this._calendar.local.name); + } + this._year = year; + this._month = month; + this._day = day; + return this; + }, + + /** Determine whether this date is in a leap year. + @memberof CDate + @return {boolean} true if this is a leap year, false if not. + @example if (date.leapYear()) ...*/ + leapYear: function() { + return this._calendar.leapYear(this); + }, + + /** Retrieve the epoch designator for this date, e.g. BCE or CE. + @memberof CDate + @return {string} The current epoch. + @example var epoch = date.epoch() */ + epoch: function() { + return this._calendar.epoch(this); + }, + + /** Format the year, if not a simple sequential number. + @memberof CDate + @return {string} The formatted year. + @example var year = date.formatYear() */ + formatYear: function() { + return this._calendar.formatYear(this); + }, + + /** Retrieve the month of the year for this date, + i.e. the month's position within a numbered year. + @memberof CDate + @return {number} The month of the year: minMonth to months per year. + @example var month = date.monthOfYear() */ + monthOfYear: function() { + return this._calendar.monthOfYear(this); + }, + + /** Retrieve the week of the year for this date. + @memberof CDate + @return {number} The week of the year: 1 to weeks per year. + @example var week = date.weekOfYear() */ + weekOfYear: function() { + return this._calendar.weekOfYear(this); + }, + + /** Retrieve the number of days in the year for this date. + @memberof CDate + @return {number} The number of days in this year. + @example var days = date.daysInYear() */ + daysInYear: function() { + return this._calendar.daysInYear(this); + }, + + /** Retrieve the day of the year for this date. + @memberof CDate + @return {number} The day of the year: 1 to days per year. + @example var doy = date.dayOfYear() */ + dayOfYear: function() { + return this._calendar.dayOfYear(this); + }, + + /** Retrieve the number of days in the month for this date. + @memberof CDate + @return {number} The number of days. + @example var days = date.daysInMonth() */ + daysInMonth: function() { + return this._calendar.daysInMonth(this); + }, + + /** Retrieve the day of the week for this date. + @memberof CDate + @return {number} The day of the week: 0 to number of days - 1. + @example var dow = date.dayOfWeek() */ + dayOfWeek: function() { + return this._calendar.dayOfWeek(this); + }, + + /** Determine whether this date is a week day. + @memberof CDate + @return {boolean} true if a week day, false if not. + @example if (date.weekDay()) ... */ + weekDay: function() { + return this._calendar.weekDay(this); + }, + + /** Retrieve additional information about this date. + @memberof CDate + @return {object} Additional information - contents depends on calendar. + @example var info = date.extraInfo() */ + extraInfo: function() { + return this._calendar.extraInfo(this); + }, + + /** Add period(s) to a date. + @memberof CDate + @param {number} offset The number of periods to adjust by. + @param {string} period One of 'y' for years, 'm' for months, 'w' for weeks, 'd' for days. + @return {CDate} The updated date. + @example date.add(10, 'd') */ + add: function(offset, period) { + return this._calendar.add(this, offset, period); + }, + + /** Set a portion of the date. + @memberof CDate + @param {number} value The new value for the period. + @param {string} period One of 'y' for year, 'm' for month, 'd' for day. + @return {CDate} The updated date. + @throws Error if not a valid date. + @example date.set(10, 'd') */ + set: function(value, period) { + return this._calendar.set(this, value, period); + }, + + /** Compare this date to another date. + @memberof CDate + @param {CDate} date The other date. + @return {number} -1 if this date is before the other date, + 0 if they are equal, or +1 if this date is after the other date. + @example if (date1.compareTo(date2) < 0) ... */ + compareTo: function(date) { + if (this._calendar.name !== date._calendar.name) { + throw ($.calendars.local.differentCalendars || $.calendars.regionalOptions[''].differentCalendars). + replace(/\{0\}/, this._calendar.local.name).replace(/\{1\}/, date._calendar.local.name); + } + var c = (this._year !== date._year ? this._year - date._year : + this._month !== date._month ? this.monthOfYear() - date.monthOfYear() : + this._day - date._day); + return (c === 0 ? 0 : (c < 0 ? -1 : +1)); + }, + + /** Retrieve the calendar backing this date. + @memberof CDate + @return {BaseCalendar} The calendar implementation. + @example var cal = date.calendar() */ + calendar: function() { + return this._calendar; + }, + + /** Retrieve the Julian date equivalent for this date, + i.e. days since January 1, 4713 BCE Greenwich noon. + @memberof CDate + @return {number} The equivalent Julian date. + @example var jd = date.toJD() */ + toJD: function() { + return this._calendar.toJD(this); + }, + + /** Create a new date from a Julian date. + @memberof CDate + @param {number} jd The Julian date to convert. + @return {CDate} The equivalent date. + @example var date2 = date1.fromJD(jd) */ + fromJD: function(jd) { + return this._calendar.fromJD(jd); + }, + + /** Convert this date to a standard (Gregorian) JavaScript Date. + @memberof CDate + @return {Date} The equivalent JavaScript date. + @example var jsd = date.toJSDate() */ + toJSDate: function() { + return this._calendar.toJSDate(this); + }, + + /** Create a new date from a standard (Gregorian) JavaScript Date. + @memberof CDate + @param {Date} jsd The JavaScript date to convert. + @return {CDate} The equivalent date. + @example var date2 = date1.fromJSDate(jsd) */ + fromJSDate: function(jsd) { + return this._calendar.fromJSDate(jsd); + }, + + /** Convert to a string for display. + @memberof CDate + @return {string} This date as a string. */ + toString: function() { + return (this.year() < 0 ? '-' : '') + pad(Math.abs(this.year()), 4) + + '-' + pad(this.month(), 2) + '-' + pad(this.day(), 2); + } + }); + + /** Basic functionality for all calendars. + Other calendars should extend this: +
OtherCalendar.prototype = new BaseCalendar();
+ @class BaseCalendar */ + function BaseCalendar() { + this.shortYearCutoff = '+10'; + } + + $.extend(BaseCalendar.prototype, { + _validateLevel: 0, // "Stack" to turn validation on/off + + /** Create a new date within this calendar - today if no parameters given. + @memberof BaseCalendar + @param {CDate|number} year The date to duplicate or the year for the date. + @param {number} [month] The month for the date (if numeric year specified above). + @param {number} [day] The day for the date (if numeric year specified above). + @return {CDate} The new date. + @throws Error if not a valid date or a different calendar is used. + @example var date = calendar.newDate(2014, 1, 26) +var date2 = calendar.newDate(date1) +var today = calendar.newDate() */ + newDate: function(year, month, day) { + if (typeof year === 'undefined' || year === null) { + return this.today(); + } + if (year.year) { + this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + day = year.day(); + month = year.month(); + year = year.year(); + } + return new CDate(this, year, month, day); + }, + + /** Create a new date for today. + @memberof BaseCalendar + @return {CDate} Today's date. + @example var today = calendar.today() */ + today: function() { + return this.fromJSDate(new Date()); + }, + + /** Retrieve the epoch designator for this date. + @memberof BaseCalendar + @param {CDate|number} year The date to examine or the year to examine. + @return {string} The current epoch. + @throws Error if an invalid year or a different calendar is used. + @example var epoch = calendar.epoch(date) +var epoch = calendar.epoch(2014) */ + epoch: function(year) { + var date = this._validate(year, this.minMonth, this.minDay, + $.calendars.local.invalidYear || $.calendars.regionalOptions[''].invalidYear); + return (date.year() < 0 ? this.local.epochs[0] : this.local.epochs[1]); + }, + + /** Format the year, if not a simple sequential number + @memberof BaseCalendar + @param {CDate|number} year The date to format or the year to format. + @return {string} The formatted year. + @throws Error if an invalid year or a different calendar is used. + @example var year = calendar.formatYear(date) +var year = calendar.formatYear(2014) */ + formatYear: function(year) { + var date = this._validate(year, this.minMonth, this.minDay, + $.calendars.local.invalidYear || $.calendars.regionalOptions[''].invalidYear); + return (date.year() < 0 ? '-' : '') + pad(Math.abs(date.year()), 4); + }, + + /** Retrieve the number of months in a year. + @memberof BaseCalendar + @param {CDate|number} year The date to examine or the year to examine. + @return {number} The number of months. + @throws Error if an invalid year or a different calendar is used. + @example var months = calendar.monthsInYear(date) +var months = calendar.monthsInYear(2014) */ + monthsInYear: function(year) { + this._validate(year, this.minMonth, this.minDay, + $.calendars.local.invalidYear || $.calendars.regionalOptions[''].invalidYear); + return 12; + }, + + /** Calculate the month's ordinal position within the year - + for those calendars that don't start at month 1! + @memberof BaseCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if numeric year specified above). + @return {number} The ordinal position, starting from minMonth. + @throws Error if an invalid year/month or a different calendar is used. + @example var pos = calendar.monthOfYear(date) +var pos = calendar.monthOfYear(2014, 7) */ + monthOfYear: function(year, month) { + var date = this._validate(year, month, this.minDay, + $.calendars.local.invalidMonth || $.calendars.regionalOptions[''].invalidMonth); + return (date.month() + this.monthsInYear(date) - this.firstMonth) % + this.monthsInYear(date) + this.minMonth; + }, + + /** Calculate actual month from ordinal position, starting from minMonth. + @memberof BaseCalendar + @param {number} year The year to examine. + @param {number} ord The month's ordinal position. + @return {number} The month's number. + @throws Error if an invalid year/month. + @example var month = calendar.fromMonthOfYear(2014, 7) */ + fromMonthOfYear: function(year, ord) { + var m = (ord + this.firstMonth - 2 * this.minMonth) % + this.monthsInYear(year) + this.minMonth; + this._validate(year, m, this.minDay, + $.calendars.local.invalidMonth || $.calendars.regionalOptions[''].invalidMonth); + return m; + }, + + /** Retrieve the number of days in a year. + @memberof BaseCalendar + @param {CDate|number} year The date to examine or the year to examine. + @return {number} The number of days. + @throws Error if an invalid year or a different calendar is used. + @example var days = calendar.daysInYear(date) +var days = calendar.daysInYear(2014) */ + daysInYear: function(year) { + var date = this._validate(year, this.minMonth, this.minDay, + $.calendars.local.invalidYear || $.calendars.regionalOptions[''].invalidYear); + return (this.leapYear(date) ? 366 : 365); + }, + + /** Retrieve the day of the year for a date. + @memberof BaseCalendar + @param {CDate|number} year The date to convert or the year to convert. + @param {number} [month] The month to convert (if numeric year specified above). + @param {number} [day] The day to convert (if numeric year specified above). + @return {number} The day of the year: 1 to days per year. + @throws Error if an invalid date or a different calendar is used. + @example var doy = calendar.dayOfYear(date) +var doy = calendar.dayOfYear(2014, 7, 1) */ + dayOfYear: function(year, month, day) { + var date = this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + return date.toJD() - this.newDate(date.year(), + this.fromMonthOfYear(date.year(), this.minMonth), this.minDay).toJD() + 1; + }, + + /** Retrieve the number of days in a week. + @memberof BaseCalendar + @return {number} The number of days. + @example var days = calendar.daysInWeek() */ + daysInWeek: function() { + return 7; + }, + + /** Retrieve the day of the week for a date. + @memberof BaseCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if numeric year specified above). + @param {number} [day] The day to examine (if numeric year specified above). + @return {number} The day of the week: 0 to number of days - 1. + @throws Error if an invalid date or a different calendar is used. + @example var dow = calendar.dayOfWeek(date) +var dow = calendar.dayOfWeek(2014, 1, 26) */ + dayOfWeek: function(year, month, day) { + var date = this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + return (Math.floor(this.toJD(date)) + 2) % this.daysInWeek(); + }, + + /** Retrieve additional information about a date. + @memberof BaseCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if numeric year specified above). + @param {number} [day] The day to examine (if numeric year specified above). + @return {object} Additional information - content depends on calendar. + @throws Error if an invalid date or a different calendar is used. + @example var info = calendar.extraInfo(date) +var info = calendar.extraInfo(2014, 1, 26) */ + extraInfo: function(year, month, day) { + this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + return {}; + }, + + /** Add period(s) to a date. + Cater for no year zero. + @memberof BaseCalendar + @param {CDate} date The starting date. + @param {number} offset The number of periods to adjust by. + @param {string} period One of 'y' for years, 'm' for months, 'w' for weeks, 'd' for days. + @return {CDate} The updated date. + @throws Error if a different calendar is used. + @example calendar.add(date, 10, 'd') */ + add: function(date, offset, period) { + this._validate(date, this.minMonth, this.minDay, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + return this._correctAdd(date, this._add(date, offset, period), offset, period); + }, + + /** Add period(s) to a date. + @memberof BaseCalendar + @private + @param {CDate} date The starting date. + @param {number} offset The number of periods to adjust by. + @param {string} period One of 'y' for years, 'm' for months, 'w' for weeks, 'd' for days. + @return {number[]} The updated date as year, month, and day. */ + _add: function(date, offset, period) { + this._validateLevel++; + var d; + if (period === 'd' || period === 'w') { + var jd = date.toJD() + offset * (period === 'w' ? this.daysInWeek() : 1); + d = date.calendar().fromJD(jd); + this._validateLevel--; + return [d.year(), d.month(), d.day()]; + } + try { + var y = date.year() + (period === 'y' ? offset : 0); + var m = date.monthOfYear() + (period === 'm' ? offset : 0); + d = date.day(); + var resyncYearMonth = function(calendar) { + while (m < calendar.minMonth) { + y--; + m += calendar.monthsInYear(y); + } + var yearMonths = calendar.monthsInYear(y); + while (m > yearMonths - 1 + calendar.minMonth) { + y++; + m -= yearMonths; + yearMonths = calendar.monthsInYear(y); + } + }; + if (period === 'y') { + if (date.month() !== this.fromMonthOfYear(y, m)) { // Hebrew + m = this.newDate(y, date.month(), this.minDay).monthOfYear(); + } + m = Math.min(m, this.monthsInYear(y)); + d = Math.min(d, this.daysInMonth(y, this.fromMonthOfYear(y, m))); + } + else if (period === 'm') { + resyncYearMonth(this); + d = Math.min(d, this.daysInMonth(y, this.fromMonthOfYear(y, m))); + } + var ymd = [y, this.fromMonthOfYear(y, m), d]; + this._validateLevel--; + return ymd; + } + catch (e) { + this._validateLevel--; + throw e; + } + }, + + /** Correct a candidate date after adding period(s) to a date. + Handle no year zero if necessary. + @memberof BaseCalendar + @private + @param {CDate} date The starting date. + @param {number[]} ymd The added date. + @param {number} offset The number of periods to adjust by. + @param {string} period One of 'y' for years, 'm' for months, 'w' for weeks, 'd' for days. + @return {CDate} The updated date. */ + _correctAdd: function(date, ymd, offset, period) { + if (!this.hasYearZero && (period === 'y' || period === 'm')) { + if (ymd[0] === 0 || // In year zero + (date.year() > 0) !== (ymd[0] > 0)) { // Crossed year zero + var adj = {y: [1, 1, 'y'], m: [1, this.monthsInYear(-1), 'm'], + w: [this.daysInWeek(), this.daysInYear(-1), 'd'], + d: [1, this.daysInYear(-1), 'd']}[period]; + var dir = (offset < 0 ? -1 : +1); + ymd = this._add(date, offset * adj[0] + dir * adj[1], adj[2]); + } + } + return date.date(ymd[0], ymd[1], ymd[2]); + }, + + /** Set a portion of the date. + @memberof BaseCalendar + @param {CDate} date The starting date. + @param {number} value The new value for the period. + @param {string} period One of 'y' for year, 'm' for month, 'd' for day. + @return {CDate} The updated date. + @throws Error if an invalid date or a different calendar is used. + @example calendar.set(date, 10, 'd') */ + set: function(date, value, period) { + this._validate(date, this.minMonth, this.minDay, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + var y = (period === 'y' ? value : date.year()); + var m = (period === 'm' ? value : date.month()); + var d = (period === 'd' ? value : date.day()); + if (period === 'y' || period === 'm') { + d = Math.min(d, this.daysInMonth(y, m)); + } + return date.date(y, m, d); + }, + + /** Determine whether a date is valid for this calendar. + @memberof BaseCalendar + @param {number} year The year to examine. + @param {number} month The month to examine. + @param {number} day The day to examine. + @return {boolean} true if a valid date, false if not. + @example if (calendar.isValid(2014, 2, 31)) ... */ + isValid: function(year, month, day) { + this._validateLevel++; + var valid = (this.hasYearZero || year !== 0); + if (valid) { + var date = this.newDate(year, month, this.minDay); + valid = (month >= this.minMonth && month - this.minMonth < this.monthsInYear(date)) && + (day >= this.minDay && day - this.minDay < this.daysInMonth(date)); + } + this._validateLevel--; + return valid; + }, + + /** Convert the date to a standard (Gregorian) JavaScript Date. + @memberof BaseCalendar + @param {CDate|number} year The date to convert or the year to convert. + @param {number} [month] The month to convert (if numeric year specified above). + @param {number} [day] The day to convert (if numeric year specified above). + @return {Date} The equivalent JavaScript date. + @throws Error if an invalid date or a different calendar is used. + @example var jsd = calendar.toJSDate(date) +var jsd = calendar.toJSDate(2014, 1, 26) */ + toJSDate: function(year, month, day) { + var date = this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + return $.calendars.instance().fromJD(this.toJD(date)).toJSDate(); + }, + + /** Convert the date from a standard (Gregorian) JavaScript Date. + @memberof BaseCalendar + @param {Date} jsd The JavaScript date. + @return {CDate} The equivalent calendar date. + @example var date = calendar.fromJSDate(jsd) */ + fromJSDate: function(jsd) { + return this.fromJD($.calendars.instance().fromJSDate(jsd).toJD()); + }, + + /** Check that a candidate date is from the same calendar and is valid. + @memberof BaseCalendar + @private + @param {CDate|number} year The date to validate or the year to validate. + @param {number} [month] The month to validate (if numeric year specified above). + @param {number} [day] The day to validate (if numeric year specified above). + @param {string} error Error message if invalid. + @throws Error if an invalid date or a different calendar is used. */ + _validate: function(year, month, day, error) { + if (year.year) { + if (this._validateLevel === 0 && this.name !== year.calendar().name) { + throw ($.calendars.local.differentCalendars || $.calendars.regionalOptions[''].differentCalendars). + replace(/\{0\}/, this.local.name).replace(/\{1\}/, year.calendar().local.name); + } + return year; + } + try { + this._validateLevel++; + if (this._validateLevel === 1 && !this.isValid(year, month, day)) { + throw error.replace(/\{0\}/, this.local.name); + } + var date = this.newDate(year, month, day); + this._validateLevel--; + return date; + } + catch (e) { + this._validateLevel--; + throw e; + } + } + }); + + /** Implementation of the Proleptic Gregorian Calendar. + See http://en.wikipedia.org/wiki/Gregorian_calendar + and http://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar. + @class GregorianCalendar + @augments BaseCalendar + @param {string} [language=''] The language code (default English) for localisation. */ + function GregorianCalendar(language) { + this.local = this.regionalOptions[language] || this.regionalOptions['']; + } + + GregorianCalendar.prototype = new BaseCalendar(); + + $.extend(GregorianCalendar.prototype, { + /** The calendar name. + @memberof GregorianCalendar */ + name: 'Gregorian', + /** Julian date of start of Gregorian epoch: 1 January 0001 CE. + @memberof GregorianCalendar */ + jdEpoch: 1721425.5, + /** Days per month in a common year. + @memberof GregorianCalendar */ + daysPerMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + /** true if has a year zero, false if not. + @memberof GregorianCalendar */ + hasYearZero: false, + /** The minimum month number. + @memberof GregorianCalendar */ + minMonth: 1, + /** The first month in the year. + @memberof GregorianCalendar */ + firstMonth: 1, + /** The minimum day number. + @memberof GregorianCalendar */ + minDay: 1, + + /** Convert a number into a localised form. + @callback CalendarsDigits + @param {number} value The number to convert. + @return {string} The localised number. + @example digits: $.calendars.substituteDigits(['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']) */ + + /** Localisations for the plugin. + Entries are objects indexed by the language code ('' being the default US/English). + Each object has the following attributes. + @memberof GregorianCalendar + @property {string} [name='Gregorian'] The calendar name. + @property {string[]} [epochs=['BCE','CE']] The epoch names. + @property {string[]} [monthNames=[...]] The long names of the months of the year. + @property {string[]} [monthNamesShort=[...]] The short names of the months of the year. + @property {string[]} [dayNames=[...]] The long names of the days of the week. + @property {string[]} [dayNamesShort=[...]] The short names of the days of the week. + @property {string[]} [dayNamesMin=[...]] The minimal names of the days of the week. + @property {CalendarsDigits} [digits=null] Convert numbers to localised versions. + @property {string} [dateFormat='mm/dd/yyyy'] The date format for this calendar. + See the options on {@linkcode BaseCalendar.formatDate|formatDate} for details. + @property {number} [firstDay=0] The number of the first day of the week, starting at 0. + @property {boolean} [isRTL=false] true if this localisation reads right-to-left. */ + regionalOptions: { // Localisations + '': { + name: 'Gregorian', + epochs: ['BCE', 'CE'], + 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'], + digits: null, + dateFormat: 'mm/dd/yyyy', + firstDay: 0, + isRTL: false + } + }, + + /** Determine whether this date is in a leap year. + @memberof GregorianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @return {boolean} true if this is a leap year, false if not. + @throws Error if an invalid year or a different calendar is used. */ + leapYear: function(year) { + var date = this._validate(year, this.minMonth, this.minDay, + $.calendars.local.invalidYear || $.calendars.regionalOptions[''].invalidYear); + year = date.year() + (date.year() < 0 ? 1 : 0); // No year zero + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + }, + + /** Determine the week of the year for a date - ISO 8601. + @memberof GregorianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if numeric year specified above). + @param {number} [day] The day to examine (if numeric year specified above). + @return {number} The week of the year, starting from 1. + @throws Error if an invalid date or a different calendar is used. */ + weekOfYear: function(year, month, day) { + // Find Thursday of this week starting on Monday + var checkDate = this.newDate(year, month, day); + checkDate.add(4 - (checkDate.dayOfWeek() || 7), 'd'); + return Math.floor((checkDate.dayOfYear() - 1) / 7) + 1; + }, + + /** Retrieve the number of days in a month. + @memberof GregorianCalendar + @param {CDate|number} year The date to examine or the year of the month. + @param {number} [month] The month (if numeric year specified above). + @return {number} The number of days in this month. + @throws Error if an invalid month/year or a different calendar is used. */ + daysInMonth: function(year, month) { + var date = this._validate(year, month, this.minDay, + $.calendars.local.invalidMonth || $.calendars.regionalOptions[''].invalidMonth); + return this.daysPerMonth[date.month() - 1] + + (date.month() === 2 && this.leapYear(date.year()) ? 1 : 0); + }, + + /** Determine whether this date is a week day. + @memberof GregorianCalendar + @param {CDate|number} year The date to examine or the year to examine. + @param {number} [month] The month to examine (if numeric year specified above). + @param {number} [day] The day to examine (if numeric year specified above). + @return {boolean} true if a week day, false if not. + @throws Error if an invalid date or a different calendar is used. */ + weekDay: function(year, month, day) { + return (this.dayOfWeek(year, month, day) || 7) < 6; + }, + + /** Retrieve the Julian date equivalent for this date, + i.e. days since January 1, 4713 BCE Greenwich noon. + @memberof GregorianCalendar + @param {CDate|number} year The date to convert or the year to convert. + @param {number} [month] The month to convert (if numeric year specified above). + @param {number} [day] The day to convert (if numeric year specified above). + @return {number} The equivalent Julian date. + @throws Error if an invalid date or a different calendar is used. */ + toJD: function(year, month, day) { + var date = this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + year = date.year(); + month = date.month(); + day = date.day(); + if (year < 0) { year++; } // No year zero + // Jean Meeus algorithm, "Astronomical Algorithms", 1991 + if (month < 3) { + month += 12; + year--; + } + var a = Math.floor(year / 100); + var b = 2 - a + Math.floor(a / 4); + return Math.floor(365.25 * (year + 4716)) + + Math.floor(30.6001 * (month + 1)) + day + b - 1524.5; + }, + + /** Create a new date from a Julian date. + @memberof GregorianCalendar + @param {number} jd The Julian date to convert. + @return {CDate} The equivalent date. */ + fromJD: function(jd) { + // Jean Meeus algorithm, "Astronomical Algorithms", 1991 + var z = Math.floor(jd + 0.5); + var a = Math.floor((z - 1867216.25) / 36524.25); + a = z + 1 + a - Math.floor(a / 4); + var b = a + 1524; + var c = Math.floor((b - 122.1) / 365.25); + var d = Math.floor(365.25 * c); + var e = Math.floor((b - d) / 30.6001); + var day = b - d - Math.floor(e * 30.6001); + var month = e - (e > 13.5 ? 13 : 1); + var year = c - (month > 2.5 ? 4716 : 4715); + if (year <= 0) { year--; } // No year zero + return this.newDate(year, month, day); + }, + + /** Convert this date to a standard (Gregorian) JavaScript Date. + @memberof GregorianCalendar + @param {CDate|number} year The date to convert or the year to convert. + @param {number} [month] The month to convert (if numeric year specified above). + @param {number} [day] The day to convert (if numeric year specified above). + @return {Date} The equivalent JavaScript date. + @throws Error if an invalid date or a different calendar is used. */ + toJSDate: function(year, month, day) { + var date = this._validate(year, month, day, + $.calendars.local.invalidDate || $.calendars.regionalOptions[''].invalidDate); + var jsd = new Date(date.year(), date.month() - 1, date.day()); + jsd.setHours(0); + jsd.setMinutes(0); + jsd.setSeconds(0); + jsd.setMilliseconds(0); + // Hours may be non-zero on daylight saving cut-over: + // > 12 when midnight changeover, but then cannot generate + // midnight datetime, so jump to 1AM, otherwise reset. + jsd.setHours(jsd.getHours() > 12 ? jsd.getHours() + 2 : 0); + return jsd; + }, + + /** Create a new date from a standard (Gregorian) JavaScript Date. + @memberof GregorianCalendar + @param {Date} jsd The JavaScript date to convert. + @return {CDate} The equivalent date. */ + fromJSDate: function(jsd) { + return this.newDate(jsd.getFullYear(), jsd.getMonth() + 1, jsd.getDate()); + } + }); + + // Singleton manager + $.calendars = new Calendars(); + + // Date template + $.calendars.cdate = CDate; + + // Base calendar template + $.calendars.baseCalendar = BaseCalendar; + + // Gregorian calendar implementation + $.calendars.calendars.gregorian = GregorianCalendar; + +})(jQuery); diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.picker.js b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.picker.js new file mode 100644 index 000000000..899448f82 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.picker.js @@ -0,0 +1,1946 @@ +/* http://keith-wood.name/calendars.html + Calendars date picker for jQuery v2.1.0. + Written by Keith Wood (wood.keith{at}optusnet.com.au) August 2009. + Available under the MIT (http://keith-wood.name/licence.html) license. + Please attribute the author if you use it. */ + +(function($) { // Hide scope, no $ conflict + 'use strict'; + + var pluginName = 'calendarsPicker'; + + /** Create the calendars datepicker plugin. +

Sets an input field to popup a calendar for date entry, + or a div or span to show an inline calendar.

+

Expects HTML like:

+
<input type="text"> or <div></div>
+

Provide inline configuration like:

+
<input type="text" data-calendarsPicker="name: 'value'"/>
+ @class CalendarsPicker + @augments JQPlugin + @example $(selector).calendarsPicker() +$(selector).calendarsPicker({minDate: 0, maxDate: '+1m +1w'}) */ + $.JQPlugin.createPlugin({ + + /** The name of the plugin. + @memberof CalendarsPicker + @default 'calendarsPicker' */ + name: pluginName, + + /** Default template for generating a datepicker. + Insert anywhere: +
    +
  • '{l10n:name}' to insert localised value for name,
  • +
  • '{link:name}' to insert a link trigger for command name,
  • +
  • '{button:name}' to insert a button trigger for command name,
  • +
  • '{popup:start}...{popup:end}' to mark a section for inclusion in a popup datepicker only,
  • +
  • '{inline:start}...{inline:end}' to mark a section for inclusion in an inline datepicker only.
  • +
+ @memberof CalendarsPicker + @property {string} picker Overall structure: '{months}' to insert calendar months. + @property {string} monthRow One row of months: '{months}' to insert calendar months. + @property {string} month A single month: '{monthHeader:dateFormat}' to insert the month header - + dateFormat is optional and defaults to 'MM yyyy', + '{weekHeader}' to insert a week header, '{weeks}' to insert the month's weeks. + @property {string} weekHeader A week header: '{days}' to insert individual day names. + @property {string} dayHeader Individual day header: '{day}' to insert day name. + @property {string} week One week of the month: '{days}' to insert the week's days, + '{weekOfYear}' to insert week of year. + @property {string} day An individual day: '{day}' to insert day value. + @property {string} monthSelector jQuery selector, relative to picker, for a single month. + @property {string} daySelector jQuery selector, relative to picker, for individual days. + @property {string} rtlClass Class for right-to-left (RTL) languages. + @property {string} multiClass Class for multi-month datepickers. + @property {string} defaultClass Class for selectable dates. + @property {string} selectedClass Class for currently selected dates. + @property {string} highlightedClass Class for highlighted dates. + @property {string} todayClass Class for today. + @property {string} otherMonthClass Class for days from other months. + @property {string} weekendClass Class for days on weekends. + @property {string} commandClass Class prefix for commands. + @property {string} commandButtonClass Extra class(es) for commands that are buttons. + @property {string} commandLinkClass Extra class(es) for commands that are links. + @property {string} disabledClass Class for disabled commands. */ + defaultRenderer: { + picker: '
' + + '
{link:prev}{link:today}{link:next}
{months}' + + '{popup:start}
{link:clear}{link:close}
{popup:end}' + + '
', + monthRow: '
{months}
', + month: '
{monthHeader}
' + + '{weekHeader}{weeks}
', + weekHeader: '{days}', + dayHeader: '{day}', + week: '{days}', + day: '{day}', + monthSelector: '.calendars-month', + daySelector: 'td', + rtlClass: 'calendars-rtl', + multiClass: 'calendars-multi', + defaultClass: '', + selectedClass: 'calendars-selected', + highlightedClass: 'calendars-highlight', + todayClass: 'calendars-today', + otherMonthClass: 'calendars-other-month', + weekendClass: 'calendars-weekend', + commandClass: 'calendars-cmd', + commandButtonClass: '', + commandLinkClass: '', + disabledClass: 'calendars-disabled' + }, + + /** Command actions that may be added to a layout by name. +
    +
  • prev - Show the previous month (based on monthsToStep option) - PageUp
  • +
  • prevJump - Show the previous year (based on monthsToJump option) - Ctrl+PageUp
  • +
  • next - Show the next month (based on monthsToStep option) - PageDown
  • +
  • nextJump - Show the next year (based on monthsToJump option) - Ctrl+PageDown
  • +
  • current - Show the currently selected month or today's if none selected - Ctrl+Home
  • +
  • today - Show today's month - Ctrl+Home
  • +
  • clear - Erase the date and close the datepicker popup - Ctrl+End
  • +
  • close - Close the datepicker popup - Esc
  • +
  • prevWeek - Move the cursor to the previous week - Ctrl+Up
  • +
  • prevDay - Move the cursor to the previous day - Ctrl+Left
  • +
  • nextDay - Move the cursor to the next day - Ctrl+Right
  • +
  • nextWeek - Move the cursor to the next week - Ctrl+Down
  • +
+ The command name is the key name and is used to add the command to a layout + with '{button:name}' or '{link:name}'. Each has the following attributes. + @memberof CalendarsPicker + @property {string} text The field in the regional settings for the displayed text. + @property {string} status The field in the regional settings for the status text. + @property {object} keystroke The keystroke to trigger the action, with attributes: + @property {number} keystroke.keyCode the code for the keystroke, + @property {boolean} [keystroke.ctrlKey] true if Ctrl is required, + @property {boolean} [keystroke.altKey] true if Alt is required, + @property {boolean} [keystroke.shiftKey] true if Shift is required. + @property {CalendarsPickerCommandEnabled} enabled The function that indicates the command is enabled. + @property {CalendarsPickerCommandDate} date The function to get the date associated with this action. + @property {CalendarsPickerCommandAction} action The function that implements the action. */ + commands: { + prev: { + text: 'prevText', + status: 'prevStatus', // Previous month + keystroke: {keyCode: 33}, // Page up + enabled: function(inst) { + var minDate = inst.curMinDate(); + return (!minDate || inst.drawDate.newDate(). + add(1 - inst.options.monthsToStep - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay).add(-1, 'd').compareTo(minDate) !== -1); + }, + date: function(inst) { + return inst.drawDate.newDate(). + add(-inst.options.monthsToStep - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay); + }, + action: function(inst) { + plugin.changeMonth(this, -inst.options.monthsToStep); + } + }, + prevJump: { + text: 'prevJumpText', + status: 'prevJumpStatus', // Previous year + keystroke: {keyCode: 33, ctrlKey: true}, // Ctrl + Page up + enabled: function(inst) { + var minDate = inst.curMinDate(); + return (!minDate || inst.drawDate.newDate(). + add(1 - inst.options.monthsToJump - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay).add(-1, 'd').compareTo(minDate) !== -1); + }, + date: function(inst) { + return inst.drawDate.newDate(). + add(-inst.options.monthsToJump - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay); + }, + action: function(inst) { + plugin.changeMonth(this, -inst.options.monthsToJump); + } + }, + next: { + text: 'nextText', + status: 'nextStatus', // Next month + keystroke: {keyCode: 34}, // Page down + enabled: function(inst) { + var maxDate = inst.get('maxDate'); + return (!maxDate || inst.drawDate.newDate(). + add(inst.options.monthsToStep - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay).compareTo(maxDate) !== +1); + }, + date: function(inst) { + return inst.drawDate.newDate(). + add(inst.options.monthsToStep - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay); + }, + action: function(inst) { + plugin.changeMonth(this, inst.options.monthsToStep); + } + }, + nextJump: { + text: 'nextJumpText', + status: 'nextJumpStatus', // Next year + keystroke: {keyCode: 34, ctrlKey: true}, // Ctrl + Page down + enabled: function(inst) { + var maxDate = inst.get('maxDate'); + return (!maxDate || inst.drawDate.newDate(). + add(inst.options.monthsToJump - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay).compareTo(maxDate) !== +1); + }, + date: function(inst) { + return inst.drawDate.newDate(). + add(inst.options.monthsToJump - inst.options.monthsOffset, 'm'). + day(inst.options.calendar.minDay); + }, + action: function(inst) { + plugin.changeMonth(this, inst.options.monthsToJump); + } + }, + current: { + text: 'currentText', + status: 'currentStatus', // Current month + keystroke: {keyCode: 36, ctrlKey: true}, // Ctrl + Home + enabled: function(inst) { + var minDate = inst.curMinDate(); + var maxDate = inst.get('maxDate'); + var curDate = inst.selectedDates[0] || inst.options.calendar.today(); + return (!minDate || curDate.compareTo(minDate) !== -1) && + (!maxDate || curDate.compareTo(maxDate) !== +1); + }, + date: function(inst) { + return inst.selectedDates[0] || inst.options.calendar.today(); + }, + action: function(inst) { + var curDate = inst.selectedDates[0] || inst.options.calendar.today(); + plugin.showMonth(this, curDate.year(), curDate.month()); + } + }, + today: { + text: 'todayText', + status: 'todayStatus', // Today's month + keystroke: {keyCode: 36, ctrlKey: true}, // Ctrl + Home + enabled: function(inst) { + var minDate = inst.curMinDate(); + var maxDate = inst.get('maxDate'); + return (!minDate || inst.options.calendar.today().compareTo(minDate) !== -1) && + (!maxDate || inst.options.calendar.today().compareTo(maxDate) !== +1); + }, + date: function(inst) { + return inst.options.calendar.today(); + }, + action: function() { + plugin.showMonth(this); + } + }, + clear: { + text: 'clearText', + status: 'clearStatus', // Clear the datepicker + keystroke: {keyCode: 35, ctrlKey: true}, // Ctrl + End + enabled: function() { return true; }, + date: function() { return null; }, + action: function() { plugin.clear(this); } + }, + close: { + text: 'closeText', + status: 'closeStatus', // Close the datepicker + keystroke: {keyCode: 27}, // Escape + enabled: function() { return true; }, + date: function() { return null; }, + action: function() { plugin.hide(this); } + }, + prevWeek: { + text: 'prevWeekText', + status: 'prevWeekStatus', // Previous week + keystroke: {keyCode: 38, ctrlKey: true}, // Ctrl + Up + enabled: function(inst) { + var minDate = inst.curMinDate(); + return (!minDate || inst.drawDate.newDate(). + add(-inst.options.calendar.daysInWeek(), 'd').compareTo(minDate) !== -1); + }, + date: function(inst) { + return inst.drawDate.newDate().add(-inst.options.calendar.daysInWeek(), 'd'); + }, + action: function(inst) { + plugin.changeDay(this, -inst.options.calendar.daysInWeek()); + } + }, + prevDay: { + text: 'prevDayText', + status: 'prevDayStatus', // Previous day + keystroke: {keyCode: 37, ctrlKey: true}, // Ctrl + Left + enabled: function(inst) { + var minDate = inst.curMinDate(); + return (!minDate || inst.drawDate.newDate().add(-1, 'd').compareTo(minDate) !== -1); + }, + date: function(inst) { + return inst.drawDate.newDate().add(-1, 'd'); + }, + action: function() { + plugin.changeDay(this, -1); + } + }, + nextDay: { + text: 'nextDayText', + status: 'nextDayStatus', // Next day + keystroke: {keyCode: 39, ctrlKey: true}, // Ctrl + Right + enabled: function(inst) { + var maxDate = inst.get('maxDate'); + return (!maxDate || inst.drawDate.newDate().add(1, 'd').compareTo(maxDate) !== +1); + }, + date: function(inst) { + return inst.drawDate.newDate().add(1, 'd'); + }, + action: function() { + plugin.changeDay(this, 1); + } + }, + nextWeek: { + text: 'nextWeekText', + status: 'nextWeekStatus', // Next week + keystroke: {keyCode: 40, ctrlKey: true}, // Ctrl + Down + enabled: function(inst) { + var maxDate = inst.get('maxDate'); + return (!maxDate || inst.drawDate.newDate(). + add(inst.options.calendar.daysInWeek(), 'd').compareTo(maxDate) !== +1); + }, + date: function(inst) { + return inst.drawDate.newDate().add(inst.options.calendar.daysInWeek(), 'd'); + }, + action: function(inst) { + plugin.changeDay(this, inst.options.calendar.daysInWeek()); + } + } + }, + + /** Determine whether a command is enabled. + @callback CalendarsPickerCommandEnabled + @param {object} inst The current instance settings. + @return {boolean} true if this command is enabled, false if not. + @example enabled: function(inst) { + return !!inst.curMinDate(); +} */ + + /** Calculate the representative date for a command. + @callback CalendarsPickerCommandDate + @param {object} inst The current instance settings. + @return {CDate} A date appropriate for this command. + @example date: function(inst) { + return inst.curMinDate(); +} */ + + /** Perform the action for a command. + @callback CalendarsPickerCommandAction + @param {object} inst The current instance settings. + @example date: function(inst) { + $.datepick.setDate(inst.elem, inst.curMinDate()); +} */ + + /** Calculate the week of the year for a date. + @callback CalendarsPickerCalculateWeek + @param {CDate} date The date to evaluate. + @return {number} The week of the year. + @example calculateWeek: function(date) { + var startYear = date.newDate(date.year(), 1, 1); + return Math.floor((date.dayOfYear() - startYear.dayOfYear()) / 7) + 1; +} */ + + /** Provide information about an individual date shown in the calendar. + @callback CalendarsPickerOnDate + @param {CDate} date The date to evaluate. + @return {object} Information about that date, with the properties above. + @property {boolean} selectable true if this date can be selected. + @property {string} dateClass Class(es) to be applied to the date. + @property {string} content The date cell content. + @property {string} tooltip A popup tooltip for the date. + @example onDate: function(date) { + return {selectable: date.day() > 0 && date.day() < 5, + dateClass: date.day() === 4 ? 'last-day' : ''}; +} */ + + /** Update the datepicker display. + @callback CalendarsPickerOnShow + @param {jQuery} picker The datepicker div to be shown. + @param {object} inst The current instance settings. + @example onShow: function(picker, inst) { + picker.append(''). + find('button:last').click(function() { + alert('Hi!'); + }); +} */ + + /** React to navigating through the months/years. + @callback CalendarsPickerOnChangeMonthYear + @param {number} year The new year. + @param {number} month The new month (calendar minimum month to maximum month). + @example onChangeMonthYear: function(year, month) { + alert('Now in ' + month + '/' + year); +} */ + + /** Datepicker on select callback. + Triggered when a date is selected. + @callback CalendarsPickerOnSelect + @param {CDate[]} dates The selected date(s). + @example onSelect: function(dates) { + alert('Selected ' + dates); +} */ + + /** Datepicker on close callback. + Triggered when a popup calendar is closed. + @callback CalendarsPickerOnClose + @param {CDate[]} dates The selected date(s). + @example onClose: function(dates) { + alert('Selected ' + dates); +} */ + + /** Default settings for the plugin. + @memberof CalendarsPicker + @property {Calendar} [calendar=$.calendars.instance()] The calendar for this datepicker. + @property {string} [pickerClass=''] CSS class to add to this instance of the datepicker. + @property {boolean} [showOnFocus=true] true for popup on focus, false for not. + @property {string|Element|jQuery} [showTrigger=null] Element to be cloned for a trigger, + null for none. + @property {string} [showAnim='show'] Name of jQuery animation for popup, '' for no animation. + @property {object} [showOptions=null] Options for enhanced animations. + @property {string|number} [showSpeed='normal'] Duration of display/closure, named or in milliseconds. + @property {string|Element|jQuery} [popupContainer=null] The element to which a popup calendar is added, + null for body. + @property {string} [alignment='bottom'] Alignment of popup - with nominated corner of input: + 'top' or 'bottom' aligns depending on language direction, + 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'. + @property {boolean} [fixedWeeks=false] true to always show 6 weeks, + false to only show as many as are needed. + @property {number} [firstDay=null] First day of the week, 0 = Sunday, 1 = Monday, etc., + null for calendar default. + @property {CalendarsPickerCalculateWeek} [calculateWeek=null] Calculate week of the year from a date, + null for calendar default. + @property {boolean} [localNumbers=false] true to localise numbers (if available), + false to use normal Arabic numerals. + @property {number|number[]} [monthsToShow=1] How many months to show, cols or [rows, cols]. + @property {number} [monthsOffset=0] How many months to offset the primary month by; + may be a function that takes the date and returns the offset. + @property {number} [monthsToStep=1] How many months to move when prev/next clicked. + @property {number} [monthsToJump=12] How many months to move when large prev/next clicked. + @property {boolean} [useMouseWheel=true] true to use mousewheel if available, + false to never use it. + @property {boolean} [changeMonth=true] true to change month/year via drop-down, + false for navigation only. + @property {string} [yearRange='c-10:c+10'] Range of years to show in drop-down: 'any' for direct text entry + or 'start:end', where start/end are '+-nn' for relative to today + or 'c+-nn' for relative to the currently selected date + or 'nnnn' for an absolute year. + @property {boolean} [showOtherMonths=false] true to show dates from other months, + false to not show them. + @property {boolean} [selectOtherMonths=false] true to allow selection of dates + from other months too. + @property {string|number|CDate} [defaultDate=null] Date to show if no other selected. + @property {boolean} [selectDefaultDate=false] true to pre-select the default date + if no other is chosen. + @property {string|number|CDate} [minDate=null] The minimum selectable date. + @property {string|number|CDate} [maxDate=null] The maximum selectable date. + @property {string} [dateFormat='mm/dd/yyyy'] Format for dates. + @property {boolean} [autoSize=false] true to size the input field according to the date format. + @property {boolean} [rangeSelect=false] Allows for selecting a date range on one date picker. + @property {string} [rangeSeparator=' - '] Text between two dates in a range. + @property {number} [multiSelect=0] Maximum number of selectable dates, zero for single select. + @property {string} [multiSeparator=','] Text between multiple dates. + @property {CalendarsPickerOnDate} [onDate=null] Callback as a date is added to the datepicker. + @property {CalendarsPickerOnShow} [onShow=null] Callback just before a datepicker is shown. + @property {CalendarsPickerOnChangeMonthYear} [onChangeMonthYear=null] Callback when a new month/year + is selected. + @property {CalendarsPickerOnSelect} [onSelect=null] Callback when a date is selected. + @property {CalendarsPickerOnClose} [onClose=null] Callback when a datepicker is closed. + @property {string|Element|jQuery} [altField=null] Alternate field to update in synch with the datepicker. + @property {string} [altFormat=null] Date format for alternate field, defaults to dateFormat. + @property {boolean} [constrainInput=true] true to constrain typed input to + dateFormat allowed characters. + @property {boolean} [commandsAsDateFormat=false] true to apply + formatDate to the command texts. + @property {object} [commands=this.commands] Command actions that may be added to a layout by name. + @example $(selector).calendarsPicker({calendar: $.calendars.instance('persian')}) +$(selector).calendarsPicker({monthsToShow: [2, 3], monthsToStep: 6}) +$(selector).calendarsPicker({minDate: $.calendars.newDate(2001, 1, 1), + maxDate: $.calendars.newDate(2010, 12, 31)}) */ + defaultOptions: { + calendar: $.calendars.instance(), + pickerClass: '', + showOnFocus: true, + showTrigger: null, + showAnim: 'show', + showOptions: {}, + showSpeed: 'normal', + popupContainer: null, + alignment: 'bottom', + fixedWeeks: false, + firstDay: null, + calculateWeek: null, + localNumbers: false, + monthsToShow: 1, + monthsOffset: 0, + monthsToStep: 1, + monthsToJump: 12, + useMouseWheel: true, + changeMonth: true, + yearRange: 'c-10:c+10', + showOtherMonths: false, + selectOtherMonths: false, + defaultDate: null, + selectDefaultDate: false, + minDate: null, + maxDate: null, + dateFormat: null, + autoSize: false, + rangeSelect: false, + rangeSeparator: ' - ', + multiSelect: 0, + multiSeparator: ',', + onDate: null, + onShow: null, + onChangeMonthYear: null, + onSelect: null, + onClose: null, + altField: null, + altFormat: null, + constrainInput: true, + commandsAsDateFormat: false, + commands: {} // this.commands + }, + + /** Localisations for the plugin. + Entries are objects indexed by the language code ('' being the default US/English). + Each object has the following attributes. + @memberof CalendarsPicker + @property {string} [renderer=this.defaultRenderer] The rendering templates. + @property {string} [prevText='<Prev'] Text for the previous month command. + @property {string} [prevStatus='Show the previous month'] Status text for the + previous month command. + @property {string} [prevJumpText='<<'] Text for the previous year command. + @property {string} [prevJumpStatus='Show the previous year'] Status text for the + previous year command. + @property {string} [nextText='Next>'] Text for the next month command. + @property {string} [nextStatus='Show the next month'] Status text for the next month command. + @property {string} [nextJumpText='>>'] Text for the next year command. + @property {string} [nextJumpStatus='Show the next year'] Status text for the + next year command. + @property {string} [currentText='Current'] Text for the current month command. + @property {string} [currentStatus='Show the current month'] Status text for the + current month command. + @property {string} [todayText='Today'] Text for the today's month command. + @property {string} [todayStatus='Show today\'s month'] Status text for the today's month command. + @property {string} [clearText='Clear'] Text for the clear command. + @property {string} [clearStatus='Clear all the dates'] Status text for the clear command. + @property {string} [closeText='Close'] Text for the close command. + @property {string} [closeStatus='Close the datepicker'] Status text for the close command. + @property {string} [yearStatus='Change the year'] Status text for year selection. + @property {string} [earlierText='  ▲'] Text for earlier years. + @property {string} [laterText='  ▼'] Text for later years. + @property {string} [monthStatus='Change the month'] Status text for month selection. + @property {string} [weekText='Wk'] Text for week of the year column header. + @property {string} [weekStatus='Week of the year'] Status text for week of the year + column header. + @property {string} [dayStatus='Select DD, M d, yyyy'] Status text for selectable days. + @property {string} [defaultStatus='Select a date'] Status text shown by default. + @property {boolean} [isRTL=false] true if language is right-to-left. */ + regionalOptions: { // Available regional settings, indexed by language/country code + '': { // Default regional settings - English/US + renderer: {}, // this.defaultRenderer + prevText: '<Prev', + prevStatus: 'Show the previous month', + prevJumpText: '<<', + prevJumpStatus: 'Show the previous year', + nextText: 'Next>', + nextStatus: 'Show the next month', + nextJumpText: '>>', + nextJumpStatus: 'Show the next year', + currentText: 'Current', + currentStatus: 'Show the current month', + todayText: 'Today', + todayStatus: 'Show today\'s month', + clearText: 'Clear', + clearStatus: 'Clear all the dates', + closeText: 'Close', + closeStatus: 'Close the datepicker', + yearStatus: 'Change the year', + earlierText: '  ▲', + laterText: '  ▼', + monthStatus: 'Change the month', + weekText: 'Wk', + weekStatus: 'Week of the year', + dayStatus: 'Select DD, M d, yyyy', + defaultStatus: 'Select a date', + isRTL: false + } + }, + + _disabled: [], + + _popupClass: 'calendars-popup', // Marker for popup division + _triggerClass: 'calendars-trigger', // Marker for trigger element + _disableClass: 'calendars-disable', // Marker for disabled element + _monthYearClass: 'calendars-month-year', // Marker for month/year inputs + _curMonthClass: 'calendars-month-', // Marker for current month/year + _anyYearClass: 'calendars-any-year', // Marker for year direct input + _curDoWClass: 'calendars-dow-', // Marker for day of week + + _init: function() { + this.defaultOptions.commands = this.commands; + this.regionalOptions[''].renderer = this.defaultRenderer; + this._super(); + }, + + _instSettings: function(elem, options) { // jshint unused:false + return {selectedDates: [], drawDate: null, pickingRange: false, + inline: ($.inArray(elem[0].nodeName.toLowerCase(), ['div', 'span']) > -1), + get: function(name) { // Get a setting value, computing if necessary + if ($.inArray(name, ['defaultDate', 'minDate', 'maxDate']) > -1) { // Decode date settings + return this.options.calendar.determineDate(this.options[name], null, + this.selectedDates[0], this.get('dateFormat'), this.getConfig()); + } + if (name === 'dateFormat') { + return this.options.dateFormat || this.options.calendar.local.dateFormat; + } + return this.options[name]; + }, + curMinDate: function() { + return (this.pickingRange ? this.selectedDates[0] : this.get('minDate')); + }, + getConfig: function() { + return {dayNamesShort: this.options.dayNamesShort, dayNames: this.options.dayNames, + monthNamesShort: this.options.monthNamesShort, monthNames: this.options.monthNames, + calculateWeek: this.options.calculateWeek, shortYearCutoff: this.options.shortYearCutoff}; + } + }; + }, + + _postAttach: function(elem, inst) { + if (inst.inline) { + inst.drawDate = plugin._checkMinMax((inst.selectedDates[0] || + inst.get('defaultDate') || inst.options.calendar.today()).newDate(), inst); + inst.prevDate = inst.drawDate.newDate(); + this._update(elem[0]); + if ($.fn.mousewheel) { + elem.mousewheel(this._doMouseWheel); + } + } + else { + this._attachments(elem, inst); + elem.on('keydown.' + inst.name, this._keyDown).on('keypress.' + inst.name, this._keyPress). + on('keyup.' + inst.name, this._keyUp); + if (elem.attr('disabled')) { + this.disable(elem[0]); + } + } + }, + + _optionsChanged: function(elem, inst, options) { + if (options.calendar && options.calendar !== inst.options.calendar) { + var discardDate = function(name) { + return (typeof inst.options[name] === 'object' ? null : inst.options[name]); + }; + options = $.extend({defaultDate: discardDate('defaultDate'), + minDate: discardDate('minDate'), maxDate: discardDate('maxDate')}, options); + inst.selectedDates = []; + inst.drawDate = null; + } + var dates = inst.selectedDates; + $.extend(inst.options, options); + this.setDate(elem[0], dates, null, false, true); + inst.pickingRange = false; + var calendar = inst.options.calendar; + var defaultDate = inst.get('defaultDate'); + inst.drawDate = this._checkMinMax((defaultDate ? defaultDate : inst.drawDate) || + defaultDate || calendar.today(), inst).newDate(); + if (!inst.inline) { + this._attachments(elem, inst); + } + if (inst.inline || inst.div) { + this._update(elem[0]); + } + }, + + /** Attach events and trigger, if necessary. + @memberof CalendarsPicker + @private + @param {jQuery} elem The control to affect. + @param {object} inst The current instance settings. */ + _attachments: function(elem, inst) { + elem.off('focus.' + inst.name); + if (inst.options.showOnFocus) { + elem.on('focus.' + inst.name, this.show); + } + if (inst.trigger) { + inst.trigger.remove(); + } + var trigger = inst.options.showTrigger; + inst.trigger = (!trigger ? $([]) : + $(trigger).clone().removeAttr('id').addClass(this._triggerClass) + [inst.options.isRTL ? 'insertBefore' : 'insertAfter'](elem). + click(function() { + if (!plugin.isDisabled(elem[0])) { + plugin[plugin.curInst === inst ? 'hide' : 'show'](elem[0]); + } + })); + this._autoSize(elem, inst); + var dates = this._extractDates(inst, elem.val()); + if (dates) { + this.setDate(elem[0], dates, null, true); + } + var defaultDate = inst.get('defaultDate'); + if (inst.options.selectDefaultDate && defaultDate && inst.selectedDates.length === 0) { + this.setDate(elem[0], (defaultDate || inst.options.calendar.today()).newDate()); + } + }, + + /** Apply the maximum length for the date format. + @memberof CalendarsPicker + @private + @param {jQuery} elem The control to affect. + @param {object} inst The current instance settings. */ + _autoSize: function(elem, inst) { + if (inst.options.autoSize && !inst.inline) { + var calendar = inst.options.calendar; + var date = calendar.newDate(2009, 10, 20); // Ensure double digits + var dateFormat = inst.get('dateFormat'); + if (dateFormat.match(/[DM]/)) { + var findMax = function(names) { + var max = 0; + var maxI = 0; + for (var i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.month(findMax(calendar.local[dateFormat.match(/MM/) ? // Longest month + 'monthNames' : 'monthNamesShort']) + 1); + date.day(findMax(calendar.local[dateFormat.match(/DD/) ? // Longest day + 'dayNames' : 'dayNamesShort']) + 20 - date.dayOfWeek()); + } + inst.elem.attr('size', date.formatDate(dateFormat, + {localNumbers: inst.options.localnumbers}).length); + } + }, + + _preDestroy: function(elem, inst) { + if (inst.trigger) { + inst.trigger.remove(); + } + elem.empty().off('.' + inst.name); + if (inst.inline && $.fn.mousewheel) { + elem.unmousewheel(); + } + if (!inst.inline && inst.options.autoSize) { + elem.removeAttr('size'); + } + }, + + /** Apply multiple event functions. + @memberof CalendarsPicker + @param {function} fns The functions to apply. + @example onShow: multipleEvents(fn1, fn2, ...) */ + multipleEvents: function(fns) { // jshint unused:false + var funcs = arguments; + return function() { + for (var i = 0; i < funcs.length; i++) { + funcs[i].apply(this, arguments); + } + }; + }, + + /** Enable the control. + @memberof CalendarsPicker + @param {Element} elem The control to affect. + @example $(selector).datepick('enable') */ + enable: function(elem) { + elem = $(elem); + if (!elem.hasClass(this._getMarker())) { + return; + } + var inst = this._getInst(elem); + if (inst.inline) { + elem.children('.' + this._disableClass).remove().end(). + find('button,select').prop('disabled', false).end(). + find('a').attr('href', '#'); + } + else { + elem.prop('disabled', false); + inst.trigger.filter('button.' + this._triggerClass).prop('disabled', false).end(). + filter('img.' + this._triggerClass).css({opacity: '1.0', cursor: ''}); + } + this._disabled = $.map(this._disabled, + function(value) { return (value === elem[0] ? null : value); }); // Delete entry + }, + + /** Disable the control. + @memberof CalendarsPicker + @param {Element} elem The control to affect. + @example $(selector).datepick('disable') */ + disable: function(elem) { + elem = $(elem); + if (!elem.hasClass(this._getMarker())) { + return; + } + var inst = this._getInst(elem); + if (inst.inline) { + var inline = elem.children(':last'); + var offset = inline.offset(); + var relOffset = {left: 0, top: 0}; + inline.parents().each(function() { + if ($(this).css('position') === 'relative') { + relOffset = $(this).offset(); + return false; + } + }); + var zIndex = elem.css('zIndex'); + zIndex = (zIndex === 'auto' ? 0 : parseInt(zIndex, 10)) + 1; + elem.prepend('
'). + find('button,select').prop('disabled', true).end(). + find('a').removeAttr('href'); + } + else { + elem.prop('disabled', true); + inst.trigger.filter('button.' + this._triggerClass).prop('disabled', true).end(). + filter('img.' + this._triggerClass).css({opacity: '0.5', cursor: 'default'}); + } + this._disabled = $.map(this._disabled, + function(value) { return (value === elem[0] ? null : value); }); // Delete entry + this._disabled.push(elem[0]); + }, + + /** Is the first field in a jQuery collection disabled as a datepicker? + @memberof CalendarsPicker + @param {Element} elem The control to examine. + @return {boolean} true if disabled, false if enabled. + @example if ($(selector).datepick('isDisabled')) {...} */ + isDisabled: function(elem) { + return (elem && $.inArray(elem, this._disabled) > -1); + }, + + /** Show a popup datepicker. + @memberof CalendarsPicker + @param {Event|Element} elem a focus event or the control to use. + @example $(selector).datepick('show') */ + show: function(elem) { + elem = $(elem.target || elem); + var inst = plugin._getInst(elem); + if (plugin.curInst === inst) { + return; + } + if (plugin.curInst) { + plugin.hide(plugin.curInst, true); + } + if (!$.isEmptyObject(inst)) { + // Retrieve existing date(s) + inst.lastVal = null; + inst.selectedDates = plugin._extractDates(inst, elem.val()); + inst.pickingRange = false; + inst.drawDate = plugin._checkMinMax((inst.selectedDates[0] || + inst.get('defaultDate') || inst.options.calendar.today()).newDate(), inst); + inst.prevDate = inst.drawDate.newDate(); + plugin.curInst = inst; + // Generate content + plugin._update(elem[0], true); + // Adjust position before showing + var offset = plugin._checkOffset(inst); + inst.div.css({left: offset.left, top: offset.top}); + // And display + var showAnim = inst.options.showAnim; + var showSpeed = inst.options.showSpeed; + showSpeed = (showSpeed === 'normal' && $.ui && + parseInt($.ui.version.substring(2)) >= 8 ? '_default' : showSpeed); + if ($.effects && ($.effects[showAnim] || ($.effects.effect && $.effects.effect[showAnim]))) { + var data = inst.div.data(); // Update old effects data + for (var key in data) { + if (key.match(/^ec\.storage\./)) { + data[key] = inst._mainDiv.css(key.replace(/ec\.storage\./, '')); + } + } + inst.div.data(data).show(showAnim, inst.options.showOptions, showSpeed); + } + else { + inst.div[showAnim || 'show'](showAnim ? showSpeed : 0); + } + } + }, + + /** Extract possible dates from a string. + @memberof CalendarsPicker + @private + @param {object} inst The current instance settings. + @param {string} text The text to extract from. + @return {CDate[]} The extracted dates. */ + _extractDates: function(inst, datesText) { + if (datesText === inst.lastVal) { + return; + } + inst.lastVal = datesText; + datesText = datesText.split(inst.options.multiSelect ? inst.options.multiSeparator : + (inst.options.rangeSelect ? inst.options.rangeSeparator : '\x00')); + var dates = []; + for (var i = 0; i < datesText.length; i++) { + try { + var date = inst.options.calendar.parseDate(inst.get('dateFormat'), datesText[i]); + if (date) { + var found = false; + for (var j = 0; j < dates.length; j++) { + if (dates[j].compareTo(date) === 0) { + found = true; + break; + } + } + if (!found) { + dates.push(date); + } + } + } + catch (e) { + // Ignore + } + } + dates.splice(inst.options.multiSelect || (inst.options.rangeSelect ? 2 : 1), dates.length); + if (inst.options.rangeSelect && dates.length === 1) { + dates[1] = dates[0]; + } + return dates; + }, + + /** Update the datepicker display. + @memberof CalendarsPicker + @private + @param {Event|Element} elem A focus event or the control to use. + @param {boolean} hidden true to initially hide the datepicker. */ + _update: function(elem, hidden) { + elem = $(elem.target || elem); + var inst = plugin._getInst(elem); + if (!$.isEmptyObject(inst)) { + if (inst.inline || plugin.curInst === inst) { + if ($.isFunction(inst.options.onChangeMonthYear) && (!inst.prevDate || + inst.prevDate.year() !== inst.drawDate.year() || + inst.prevDate.month() !== inst.drawDate.month())) { + inst.options.onChangeMonthYear.apply(elem[0], + [inst.drawDate.year(), inst.drawDate.month()]); + } + } + if (inst.inline) { + var index = $('a, :input', elem).index($(':focus', elem)); + elem.html(this._generateContent(elem[0], inst)); + var focus = elem.find('a, :input'); + focus.eq(Math.max(Math.min(index, focus.length - 1), 0)).focus(); + } + else if (plugin.curInst === inst) { + if (!inst.div) { + inst.div = $('
').addClass(this._popupClass). + css({display: (hidden ? 'none' : 'static'), position: 'absolute', + left: elem.offset().left, top: elem.offset().top + elem.outerHeight()}). + appendTo($(inst.options.popupContainer || 'body')); + if ($.fn.mousewheel) { + inst.div.mousewheel(this._doMouseWheel); + } + } + inst.div.html(this._generateContent(elem[0], inst)); + elem.focus(); + } + } + }, + + /** Update the input field and any alternate field with the current dates. + @memberof CalendarsPicker + @private + @param {Element} elem The control to use. + @param {boolean} keyUp true if coming from keyUp processing (internal). */ + _updateInput: function(elem, keyUp) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst)) { + var value = ''; + var altValue = ''; + var sep = (inst.options.multiSelect ? inst.options.multiSeparator : + inst.options.rangeSeparator); + var calendar = inst.options.calendar; + var dateFormat = inst.get('dateFormat'); + var altFormat = inst.options.altFormat || dateFormat; + var settings = {localNumbers: inst.options.localNumbers}; + for (var i = 0; i < inst.selectedDates.length; i++) { + value += (keyUp ? '' : (i > 0 ? sep : '') + + calendar.formatDate(dateFormat, inst.selectedDates[i], settings)); + altValue += (i > 0 ? sep : '') + + calendar.formatDate(altFormat, inst.selectedDates[i], settings); + } + if (!inst.inline && !keyUp) { + $(elem).val(value); + } + $(inst.options.altField).val(altValue); + if ($.isFunction(inst.options.onSelect) && !keyUp && !inst.inSelect) { + inst.inSelect = true; // Prevent endless loops + inst.options.onSelect.apply(elem, [inst.selectedDates]); + inst.inSelect = false; + } + $(elem).change(); + } + }, + + /** Retrieve the size of left and top borders for an element. + @memberof CalendarsPicker + @private + @param {jQuery} elem The element of interest. + @return {number[]} The left and top borders. */ + _getBorders: function(elem) { + var convert = function(value) { + return {thin: 1, medium: 3, thick: 5}[value] || value; + }; + return [parseFloat(convert(elem.css('border-left-width'))), + parseFloat(convert(elem.css('border-top-width')))]; + }, + + /** Check positioning to remain on the screen. + @memberof CalendarsPicker + @private + @param {object} inst The current instance settings. + @return {object} The updated offset for the datepicker. */ + _checkOffset: function(inst) { + var base = (inst.elem.is(':hidden') && inst.trigger ? inst.trigger : inst.elem); + var offset = base.offset(); + var browserWidth = $(window).width(); + var browserHeight = $(window).height(); + if (browserWidth === 0) { + return offset; + } + var isFixed = false; + $(inst.elem).parents().each(function() { + isFixed = isFixed || $(this).css('position') === 'fixed'; + return !isFixed; + }); + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + var above = offset.top - (isFixed ? scrollY : 0) - inst.div.outerHeight(); + var below = offset.top - (isFixed ? scrollY : 0) + base.outerHeight(); + var alignL = offset.left - (isFixed ? scrollX : 0); + var alignR = offset.left - (isFixed ? scrollX : 0) + base.outerWidth() - inst.div.outerWidth(); + var tooWide = (offset.left - scrollX + inst.div.outerWidth()) > browserWidth; + var tooHigh = (offset.top - scrollY + inst.elem.outerHeight() + + inst.div.outerHeight()) > browserHeight; + inst.div.css('position', isFixed ? 'fixed' : 'absolute'); + var alignment = inst.options.alignment; + if (alignment === 'topLeft') { + offset = {left: alignL, top: above}; + } + else if (alignment === 'topRight') { + offset = {left: alignR, top: above}; + } + else if (alignment === 'bottomLeft') { + offset = {left: alignL, top: below}; + } + else if (alignment === 'bottomRight') { + offset = {left: alignR, top: below}; + } + else if (alignment === 'top') { + offset = {left: (inst.options.isRTL || tooWide ? alignR : alignL), top: above}; + } + else { // bottom + offset = {left: (inst.options.isRTL || tooWide ? alignR : alignL), + top: (tooHigh ? above : below)}; + } + offset.left = Math.max((isFixed ? 0 : scrollX), offset.left); + offset.top = Math.max((isFixed ? 0 : scrollY), offset.top); + return offset; + }, + + /** Close date picker if clicked elsewhere. + @memberof CalendarsPicker + @private + @param {MouseEvent} event The mouse click to check. */ + _checkExternalClick: function(event) { + if (!plugin.curInst) { + return; + } + var elem = $(event.target); + if (elem.closest('.' + plugin._popupClass + ',.' + plugin._triggerClass).length === 0 && + !elem.hasClass(plugin._getMarker())) { + plugin.hide(plugin.curInst); + } + }, + + /** Hide a popup datepicker. + @memberof CalendarsPicker + @param {Element|object} elem The control to use or the current instance settings. + @param {boolean} immediate true to close immediately without animation (internal). + @example $(selector).datepick('hide') */ + hide: function(elem, immediate) { + if (!elem) { + return; + } + var inst = this._getInst(elem); + if ($.isEmptyObject(inst)) { + inst = elem; + } + if (inst && inst === plugin.curInst) { + var showAnim = (immediate ? '' : inst.options.showAnim); + var showSpeed = inst.options.showSpeed; + showSpeed = (showSpeed === 'normal' && $.ui && + parseInt($.ui.version.substring(2)) >= 8 ? '_default' : showSpeed); + var postProcess = function() { + if (!inst.div) { + return; + } + inst.div.remove(); + inst.div = null; + plugin.curInst = null; + if ($.isFunction(inst.options.onClose)) { + inst.options.onClose.apply(elem, [inst.selectedDates]); + } + }; + inst.div.stop(); + if ($.effects && ($.effects[showAnim] || ($.effects.effect && $.effects.effect[showAnim]))) { + inst.div.hide(showAnim, inst.options.showOptions, showSpeed, postProcess); + } + else { + var hideAnim = (showAnim === 'slideDown' ? 'slideUp' : + (showAnim === 'fadeIn' ? 'fadeOut' : 'hide')); + inst.div[hideAnim]((showAnim ? showSpeed : ''), postProcess); + } + if (!showAnim) { + postProcess(); + } + } + }, + + /** Handle keystrokes in the datepicker. + @memberof CalendarsPicker + @private + @param {KeyEvent} event The keystroke. + @return {boolean} true if not handled, false if handled. */ + _keyDown: function(event) { + var elem = (event.data && event.data.elem) || event.target; + var inst = plugin._getInst(elem); + var handled = false; + var command; + if (inst.inline || inst.div) { + if (event.keyCode === 9) { // Tab - close + plugin.hide(elem); + } + else if (event.keyCode === 13) { // Enter - select + plugin.selectDate(elem, + $('a.' + inst.options.renderer.highlightedClass, inst.div)[0]); + handled = true; + } + else { // Command keystrokes + var commands = inst.options.commands; + for (var name in commands) { + if (inst.options.commands.hasOwnProperty(name)) { + command = commands[name]; + /* jshint -W018 */ // Dislikes !! + if (command.keystroke.keyCode === event.keyCode && + !!command.keystroke.ctrlKey === !!(event.ctrlKey || event.metaKey) && + !!command.keystroke.altKey === event.altKey && + !!command.keystroke.shiftKey === event.shiftKey) { + /* jshint +W018 */ + plugin.performAction(elem, name); + handled = true; + break; + } + } + } + } + } + else { // Show on 'current' keystroke + command = inst.options.commands.current; + /* jshint -W018 */ // Dislikes !! + if (command.keystroke.keyCode === event.keyCode && + !!command.keystroke.ctrlKey === !!(event.ctrlKey || event.metaKey) && + !!command.keystroke.altKey === event.altKey && + !!command.keystroke.shiftKey === event.shiftKey) { + /* jshint +W018 */ + plugin.show(elem); + handled = true; + } + } + inst.ctrlKey = ((event.keyCode < 48 && event.keyCode !== 32) || event.ctrlKey || event.metaKey); + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + return !handled; + }, + + /** Filter keystrokes in the datepicker. + @memberof CalendarsPicker + @private + @param {KeyEvent} event The keystroke. + @return {boolean} true if allowed, false if not allowed. */ + _keyPress: function(event) { + var inst = plugin._getInst((event.data && event.data.elem) || event.target); + if (!$.isEmptyObject(inst) && inst.options.constrainInput) { + var ch = String.fromCharCode(event.keyCode || event.charCode); + var allowedChars = plugin._allowedChars(inst); + return (event.metaKey || inst.ctrlKey || ch < ' ' || + !allowedChars || allowedChars.indexOf(ch) > -1); + } + return true; + }, + + /** Determine the set of characters allowed by the date format. + @memberof CalendarsPicker + @private + @param {object} inst The current instance settings. + @return {string} The set of allowed characters, or null if anything allowed. */ + _allowedChars: function(inst) { + var allowedChars = (inst.options.multiSelect ? inst.options.multiSeparator : + (inst.options.rangeSelect ? inst.options.rangeSeparator : '')); + var literal = false; + var hasNum = false; + var dateFormat = inst.get('dateFormat'); + for (var i = 0; i < dateFormat.length; i++) { + var ch = dateFormat.charAt(i); + if (literal) { + if (ch === '\'' && dateFormat.charAt(i + 1) !== '\'') { + literal = false; + } + else { + allowedChars += ch; + } + } + else { + switch (ch) { + case 'd': + case 'm': + case 'o': + case 'w': + allowedChars += (hasNum ? '' : '0123456789'); + hasNum = true; + break; + case 'y': + case '@': + case '!': + allowedChars += (hasNum ? '' : '0123456789') + '-'; + hasNum = true; + break; + case 'J': + allowedChars += (hasNum ? '' : '0123456789') + '-.'; + hasNum = true; + break; + case 'D': + case 'M': + case 'Y': + return null; // Accept anything + case '\'': + if (dateFormat.charAt(i + 1) === '\'') { + allowedChars += '\''; + } + else { + literal = true; + } + break; + default: + allowedChars += ch; + } + } + } + return allowedChars; + }, + + /** Synchronise datepicker with the field. + @memberof CalendarsPicker + @private + @param {KeyEvent} event The keystroke. + @return {boolean} true if allowed, false if not allowed. */ + _keyUp: function(event) { + var elem = (event.data && event.data.elem) || event.target; + var inst = plugin._getInst(elem); + if (!$.isEmptyObject(inst) && !inst.ctrlKey && inst.lastVal !== inst.elem.val()) { + try { + var dates = plugin._extractDates(inst, inst.elem.val()); + if (dates.length > 0) { + plugin.setDate(elem, dates, null, true); + } + } + catch (e) { + // Ignore + } + } + return true; + }, + + /** Increment/decrement month/year on mouse wheel activity. + @memberof CalendarsPicker + @private + @param {event} event The mouse wheel event. + @param {number} delta The amount of change. */ + _doMouseWheel: function(event, delta) { + var elem = (plugin.curInst && plugin.curInst.elem[0]) || + $(event.target).closest('.' + plugin._getMarker())[0]; + if (plugin.isDisabled(elem)) { + return; + } + var inst = plugin._getInst(elem); + if (inst.options.useMouseWheel) { + delta = (delta < 0 ? -1 : +1); + plugin.changeMonth(elem, -inst.options[event.ctrlKey ? 'monthsToJump' : 'monthsToStep'] * delta); + } + event.preventDefault(); + }, + + /** Clear an input and close a popup datepicker. + @memberof CalendarsPicker + @param {Element} elem The control to use. + @example $(selector).datepick('clear') */ + clear: function(elem) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst)) { + inst.selectedDates = []; + this.hide(elem); + var defaultDate = inst.get('defaultDate'); + if (inst.options.selectDefaultDate && defaultDate) { + this.setDate(elem, (defaultDate || inst.options.calendar.today()).newDate()); + } + else { + this._updateInput(elem); + } + } + }, + + /** Retrieve the selected date(s) for a datepicker. + @memberof CalendarsPicker + @param {Element} elem The control to examine. + @return {CDate[]} The selected date(s). + @example var dates = $(selector).datepick('getDate') */ + getDate: function(elem) { + var inst = this._getInst(elem); + return (!$.isEmptyObject(inst) ? inst.selectedDates : []); + }, + + /** Set the selected date(s) for a datepicker. + @memberof CalendarsPicker + @param {Element} elem The control to examine. + @param {CDate|number|string|array} dates The selected date(s). + @param {CDate|number|string} [endDate] The ending date for a range. + @param {boolean} [keyUp] true if coming from keyUp processing (internal). + @param {boolean} [setOpt] true if coming from option processing (internal). + @example $(selector).datepick('setDate', new Date(2014, 12-1, 25)) +$(selector).datepick('setDate', '12/25/2014', '01/01/2015') +$(selector).datepick('setDate', [date1, date2, date3]) */ + setDate: function(elem, dates, endDate, keyUp, setOpt) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst)) { + if (!$.isArray(dates)) { + dates = [dates]; + if (endDate) { + dates.push(endDate); + } + } + var minDate = inst.get('minDate'); + var maxDate = inst.get('maxDate'); + var curDate = inst.selectedDates[0]; + inst.selectedDates = []; + for (var i = 0; i < dates.length; i++) { + var date = inst.options.calendar.determineDate( + dates[i], null, curDate, inst.get('dateFormat'), inst.getConfig()); + if (date) { + if ((!minDate || date.compareTo(minDate) !== -1) && + (!maxDate || date.compareTo(maxDate) !== +1)) { + var found = false; + for (var j = 0; j < inst.selectedDates.length; j++) { + if (inst.selectedDates[j].compareTo(date) === 0) { + found = true; + break; + } + } + if (!found) { + inst.selectedDates.push(date); + } + } + } + } + inst.selectedDates.splice(inst.options.multiSelect || + (inst.options.rangeSelect ? 2 : 1), inst.selectedDates.length); + if (inst.options.rangeSelect) { + switch (inst.selectedDates.length) { + case 1: + inst.selectedDates[1] = inst.selectedDates[0]; + break; + case 2: + inst.selectedDates[1] = (inst.selectedDates[0].compareTo(inst.selectedDates[1]) === +1 ? + inst.selectedDates[0] : inst.selectedDates[1]); + break; + } + inst.pickingRange = false; + } + inst.prevDate = (inst.drawDate ? inst.drawDate.newDate() : null); + inst.drawDate = this._checkMinMax((inst.selectedDates[0] || + inst.get('defaultDate') || inst.options.calendar.today()).newDate(), inst); + if (!setOpt) { + this._update(elem); + this._updateInput(elem, keyUp); + } + } + }, + + /** Determine whether a date is selectable for this datepicker. + @memberof CalendarsPicker + @private + @param {Element} elem The control to check. + @param {CDate|string|number} date The date to check. + @return {boolean} true if selectable, false if not. + @example var selectable = $(selector).datepick('isSelectable', date) */ + isSelectable: function(elem, date) { + var inst = this._getInst(elem); + if ($.isEmptyObject(inst)) { + return false; + } + date = inst.options.calendar.determineDate(date, + inst.selectedDates[0] || inst.options.calendar.today(), null, + inst.options.dateFormat, inst.getConfig()); + return this._isSelectable(elem, date, inst.options.onDate, + inst.get('minDate'), inst.get('maxDate')); + }, + + /** Internally determine whether a date is selectable for this datepicker. + @memberof CalendarsPicker + @private + @param {Element} elem The control to check. + @param {CDate} date The date to check. + @param {function|boolean} onDate Any onDate callback or callback.selectable. + @param {CDate} minDate The minimum allowed date. + @param {CDate} maxDate The maximum allowed date. + @return {boolean} true if selectable, false if not. */ + _isSelectable: function(elem, date, onDate, minDate, maxDate) { + var dateInfo = (typeof onDate === 'boolean' ? {selectable: onDate} : + (!$.isFunction(onDate) ? {} : onDate.apply(elem, [date, true]))); + return (dateInfo.selectable !== false) && + (!minDate || date.toJD() >= minDate.toJD()) && (!maxDate || date.toJD() <= maxDate.toJD()); + }, + + /** Perform a named action for a datepicker. + @memberof CalendarsPicker + @param {element} elem The control to affect. + @param {string} action The name of the {@link CalendarsPicker.commands|action}. + @example $(selector).calendarsPicker('performAction', 'next') */ + performAction: function(elem, action) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst) && !this.isDisabled(elem)) { + var commands = inst.options.commands; + if (commands[action] && commands[action].enabled.apply(elem, [inst])) { + commands[action].action.apply(elem, [inst]); + } + } + }, + + /** Set the currently shown month, defaulting to today's. + @memberof CalendarsPicker + @param {Element} elem The control to affect. + @param {number} [year] The year to show. + @param {number} [month] The month to show (calendar minimum month to maximum month). + @param {number} [day] The day to show. + @example $(selector).datepick('showMonth', 2014, 12, 25) */ + showMonth: function(elem, year, month, day) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst) && ((typeof day !== 'undefined' && day !== null) || + inst.drawDate.year() !== year || inst.drawDate.month() !== month)) { + inst.prevDate = inst.drawDate.newDate(); + var calendar = inst.options.calendar; + var show = this._checkMinMax(typeof year !== 'undefined' && year !== null ? + calendar.newDate(year, month, 1) : calendar.today(), inst); + inst.drawDate.date(show.year(), show.month(), + typeof day !== 'undefined' && day !== null ? day : Math.min(inst.drawDate.day(), + calendar.daysInMonth(show.year(), show.month()))); + this._update(elem); + } + }, + + /** Adjust the currently shown month. + @memberof CalendarsPicker + @param {Element} elem The control to affect. + @param {number} offset The number of months to change by. + @example $(selector).datepick('changeMonth', 2)*/ + changeMonth: function(elem, offset) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst)) { + var date = inst.drawDate.newDate().add(offset, 'm'); + this.showMonth(elem, date.year(), date.month()); + } + }, + + /** Adjust the currently shown day. + @memberof CalendarsPicker + @param {Element} elem The control to affect. + @param {number} offset The number of days to change by. + @example $(selector).datepick('changeDay', 7)*/ + changeDay: function(elem, offset) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst)) { + var date = inst.drawDate.newDate().add(offset, 'd'); + this.showMonth(elem, date.year(), date.month(), date.day()); + } + }, + + /** Restrict a date to the minimum/maximum specified. + @memberof CalendarsPicker + @private + @param {CDate} date The date to check. + @param {object} inst The current instance settings. */ + _checkMinMax: function(date, inst) { + var minDate = inst.get('minDate'); + var maxDate = inst.get('maxDate'); + date = (minDate && date.compareTo(minDate) === -1 ? minDate.newDate() : date); + date = (maxDate && date.compareTo(maxDate) === +1 ? maxDate.newDate() : date); + return date; + }, + + /** Retrieve the date associated with an entry in the datepicker. + @memberof CalendarsPicker + @param {Element} elem The control to examine. + @param {Element} target The selected datepicker element. + @return {CDate} The corresponding date, or null. + @example var date = $(selector).datepick('retrieveDate', + $('div.datepick-popup a:contains(10)')[0]) */ + retrieveDate: function(elem, target) { + var inst = this._getInst(elem); + return ($.isEmptyObject(inst) ? null : inst.options.calendar.fromJD( + parseFloat(target.className.replace(/^.*jd(\d+\.5).*$/, '$1')))); + }, + + /** Select a date for this datepicker. + @memberof CalendarsPicker + @param {Element} elem The control to examine. + @param {Element} target The selected datepicker element. + @example $(selector).datepick('selectDate', $('div.datepick-popup a:contains(10)')[0]) */ + selectDate: function(elem, target) { + var inst = this._getInst(elem); + if (!$.isEmptyObject(inst) && !this.isDisabled(elem)) { + var date = this.retrieveDate(elem, target); + if (inst.options.multiSelect) { + var found = false; + for (var i = 0; i < inst.selectedDates.length; i++) { + if (date.compareTo(inst.selectedDates[i]) === 0) { + inst.selectedDates.splice(i, 1); + found = true; + break; + } + } + if (!found && inst.selectedDates.length < inst.options.multiSelect) { + inst.selectedDates.push(date); + } + } + else if (inst.options.rangeSelect) { + if (inst.pickingRange) { + inst.selectedDates[1] = date; + } + else { + inst.selectedDates = [date, date]; + } + inst.pickingRange = !inst.pickingRange; + } + else { + inst.selectedDates = [date]; + } + inst.prevDate = inst.drawDate = date.newDate(); + this._updateInput(elem); + if (inst.inline || inst.pickingRange || inst.selectedDates.length < + (inst.options.multiSelect || (inst.options.rangeSelect ? 2 : 1))) { + this._update(elem); + } + else { + this.hide(elem); + } + } + }, + + /** Generate the datepicker content for this control. + @memberof CalendarsPicker + @private + @param {Element} elem The control to affect. + @param {object} inst The current instance settings. + @return {jQuery} The datepicker content */ + _generateContent: function(elem, inst) { + var monthsToShow = inst.options.monthsToShow; + monthsToShow = ($.isArray(monthsToShow) ? monthsToShow : [1, monthsToShow]); + inst.drawDate = this._checkMinMax( + inst.drawDate || inst.get('defaultDate') || inst.options.calendar.today(), inst); + var drawDate = inst.drawDate.newDate().add(-inst.options.monthsOffset, 'm'); + // Generate months + var monthRows = ''; + for (var row = 0; row < monthsToShow[0]; row++) { + var months = ''; + for (var col = 0; col < monthsToShow[1]; col++) { + months += this._generateMonth(elem, inst, drawDate.year(), + drawDate.month(), inst.options.calendar, inst.options.renderer, (row === 0 && col === 0)); + drawDate.add(1, 'm'); + } + monthRows += this._prepare(inst.options.renderer.monthRow, inst).replace(/\{months\}/, months); + } + var picker = this._prepare(inst.options.renderer.picker, inst).replace(/\{months\}/, monthRows). + replace(/\{weekHeader\}/g, this._generateDayHeaders(inst, inst.options.calendar, inst.options.renderer)); + // Add commands + var addCommand = function(type, open, close, name, classes) { + if (picker.indexOf('{' + type + ':' + name + '}') === -1) { + return; + } + var command = inst.options.commands[name]; + var date = (inst.options.commandsAsDateFormat ? command.date.apply(elem, [inst]) : null); + picker = picker.replace(new RegExp('\\{' + type + ':' + name + '\\}', 'g'), + '<' + open + (command.status ? ' title="' + inst.options[command.status] + '"' : '') + + ' class="' + inst.options.renderer.commandClass + ' ' + + inst.options.renderer.commandClass + '-' + name + ' ' + classes + + (command.enabled(inst) ? '' : ' ' + inst.options.renderer.disabledClass) + '">' + + (date ? date.formatDate(inst.options[command.text], {localNumbers: inst.options.localNumbers}) : + inst.options[command.text]) + ''); + }; + for (var name in inst.options.commands) { + if (inst.options.commands.hasOwnProperty(name)) { + addCommand('button', 'button type="button"', 'button', name, + inst.options.renderer.commandButtonClass); + addCommand('link', 'a href="javascript:void(0)"', 'a', name, + inst.options.renderer.commandLinkClass); + } + } + picker = $(picker); + if (monthsToShow[1] > 1) { + var count = 0; + $(inst.options.renderer.monthSelector, picker).each(function() { + var nth = ++count % monthsToShow[1]; + $(this).addClass(nth === 1 ? 'first' : (nth === 0 ? 'last' : '')); + }); + } + // Add datepicker behaviour + var self = this; + function removeHighlight(elem) { + (inst.inline ? $(elem).closest('.' + self._getMarker()) : inst.div). + find(inst.options.renderer.daySelector + ' a'). + removeClass(inst.options.renderer.highlightedClass); + } + picker.find(inst.options.renderer.daySelector + ' a').hover( + function() { + removeHighlight(this); + $(this).addClass(inst.options.renderer.highlightedClass); + }, + function() { + removeHighlight(this); + }). + click(function() { + self.selectDate(elem, this); + }).end(). + find('select.' + this._monthYearClass + ':not(.' + this._anyYearClass + ')'). + change(function() { + var monthYear = $(this).val().split('/'); + self.showMonth(elem, parseInt(monthYear[1], 10), parseInt(monthYear[0], 10)); + }).end(). + find('select.' + this._anyYearClass).click(function() { + $(this).css('visibility', 'hidden'). + next('input').css({left: this.offsetLeft, top: this.offsetTop, + width: this.offsetWidth, height: this.offsetHeight}).show().focus(); + }).end(). + find('input.' + self._monthYearClass).change(function() { + try { + var year = parseInt($(this).val(), 10); + year = (isNaN(year) ? inst.drawDate.year() : year); + self.showMonth(elem, year, inst.drawDate.month(), inst.drawDate.day()); + } + catch (e) { + // Ignore + } + }).keydown(function(event) { + if (event.keyCode === 13) { // Enter + $(event.elem).change(); + } + else if (event.keyCode === 27) { // Escape + $(event.elem).hide().prev('select').css('visibility', 'visible'); + inst.elem.focus(); + } + }); + // Add keyboard handling + var data = {elem: inst.elem[0]}; + picker.keydown(data, this._keyDown).keypress(data, this._keyPress).keyup(data, this._keyUp); + // Add command behaviour + picker.find('.' + inst.options.renderer.commandClass).click(function() { + if (!$(this).hasClass(inst.options.renderer.disabledClass)) { + var action = this.className.replace( + new RegExp('^.*' + inst.options.renderer.commandClass + '-([^ ]+).*$'), '$1'); + plugin.performAction(elem, action); + } + }); + // Add classes + if (inst.options.isRTL) { + picker.addClass(inst.options.renderer.rtlClass); + } + if (monthsToShow[0] * monthsToShow[1] > 1) { + picker.addClass(inst.options.renderer.multiClass); + } + if (inst.options.pickerClass) { + picker.addClass(inst.options.pickerClass); + } + // Resize + $('body').append(picker); + var width = 0; + picker.find(inst.options.renderer.monthSelector).each(function() { + width += $(this).outerWidth(); + }); + picker.width(width / monthsToShow[0]); + // Pre-show customisation + if ($.isFunction(inst.options.onShow)) { + inst.options.onShow.apply(elem, [picker, inst.options.calendar, inst]); + } + return picker; + }, + + /** Generate the content for a single month. + @memberof CalendarsPicker + @private + @param {Element} elem The control to affect. + @param {object} inst The current instance settings. + @param {number} year The year to generate. + @param {number} month The month to generate. + @param {BaseCalendar} calendar The current calendar. + @param {object} renderer The rendering templates. + @param {boolean} first true if first of multiple months. + @return {string} The month content. */ + _generateMonth: function(elem, inst, year, month, calendar, renderer, first) { + var daysInMonth = calendar.daysInMonth(year, month); + var monthsToShow = inst.options.monthsToShow; + monthsToShow = ($.isArray(monthsToShow) ? monthsToShow : [1, monthsToShow]); + var fixedWeeks = inst.options.fixedWeeks || (monthsToShow[0] * monthsToShow[1] > 1); + var firstDay = inst.options.firstDay; + firstDay = (typeof firstDay === 'undefined' || firstDay === null ? calendar.local.firstDay : firstDay); + var leadDays = (calendar.dayOfWeek(year, month, calendar.minDay) - + firstDay + calendar.daysInWeek()) % calendar.daysInWeek(); + var numWeeks = (fixedWeeks ? 6 : Math.ceil((leadDays + daysInMonth) / calendar.daysInWeek())); + var selectOtherMonths = inst.options.selectOtherMonths && inst.options.showOtherMonths; + var minDate = (inst.pickingRange ? inst.selectedDates[0] : inst.get('minDate')); + var maxDate = inst.get('maxDate'); + var showWeeks = renderer.week.indexOf('{weekOfYear}') > -1; + var today = calendar.today(); + var drawDate = calendar.newDate(year, month, calendar.minDay); + drawDate.add(-leadDays - (fixedWeeks && + (drawDate.dayOfWeek() === firstDay || drawDate.daysInMonth() < calendar.daysInWeek())? + calendar.daysInWeek() : 0), 'd'); + var jd = drawDate.toJD(); + // Localise numbers if requested and available + var localiseNumbers = function(value) { + return (inst.options.localNumbers && calendar.local.digits ? calendar.local.digits(value) : value); + }; + // Generate weeks + var weeks = ''; + for (var week = 0; week < numWeeks; week++) { + var weekOfYear = (!showWeeks ? '' : '' + + ($.isFunction(inst.options.calculateWeek) ? + inst.options.calculateWeek(drawDate) : drawDate.weekOfYear()) + ''); + var days = ''; + for (var day = 0; day < calendar.daysInWeek(); day++) { + var selected = false; + if (inst.options.rangeSelect && inst.selectedDates.length > 0) { + selected = drawDate.compareTo(inst.selectedDates[0]) !== -1 && + drawDate.compareTo(inst.selectedDates[1]) !== +1; + } + else { + for (var i = 0; i < inst.selectedDates.length; i++) { + if (inst.selectedDates[i].compareTo(drawDate) === 0) { + selected = true; + break; + } + } + } + var dateInfo = (!$.isFunction(inst.options.onDate) ? {} : + inst.options.onDate.apply(elem, [drawDate, drawDate.month() === month])); + var selectable = (selectOtherMonths || drawDate.month() === month) && + this._isSelectable(elem, drawDate, dateInfo.selectable, minDate, maxDate); + days += this._prepare(renderer.day, inst).replace(/\{day\}/g, + (selectable ? '' + + (inst.options.showOtherMonths || drawDate.month() === month ? + dateInfo.content || localiseNumbers(drawDate.day()) : ' ') + + (selectable ? '' : '')); + drawDate.add(1, 'd'); + jd++; + } + weeks += this._prepare(renderer.week, inst).replace(/\{days\}/g, days). + replace(/\{weekOfYear\}/g, weekOfYear); + } + var monthHeader = this._prepare(renderer.month, inst).match(/\{monthHeader(:[^\}]+)?\}/); + monthHeader = (monthHeader[0].length <= 13 ? 'MM yyyy' : + monthHeader[0].substring(13, monthHeader[0].length - 1)); + monthHeader = (first ? this._generateMonthSelection( + inst, year, month, minDate, maxDate, monthHeader, calendar, renderer) : + calendar.formatDate(monthHeader, calendar.newDate(year, month, calendar.minDay), + {localNumbers: inst.options.localNumbers})); + var weekHeader = this._prepare(renderer.weekHeader, inst). + replace(/\{days\}/g, this._generateDayHeaders(inst, calendar, renderer)); + return this._prepare(renderer.month, inst).replace(/\{monthHeader(:[^\}]+)?\}/g, monthHeader). + replace(/\{weekHeader\}/g, weekHeader).replace(/\{weeks\}/g, weeks); + }, + + /** Generate the HTML for the day headers. + @memberof CalendarsPicker + @private + @param {object} inst The current instance settings. + @param {BaseCalendar} calendar The current calendar. + @param {object} renderer The rendering templates. + @return {string} A week's worth of day headers. */ + _generateDayHeaders: function(inst, calendar, renderer) { + var firstDay = inst.options.firstDay; + firstDay = (typeof firstDay === 'undefined' || firstDay === null ? calendar.local.firstDay : firstDay); + var header = ''; + for (var day = 0; day < calendar.daysInWeek(); day++) { + var dow = (day + firstDay) % calendar.daysInWeek(); + header += this._prepare(renderer.dayHeader, inst).replace(/\{day\}/g, + '' + calendar.local.dayNamesMin[dow] + ''); + } + return header; + }, + + /** Generate the selection controls for a month. + @memberof CalendarsPicker + @private + @param {object} inst The current instance settings. + @param {number} year The year to generate. + @param {number} month The month to generate. + @param {CDate} minDate The minimum date allowed. + @param {CDate} maxDate The maximum date allowed. + @param {string} monthHeader The month/year format. + @param {BaseCalendar} calendar The current calendar. + @return {string} The month selection content. */ + _generateMonthSelection: function(inst, year, month, minDate, maxDate, monthHeader, calendar) { + if (!inst.options.changeMonth) { + return calendar.formatDate(monthHeader, calendar.newDate(year, month, 1), + {localNumbers: inst.options.localNumbers}); + } + // Months + var monthNames = calendar.local[ + 'monthNames' + (monthHeader.match(/mm/i) ? '' : 'Short')]; + var html = monthHeader.replace(/m+/i, '\\x2E').replace(/y+/i, '\\x2F'); + var selector = ''; + html = html.replace(/\\x2E/, selector); + // Years + var localiseNumbers = function(value) { + return (inst.options.localNumbers && calendar.local.digits ? calendar.local.digits(value) : value); + }; + var yearRange = inst.options.yearRange; + if (yearRange === 'any') { + selector = '' + + ''; + } + else { + yearRange = yearRange.split(':'); + var todayYear = calendar.today().year(); + var start = (yearRange[0].match('c[+-].*') ? year + parseInt(yearRange[0].substring(1), 10) : + ((yearRange[0].match('[+-].*') ? todayYear : 0) + parseInt(yearRange[0], 10))); + var end = (yearRange[1].match('c[+-].*') ? year + parseInt(yearRange[1].substring(1), 10) : + ((yearRange[1].match('[+-].*') ? todayYear : 0) + parseInt(yearRange[1], 10))); + selector = ''; + } + html = html.replace(/\\x2F/, selector); + return html; + }, + + /** Prepare a render template for use. + Exclude popup/inline sections that are not applicable. + Localise text of the form: {l10n:name}. + @memberof CalendarsPicker + @private + @param {string} text The text to localise. + @param {object} inst The current instance settings. + @return {string} The localised text. */ + _prepare: function(text, inst) { + var replaceSection = function(type, retain) { + while (true) { + var start = text.indexOf('{' + type + ':start}'); + if (start === -1) { + return; + } + var end = text.substring(start).indexOf('{' + type + ':end}'); + if (end > -1) { + text = text.substring(0, start) + + (retain ? text.substr(start + type.length + 8, end - type.length - 8) : '') + + text.substring(start + end + type.length + 6); + } + } + }; + replaceSection('inline', inst.inline); + replaceSection('popup', !inst.inline); + var pattern = /\{l10n:([^\}]+)\}/; + var matches = pattern.exec(text); + while (matches) { + text = text.replace(matches[0], inst.options[matches[1]]); + matches = pattern.exec(text); + } + return text; + } + }); + + var plugin = $.calendarsPicker; // Singleton instance + + $(function() { + $(document).on('mousedown.' + pluginName, plugin._checkExternalClick). + on('resize.' + pluginName, function() { plugin.hide(plugin.curInst); }); + }); + +})(jQuery); diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.plus.js b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.plus.js new file mode 100644 index 000000000..f3014705e --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.calendars.plus.js @@ -0,0 +1,463 @@ +/* http://keith-wood.name/calendars.html + Calendars extras for jQuery v2.1.0. + Written by Keith Wood (wood.keith{at}optusnet.com.au) August 2009. + Available under the MIT (http://keith-wood.name/licence.html) license. + Please attribute the author if you use it. */ + +(function($) { // Hide scope, no $ conflict + 'use strict'; + + $.extend($.calendars.regionalOptions[''], { + invalidArguments: 'Invalid arguments', + invalidFormat: 'Cannot format a date from another calendar', + missingNumberAt: 'Missing number at position {0}', + unknownNameAt: 'Unknown name at position {0}', + unexpectedLiteralAt: 'Unexpected literal at position {0}', + unexpectedText: 'Additional text found at end' + }); + $.calendars.local = $.calendars.regionalOptions['']; + + $.extend($.calendars.cdate.prototype, { + + /** Format this date. + Found in the jquery.calendars.plus.js module. + @memberof CDate + @param {string} [format] The date format to use (see {@linkcode BaseCalendar.formatDate|formatDate}). + @param {object} [settings] Options for the formatDate function. + @return {string} The formatted date. */ + formatDate: function(format, settings) { + if (typeof format !== 'string') { + settings = format; + format = ''; + } + return this._calendar.formatDate(format || '', this, settings); + } + }); + + $.extend($.calendars.baseCalendar.prototype, { + + UNIX_EPOCH: $.calendars.instance().newDate(1970, 1, 1).toJD(), + SECS_PER_DAY: 24 * 60 * 60, + TICKS_EPOCH: $.calendars.instance().jdEpoch, // 1 January 0001 CE + TICKS_PER_DAY: 24 * 60 * 60 * 10000000, + + /** Date format for ATOM (RFC 3339/ISO 8601) - 'yyyy-mm-dd'. + @memberof BaseCalendar */ + ATOM: 'yyyy-mm-dd', + /** Date format for cookies - 'D, dd M yyyy'. + @memberof BaseCalendar */ + COOKIE: 'D, dd M yyyy', + /** Date format for the full date - 'DD, MM d, yyyy'. + @memberof BaseCalendar */ + FULL: 'DD, MM d, yyyy', + /** Date format for ISO 8601 - 'yyyy-mm-dd'. + @memberof BaseCalendar */ + ISO_8601: 'yyyy-mm-dd', + /** Date format for Julian date - days since January 1, 4713 BCE Greenwich noon. + @memberof BaseCalendar */ + JULIAN: 'J', + /** Date format for RFC 822 - 'D, d M yy'. + @memberof BaseCalendar */ + RFC_822: 'D, d M yy', + /** Date format for RFC 850 - 'DD, dd-M-yy'. + @memberof BaseCalendar */ + RFC_850: 'DD, dd-M-yy', + /** Date format for RFC 1036 - 'D, d M yy'. + @memberof BaseCalendar */ + RFC_1036: 'D, d M yy', + /** Date format for RFC 1123 - 'D, d M yyyy'. + @memberof BaseCalendar */ + RFC_1123: 'D, d M yyyy', + /** Date format for RFC 2822 - 'D, d M yyyy'. + @memberof BaseCalendar */ + RFC_2822: 'D, d M yyyy', + /** Date format for RSS (RFC 822) - 'D, d M yy'. + @memberof BaseCalendar */ + RSS: 'D, d M yy', + /** Date format for Windows ticks - number of 100-nanosecond ticks since 1 January 0001 00:00:00 UTC. + @memberof BaseCalendar */ + TICKS: '!', + /** Date format for Unix timestamp - number of seconds elapsed since the + start of the Unix epoch at 1 January 1970 00:00:00 UTC. + @memberof BaseCalendar */ + TIMESTAMP: '@', + /** Date format for W3C (ISO 8601) - 'yyyy-mm-dd'. + @memberof BaseCalendar */ + W3C: 'yyyy-mm-dd', + + /** Format a date object into a string value. + The format can be combinations of the following: +
    +
  • d - day of month (no leading zero)
  • +
  • dd - day of month (two digit)
  • +
  • o - day of year (no leading zeros)
  • +
  • oo - day of year (three digit)
  • +
  • D - day name short
  • +
  • DD - day name long
  • +
  • w - week of year (no leading zero)
  • +
  • ww - week of year (two digit)
  • +
  • m - month of year (no leading zero)
  • +
  • mm - month of year (two digit)
  • +
  • M - month name short
  • +
  • MM - month name long
  • +
  • yy - year (two digit)
  • +
  • yyyy - year (four digit)
  • +
  • YYYY - formatted year
  • +
  • J - Julian date (days since January 1, 4713 BCE Greenwich noon)
  • +
  • @ - Unix timestamp (s since 01/01/1970)
  • +
  • ! - Windows ticks (100ns since 01/01/0001)
  • +
  • '...' - literal text
  • +
  • '' - single quote
  • +
+ Found in the jquery.calendars.plus.js module. + @memberof BaseCalendar + @param {string} [format] The desired format of the date (defaults to calendar format). + @param {CDate} date The date value to format. + @param {object} [settings] Addition options, whose attributes include: + @param {string[]} [settings.dayNamesShort] Abbreviated names of the days from day 0 (Sunday). + @param {string[]} [settings.dayNames] Names of the days from day 0 (Sunday). + @param {string[]} [settings.monthNamesShort] Abbreviated names of the months. + @param {string[]} [settings.monthNames] Names of the months. + @param {boolean} [settings.localNumbers=false] true to localise numbers (if available), + false to use normal Arabic numerals. + @return {string} The date in the above format. + @throws Errors if the date is from a different calendar. */ + formatDate: function(format, date, settings) { + if (typeof format !== 'string') { + settings = date; + date = format; + format = ''; + } + if (!date) { + return ''; + } + if (date.calendar() !== this) { + throw $.calendars.local.invalidFormat || $.calendars.regionalOptions[''].invalidFormat; + } + format = format || this.local.dateFormat; + settings = settings || {}; + var dayNamesShort = settings.dayNamesShort || this.local.dayNamesShort; + var dayNames = settings.dayNames || this.local.dayNames; + var monthNamesShort = settings.monthNamesShort || this.local.monthNamesShort; + var monthNames = settings.monthNames || this.local.monthNames; + var localNumbers = settings.localNumbers || this.local.localNumbers; + // Check whether a format character is doubled + var doubled = function(match, step) { + var matches = 1; + while (iFormat + matches < format.length && format.charAt(iFormat + matches) === match) { + matches++; + } + iFormat += matches - 1; + return Math.floor(matches / (step || 1)) > 1; + }; + // Format a number, with leading zeroes if necessary + var formatNumber = function(match, value, len, step) { + var num = '' + value; + if (doubled(match, step)) { + while (num.length < len) { + num = '0' + num; + } + } + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (doubled(match) ? longNames[value] : shortNames[value]); + }; + // Localise numbers if requested and available + var localiseNumbers = localNumbers && this.local.digits ? + this.local.digits : function(value) { return value; }; + var output = ''; + var literal = false; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === '\'' && !doubled('\'')) { + literal = false; + } + else { + output += format.charAt(iFormat); + } + } + else { + switch (format.charAt(iFormat)) { + case 'd': + output += localiseNumbers(formatNumber('d', date.day(), 2)); + break; + case 'D': + output += formatName('D', date.dayOfWeek(), dayNamesShort, dayNames); + break; + case 'o': + output += formatNumber('o', date.dayOfYear(), 3); + break; + case 'w': + output += formatNumber('w', date.weekOfYear(), 2); + break; + case 'm': + output += localiseNumbers(formatNumber('m', date.month(), 2)); + break; + case 'M': + output += formatName('M', date.month() - this.minMonth, monthNamesShort, monthNames); + break; + case 'y': + output += localiseNumbers(doubled('y', 2) ? date.year() : + (date.year() % 100 < 10 ? '0' : '') + date.year() % 100); + break; + case 'Y': + doubled('Y', 2); + output += date.formatYear(); + break; + case 'J': + output += date.toJD(); + break; + case '@': + output += (date.toJD() - this.UNIX_EPOCH) * this.SECS_PER_DAY; + break; + case '!': + output += (date.toJD() - this.TICKS_EPOCH) * this.TICKS_PER_DAY; + break; + case '\'': + if (doubled('\'')) { + output += '\''; + } + else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); + } + } + } + return output; + }, + + /** Parse a string value into a date object. + See {@linkcode BaseCalendar.formatDate|formatDate} for the possible formats, plus: +
    +
  • * - ignore rest of string
  • +
+ Found in the jquery.calendars.plus.js module. + @memberof BaseCalendar + @param {string} format The expected format of the date ('' for default calendar format). + @param {string} value The date in the above format. + @param {object} [settings] Additional options whose attributes include: + @param {number} [settings.shortYearCutoff] The cutoff year for determining the century. + @param {string[]} [settings.dayNamesShort] Abbreviated names of the days from day 0 (Sunday). + @param {string[]} [settings.dayNames] Names of the days from day 0 (Sunday). + @param {string[]} [settings.monthNamesShort] Abbreviated names of the months. + @param {string[]} [settings.monthNames] Names of the months. + @return {CDate} The extracted date value or null if value is blank. + @throws Errors if the format and/or value are missing, + if the value doesn't match the format, or if the date is invalid. */ + parseDate: function(format, value, settings) { + if (typeof value === 'undefined' || value === null) { + throw $.calendars.local.invalidArguments || $.calendars.regionalOptions[''].invalidArguments; + } + value = (typeof value === 'object' ? value.toString() : value + ''); + if (value === '') { + return null; + } + format = format || this.local.dateFormat; + settings = settings || {}; + var shortYearCutoff = settings.shortYearCutoff || this.shortYearCutoff; + shortYearCutoff = (typeof shortYearCutoff !== 'string' ? shortYearCutoff : + this.today().year() % 100 + parseInt(shortYearCutoff, 10)); + var dayNamesShort = settings.dayNamesShort || this.local.dayNamesShort; + var dayNames = settings.dayNames || this.local.dayNames; + var monthNamesShort = settings.monthNamesShort || this.local.monthNamesShort; + var monthNames = settings.monthNames || this.local.monthNames; + var jd = -1; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var shortYear = false; + var literal = false; + // Check whether a format character is doubled + var doubled = function(match, step) { + var matches = 1; + while (iFormat + matches < format.length && format.charAt(iFormat + matches) === match) { + matches++; + } + iFormat += matches - 1; + return Math.floor(matches / (step || 1)) > 1; + }; + // Extract a number from the string value + var getNumber = function(match, step) { + var isDoubled = doubled(match, step); + var size = [2, 3, isDoubled ? 4 : 2, isDoubled ? 4 : 2, 10, 11, 20]['oyYJ@!'.indexOf(match) + 1]; + var digits = new RegExp('^-?\\d{1,' + size + '}'); + var num = value.substring(iValue).match(digits); + if (!num) { + throw ($.calendars.local.missingNumberAt || $.calendars.regionalOptions[''].missingNumberAt). + replace(/\{0\}/, iValue); + } + iValue += num[0].length; + return parseInt(num[0], 10); + }; + // Extract a name from the string value and convert to an index + var calendar = this; + var getName = function(match, shortNames, longNames, step) { + var names = (doubled(match, step) ? longNames : shortNames); + for (var i = 0; i < names.length; i++) { + if (value.substr(iValue, names[i].length).toLowerCase() === names[i].toLowerCase()) { + iValue += names[i].length; + return i + calendar.minMonth; + } + } + throw ($.calendars.local.unknownNameAt || $.calendars.regionalOptions[''].unknownNameAt). + replace(/\{0\}/, iValue); + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw ($.calendars.local.unexpectedLiteralAt || + $.calendars.regionalOptions[''].unexpectedLiteralAt).replace(/\{0\}/, iValue); + } + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === '\'' && !doubled('\'')) { + literal = false; + } + else { + checkLiteral(); + } + } + else { + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'w': + getNumber('w'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + var iSave = iFormat; + shortYear = !doubled('y', 2); + iFormat = iSave; + year = getNumber('y', 2); + break; + case 'Y': + year = getNumber('Y', 2); + break; + case 'J': + jd = getNumber('J') + 0.5; + if (value.charAt(iValue) === '.') { + iValue++; + getNumber('J'); + } + break; + case '@': + jd = getNumber('@') / this.SECS_PER_DAY + this.UNIX_EPOCH; + break; + case '!': + jd = getNumber('!') / this.TICKS_PER_DAY + this.TICKS_EPOCH; + break; + case '*': + iValue = value.length; + break; + case '\'': + if (doubled('\'')) { + checkLiteral(); + } + else { + literal = true; + } + break; + default: + checkLiteral(); + } + } + } + if (iValue < value.length) { + throw $.calendars.local.unexpectedText || $.calendars.regionalOptions[''].unexpectedText; + } + if (year === -1) { + year = this.today().year(); + } + else if (year < 100 && shortYear) { + year += (shortYearCutoff === -1 ? 1900 : this.today().year() - + this.today().year() % 100 - (year <= shortYearCutoff ? 0 : 100)); + } + if (doy > -1) { + month = 1; + day = doy; + for (var dim = this.daysInMonth(year, month); day > dim; dim = this.daysInMonth(year, month)) { + month++; + day -= dim; + } + } + return (jd > -1 ? this.fromJD(jd) : this.newDate(year, month, day)); + }, + + /** A date may be specified as an exact value or a relative one. + Found in the jquery.calendars.plus.js module. + @memberof BaseCalendar + @param {CDate|number|string} dateSpec The date as an object or string in the given format or + an offset - numeric days from today, or string amounts and periods, e.g. '+1m +2w'. + @param {CDate} defaultDate The date to use if no other supplied, may be null. + @param {CDate} [currentDate=null] The current date as a possible basis for relative dates, + if null today is used. + @param {string} [dateFormat] The expected date format - + see {@linkcode BaseCalendar.formatDate|formatDate}. Use '' for the calendar default format. + @param {object} [settings] Additional options whose attributes include: + @param {number} [settings.shortYearCutoff] The cutoff year for determining the century. + @param {string[]} [settings.dayNamesShort] Abbreviated names of the days from day 0 (Sunday). + @param {string[]} [settings.dayNames] Names of the days from day 0 (Sunday). + @param {string[]} [settings.monthNamesShort] Abbreviated names of the months. + @param {string[]} [settings.monthNames] Names of the months. + @return {CDate} The decoded date. */ + determineDate: function(dateSpec, defaultDate, currentDate, dateFormat, settings) { + if (currentDate && typeof currentDate !== 'object') { + settings = dateFormat; + dateFormat = currentDate; + currentDate = null; + } + if (typeof dateFormat !== 'string') { + settings = dateFormat; + dateFormat = ''; + } + var calendar = this; + var offsetString = function(offset) { + try { + return calendar.parseDate(dateFormat, offset, settings); + } + catch (e) { + // Ignore + } + offset = offset.toLowerCase(); + var date = (offset.match(/^c/) && currentDate ? + currentDate.newDate() : null) || calendar.today(); + var pattern = /([+-]?[0-9]+)\s*(d|w|m|y)?/g; + var matches = pattern.exec(offset); + while (matches) { + date.add(parseInt(matches[1], 10), matches[2] || 'd'); + matches = pattern.exec(offset); + } + return date; + }; + defaultDate = (defaultDate ? defaultDate.newDate() : null); + dateSpec = (typeof dateSpec === 'undefined' || dateSpec === null ? defaultDate : + (typeof dateSpec === 'string' ? offsetString(dateSpec) : (typeof dateSpec === 'number' ? + (isNaN(dateSpec) || dateSpec === Infinity || dateSpec === -Infinity ? defaultDate : + calendar.today().add(dateSpec, 'd')) : calendar.newDate(dateSpec)))); + return dateSpec; + } + }); + +})(jQuery); diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.plugin.js b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.plugin.js new file mode 100644 index 000000000..179f9e2a7 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/js/jquery.plugin.js @@ -0,0 +1,389 @@ +/* globals JQClass */ +/*! Simple JavaScript Inheritance + * By John Resig http://ejohn.org/ + * MIT Licensed. + */ +// Inspired by base2 and Prototype +import $ from "@/shared/common/jquery-global"; +(function(){ + 'use strict'; + var initializing = false; + + // The base JQClass implementation (does nothing) + window.JQClass = function(){}; + + // Collection of derived classes + JQClass.classes = {}; + + // Create a new JQClass that inherits from this class + JQClass.extend = function extender(prop) { + var base = this.prototype; + + // Instantiate a base 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) { // jshint loopfunc:true + // Check if we're overwriting an existing function + if (typeof prop[name] === 'function' && typeof base[name] === 'function') { + prototype[name] = (function (name, fn) { + return function () { + var __super = this._super; + // Add a new ._super() method that is the same method but on the super-class + this._super = function (args) { + return base[name].apply(this, args || []); + }; + var ret = fn.apply(this, arguments); + // The method only needs to be bound temporarily, so we remove it when we're done executing + this._super = __super; + return ret; + }; + })(name, prop[name]); + // Check if we're overwriting existing default options. + } else if (typeof prop[name] === 'object' && typeof base[name] === 'object' && name === 'defaultOptions') { + var obj1 = base[name]; + var obj2 = prop[name]; + var obj3 = {}; + var key; + for (key in obj1) { // jshint forin:false + obj3[key] = obj1[key]; + } + for (key in obj2) { // jshint forin:false + obj3[key] = obj2[key]; + } + prototype[name] = obj3; + } else { + prototype[name] = prop[name]; + } + } + + // The dummy class constructor + function JQClass() { + // All construction is actually done in the init method + if (!initializing && this._init) { + this._init.apply(this, arguments); + } + } + + // Populate our constructed prototype object + JQClass.prototype = prototype; + + // Enforce the constructor to be what we expect + JQClass.prototype.constructor = JQClass; + + // And make this class extendable + JQClass.extend = extender; + + return JQClass; + }; +})(); +/*! Abstract base class for collection plugins v1.0.2. + Written by Keith Wood (wood.keith{at}optusnet.com.au) December 2013. + Licensed under the MIT license (http://keith-wood.name/licence.html). */ +(function($) { // Ensure $, encapsulate + 'use strict'; + + /**

Abstract base class for collection plugins v1.0.2.

+

Written by Keith Wood (wood.keith{at}optusnet.com.au) December 2013.

+

Licensed under the MIT license (http://keith-wood.name/licence.html).

+

Use {@link $.JQPlugin.createPlugin} to create new plugins using this framework.

+

This base class provides common functionality such as:

+
    +
  • Creates jQuery bridge - allowing you to invoke your plugin on a collection of elements.
  • +
  • Handles initialisation including reading settings from metadata - + an instance object is attached to the affected element(s) containing all the necessary data.
  • +
  • Handles option retrieval and update - options can be set through default values, + through inline metadata, or through instantiation settings.
    + Metadata is specified as an attribute on the element: + data-<pluginName>="<option name>: '<value>', ...". + Dates should be specified as strings in this format: 'new Date(y, m-1, d)'.
  • +
  • Handles method calling - inner functions starting with '_'are inaccessible, + whereas others can be called via $(selector).pluginName('functionName').
  • +
  • Handles plugin destruction - removing all trace of the plugin.
  • +
+ @module JQPlugin + @abstract */ + JQClass.classes.JQPlugin = JQClass.extend({ + + /** Name to identify this plugin. + @example name: 'tabs' */ + name: 'plugin', + + /** Default options for instances of this plugin (default: {}). + @example defaultOptions: { + selectedClass: 'selected', + triggers: 'click' +} */ + defaultOptions: {}, + + /** Options dependent on the locale. + Indexed by language and (optional) country code, with '' denoting the default language (English/US). + Normally additional languages would be provided as separate files to all them to be included as needed. + @example regionalOptions: { + '': { + greeting: 'Hi' + } +} */ + regionalOptions: {}, + + /** Whether or not a deep merge should be performed when accumulating options. + The default is true but can be overridden in a sub-class. */ + deepMerge: true, + + /** Retrieve a marker class for affected elements. + In the format: is-<pluginName>. + @protected + @return {string} The marker class. */ + _getMarker: function() { + return 'is-' + this.name; + }, + + /** Initialise the plugin. + Create the jQuery bridge - plugin name xyz + produces singleton $.xyz and collection function $.fn.xyz. + @protected */ + _init: function() { + // Apply default localisations + $.extend(this.defaultOptions, (this.regionalOptions && this.regionalOptions['']) || {}); + // Camel-case the name + var jqName = camelCase(this.name); + // Expose jQuery singleton manager + $[jqName] = this; + // Expose jQuery collection plugin + $.fn[jqName] = function(options) { + var otherArgs = Array.prototype.slice.call(arguments, 1); + var inst = this; + var returnValue = this; + this.each(function () { + if (typeof options === 'string') { + if (options[0] === '_' || !$[jqName][options]) { + throw 'Unknown method: ' + options; + } + var methodValue = $[jqName][options].apply($[jqName], [this].concat(otherArgs)); + if (methodValue !== inst && methodValue !== undefined) { + returnValue = methodValue; + return false; + } + } else { + $[jqName]._attach(this, options); + } + }); + return returnValue; + }; + }, + + /** Set default options for all subsequent instances. + @param {object} options The new default options. + @example $.pluginName.setDefaults({name: value, ...}) */ + setDefaults: function(options) { + $.extend(this.defaultOptions, options || {}); + }, + + /** Initialise an element. Called internally only. + Adds an instance object as data named for the plugin. + Override {@linkcode module:JQPlugin~_postAttach|_postAttach} for plugin-specific processing. + @private + @param {Element} elem The element to enhance. + @param {object} options Overriding settings. */ + _attach: function(elem, options) { + elem = $(elem); + if (elem.hasClass(this._getMarker())) { + return; + } + elem.addClass(this._getMarker()); + options = $.extend(this.deepMerge, {}, this.defaultOptions, this._getMetadata(elem), options || {}); + var inst = $.extend({name: this.name, elem: elem, options: options}, this._instSettings(elem, options)); + elem.data(this.name, inst); // Save instance against element + this._postAttach(elem, inst); + this.option(elem, options); + }, + + /** Retrieve additional instance settings. + Override this in a sub-class to provide extra settings. + These are added directly to the instance object. + Default attributes of an instance object are shown as properties below: + @protected + @param {jQuery} elem The current jQuery element. + @param {object} options The instance options. + @return {object} Any extra instance values. + @property {Element} elem The element to which this instance applies. + @property {string} name The name of this plugin. + @property {object} options The accumulated options for this instance. + @example _instSettings: function(elem, options) { + return {nav: elem.find(options.navSelector)}; +} */ + _instSettings: function(elem, options) { // jshint unused:false + return {}; + }, + + /** Plugin specific post initialisation. + Override this in a sub-class to perform extra activities. + This is where you would implement your plugin's main functionality. + @protected + @param {jQuery} elem The current jQuery element. + @param {object} inst The instance settings. + @example _postAttach: function(elem, inst) { + elem.on('click.' + this.name, function() { + ... + }); +} */ + _postAttach: function(elem, inst) { // jshint unused:false + }, + + /** Retrieve metadata configuration from the element. + Metadata is specified as an attribute: + data-<pluginName>="<option name>: '<value>', ...". + Dates should be specified as strings in this format: 'new Date(y, m-1, d)'. + @private + @param {jQuery} elem The source element. + @return {object} The inline configuration or {}. */ + _getMetadata: function(elem) { + try { + var data = elem.data(this.name.toLowerCase()) || ''; + data = data.replace(/(\\?)'/g, function(e, t) { + return t ? '\'' : '"'; + }).replace(/([a-zA-Z0-9]+):/g, function(match, group, i) { + var count = data.substring(0, i).match(/"/g); // Handle embedded ':' + return (!count || count.length % 2 === 0 ? '"' + group + '":' : group + ':'); + }).replace(/\\:/g, ':'); + data = $.parseJSON('{' + data + '}'); + for (var key in data) { + if (data.hasOwnProperty(key)) { + var value = data[key]; + if (typeof value === 'string' && value.match(/^new Date\(([-0-9,\s]*)\)$/)) { // Convert dates + data[key] = eval(value); // jshint ignore:line + } + } + } + return data; + } + catch (e) { + return {}; + } + }, + + /** Retrieve the instance data for element. + @protected + @param {Element} elem The source element. + @return {object} The instance data or {} if none. */ + _getInst: function(elem) { + return $(elem).data(this.name) || {}; + }, + + /** Retrieve or reconfigure the settings for a plugin. + If new settings are provided they are applied to the instance options. + If an option name only is provided the value of that option is returned. + If no name or value is provided, all options are returned. + Override {@linkcode module:JQPlugin~_optionsChanged|_optionsChanged} + for plugin-specific processing when option values change. + @param {Element} elem The source element. + @param {object|string} [name] The collection of new option values or the name of a single option. + @param {any} [value] The value for a single named option. + @return {any|object} If retrieving a single value or all options. + @example $(selector).plugin('option', 'name', value) // Set one option +$(selector).plugin('option', {name: value, ...}) // Set multiple options +var value = $(selector).plugin('option', 'name') // Get one option +var options = $(selector).plugin('option') // Get all options */ + option: function(elem, name, value) { + elem = $(elem); + var inst = elem.data(this.name); + var options = name || {}; + if (!name || (typeof name === 'string' && typeof value === 'undefined')) { + options = (inst || {}).options; + return (options && name ? options[name] : options); + } + if (!elem.hasClass(this._getMarker())) { + return; + } + if (typeof name === 'string') { + options = {}; + options[name] = value; + } + this._optionsChanged(elem, inst, options); + $.extend(inst.options, options); + }, + + /** Plugin specific options processing. + Old value available in inst.options[name], new value in options[name]. + Override this in a sub-class to perform extra activities. + @protected + @param {jQuery} elem The current jQuery element. + @param {object} inst The instance settings. + @param {object} options The new options. + @example _optionsChanged: function(elem, inst, options) { + if (options.name != inst.options.name) { + elem.removeClass(inst.options.name).addClass(options.name); + } +} */ + _optionsChanged: function(elem, inst, options) { // jshint unused:false + }, + + /** Remove all trace of the plugin. + Override {@linkcode module:JQPlugin~_preDestroy|_preDestroy} for plugin-specific processing. + @param {Element} elem The source element. + @example $(selector).plugin('destroy') */ + destroy: function(elem) { + elem = $(elem); + if (!elem.hasClass(this._getMarker())) { + return; + } + this._preDestroy(elem, this._getInst(elem)); + elem.removeData(this.name).removeClass(this._getMarker()); + }, + + /** Plugin specific pre destruction. + It is invoked as part of the {@linkcode module:JQPlugin~destroy|destroy} processing. + Override this in a sub-class to perform extra activities and undo everything that was + done in the {@linkcode module:JQPlugin~_postAttach|_postAttach} or + {@linkcode module:JQPlugin~_optionsChanged|_optionsChanged} functions. + @protected + @param {jQuery} elem The current jQuery element. + @param {object} inst The instance settings. + @example _preDestroy: function(elem, inst) { + elem.off('.' + this.name); +} */ + _preDestroy: function(elem, inst) { // jshint unused:false + } + }); + + /** Convert names from hyphenated to camel-case. + @private + @param {string} value The original hyphenated name. + @return {string} The camel-case version. */ + function camelCase(name) { + return name.replace(/-([a-z])/g, function(match, group) { + return group.toUpperCase(); + }); + } + + /** Expose the plugin base. + @namespace $.JQPlugin */ + $.JQPlugin = { + + /** Create a new collection plugin. + @memberof $.JQPlugin + @param {string} [superClass='JQPlugin'] The name of the parent class to inherit from. + @param {object} overrides The property/function overrides for the new class. + See {@link module:JQPlugin|JQPlugin} for the base functionality. + @example $.JQPlugin.createPlugin({ // Define the plugin + name: 'tabs', + defaultOptions: {selectedClass: 'selected'}, + _initSettings: function(elem, options) { return {...}; }, + _postAttach: function(elem, inst) { ... } +}); +$('selector').tabs(); // And instantiate it */ + createPlugin: function(superClass, overrides) { + if (typeof superClass === 'object') { + overrides = superClass; + superClass = 'JQPlugin'; + } + superClass = camelCase(superClass); + var className = camelCase(overrides.name); + JQClass.classes[className] = JQClass.classes[superClass].extend(overrides); + new JQClass.classes[className](); // jshint ignore:line + } + }; + +})(jQuery); \ No newline at end of file diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/localizedName.ts b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/localizedName.ts new file mode 100644 index 000000000..cfa1ba2a1 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/localizedName.ts @@ -0,0 +1,21 @@ +import { useCallback } from "react"; +import { useTranslation } from "react-i18next"; + +export type LocalizedText = { + am?: string; + en?: string; +}; + +export const useLocalizedName = (language?: string) => { + const { i18n } = useTranslation(); + const currentLanguage = language || i18n.language; + return useCallback( + (name?: LocalizedText): string => { + if (!name) return ""; + const am = name.am?.trim() ?? ""; + const en = name.en?.trim() ?? ""; + return (currentLanguage.startsWith("am") ? am || en : en || am) || ""; + }, + [currentLanguage], + ); +}; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/FayidaInput.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/FayidaInput.tsx new file mode 100644 index 000000000..8144409db --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/FayidaInput.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import { Input } from "@/shared/common/ui/input"; // your Input component + +interface FaydaInputProps { + faydaValue: string; + setFaydaValue: (value: string) => void; // make sure it's not optional +} + +export const FaydaInput: React.FC = ({ + faydaValue, + setFaydaValue, +}) => { + return ( +
+ +
+ ); +}; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/LoadingOverlay.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/LoadingOverlay.tsx new file mode 100644 index 000000000..56c5cb688 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/LoadingOverlay.tsx @@ -0,0 +1,20 @@ +import { Progress } from "@/shared/common/ui/progress"; + +interface LoadingOverlayProps { + progress?: number; + text?: string; +} + +export function LoadingOverlay({ + progress = 50, + text = "Processing...", +}: LoadingOverlayProps) { + return ( +
+
+ {text} +
+ +
+ ); +} diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/SliderUI.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/SliderUI.tsx new file mode 100644 index 000000000..7fb80e885 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/SliderUI.tsx @@ -0,0 +1,53 @@ +import { FC } from "react"; +// @ts-ignore - Module types not available +import * as SliderPrimitive from "@radix-ui/react-slider"; + +interface SliderUIProps { + id?: string; + label: string; + description?: string; + value: number[]; + onChange: (value: number) => void; + min?: number; + max?: number; + step?: number; + required?: boolean; + disabled?: boolean; +} + +export const SliderUI: FC = ({ + id, + label, + description, + value, + onChange, + min = 0, + max = 100, + step = 1, + required = false, + disabled = false, +}) => { + return ( +
+ + {description &&

{description}

} + onChange(val[0])} + min={min} + max={max} + step={step} + disabled={disabled} + className="relative flex w-full touch-none select-none items-center h-5"> + + + + + +
{value}
+
+ ); +}; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/Text.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/Text.tsx new file mode 100644 index 000000000..6c241106a --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/Text.tsx @@ -0,0 +1,25 @@ +// src/shared/common/ui/text.tsx +import React from "react"; + +type TextProps = React.HTMLAttributes & { + fw?: number | string; + color?: string; + size?: string | number; +}; + +export const Text: React.FC = ({ + fw, + color, + size, + style, + children, + ...props +}) => { + return ( + + {children} + + ); +}; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/accordion.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/accordion.tsx new file mode 100644 index 000000000..5ccc88336 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/accordion.tsx @@ -0,0 +1,64 @@ +import * as React from "react"; +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { ChevronDownIcon } from "lucide-react"; + +import { cn } from "@/shared/lib/utils"; + +function Accordion({ + ...props +}: React.ComponentProps) { + return ; +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ); +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ); +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/alert-dialog.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/alert-dialog.tsx new file mode 100644 index 000000000..131445477 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/alert-dialog.tsx @@ -0,0 +1,155 @@ +import * as React from "react"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; + +import { cn } from "@/shared/lib/utils"; +import { buttonVariants } from "@/shared/common/ui/button"; + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return ; +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ); +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +}; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/alert.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/alert.tsx new file mode 100644 index 000000000..af7130e7f --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/alert.tsx @@ -0,0 +1,58 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/super-admin/lib/utils"; + +const alertVariants = cva( + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)); +Alert.displayName = "Alert"; + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +AlertTitle.displayName = "AlertTitle"; + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +AlertDescription.displayName = "AlertDescription"; + +export { Alert, AlertTitle, AlertDescription }; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/avatar.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/avatar.tsx new file mode 100644 index 000000000..812e64e47 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client"; + +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; + +import { cn } from "@/super-admin/lib/utils"; + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/badge.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/badge.tsx new file mode 100644 index 000000000..c9c016ee7 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/badge.tsx @@ -0,0 +1,62 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/shared/lib/utils"; +//the status edit +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + //draft and forward + default: + "bg-blue-100 text-blue-800 text-sm font-medium me-2 px-3 py-0.5 rounded-full dark:bg-blue-900 dark:text-blue-300", + secondary: + "bg-indigo-100 text-indigo-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-indigo-900 dark:text-indigo-300", + destructive: + "bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-sm dark:bg-gray-700 dark:text-gray-300", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + info: "border-transparent bg-info text-info-foreground [a&]:hover:bg-info/90", + purple: + "bg-purple-100 text-purple-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-purple-900 dark:text-purple-300", + warning: + "bg-pink-100 text-pink-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-pink-900 dark:text-pink-300", + //approved + success: + "bg-green-100 text-green-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-green-900 dark:text-green-300", + danger: + "bg-red-100 text-red-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-red-900 dark:text-red-300", + danger2: + "bg-yellow-100 text-yellow-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-yellow-900 dark:text-yellow-300", + forward: + "bg-orange-100 text-orange-800 text-sm font-medium me-2 px-3 py-0.5 rounded-full dark:bg-orange-900 dark:text-orange-300", + dispatched: + "bg-green-100 text-green-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded-full dark:bg-green-900 dark:text-green-300", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/breadcrumb.tsx b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/breadcrumb.tsx new file mode 100644 index 000000000..d1bb88e84 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/new-user-management-ui/shared/common/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { ChevronRight, MoreHorizontal } from "lucide-react"; + +import { cn } from "@/shared/lib/utils"; + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return