@@ -2,26 +2,92 @@ import 'flatpickr/dist/flatpickr.min.css';
22
33import flatpickr from 'flatpickr' ;
44import $ from 'jquery' ;
5- import Picker from 'pickadate/lib/picker' ;
65import { AutoloadPage } from 'vj/misc/Page' ;
7- import TimePicker from './timepicker' ;
6+
7+ function padTwo ( n : number ) {
8+ return n < 10 ? `0${ n } ` : `${ n } ` ;
9+ }
10+
11+ function initTimePicker ( input : HTMLInputElement ) {
12+ const $input = $ ( input ) ;
13+ const interval = 15 ;
14+ const $wrapper = $ ( '<div>' ) . css ( { position : 'relative' , display : 'inline-block' , width : '100%' } ) ;
15+ $input . wrap ( $wrapper ) ;
16+
17+ const $dropdown = $ ( '<div>' ) . css ( {
18+ position : 'absolute' ,
19+ top : $input . outerHeight ( ) ,
20+ left : 0 ,
21+ right : 0 ,
22+ maxHeight : 0 ,
23+ overflowY : 'auto' ,
24+ background : 'var(--bg-color, #fff)' ,
25+ border : '1px solid #ccc' ,
26+ borderTop : 'none' ,
27+ borderRadius : '0 0 4px 4px' ,
28+ zIndex : 1000 ,
29+ opacity : 0 ,
30+ boxShadow : '0 2px 8px rgba(0,0,0,0.15)' ,
31+ transition : 'max-height .2s ease, opacity .2s ease' ,
32+ pointerEvents : 'none' ,
33+ } ) . addClass ( 'time-picker-dropdown' ) ;
34+
35+ for ( let h = 0 ; h < 24 ; h ++ ) {
36+ for ( let m = 0 ; m < 60 ; m += interval ) {
37+ const time = `${ padTwo ( h ) } :${ padTwo ( m ) } ` ;
38+ const $item = $ ( '<div>' ) . text ( time ) . css ( {
39+ padding : '6px 12px' ,
40+ cursor : 'pointer' ,
41+ } ) . on ( 'mousedown' , ( e ) => {
42+ e . preventDefault ( ) ;
43+ $input . val ( time ) . trigger ( 'change' ) ;
44+ closeDropdown ( ) ;
45+ } ) . on ( 'mouseenter' , function ( ) {
46+ $ ( this ) . css ( 'background' , 'var(--highlight-color, #e8f0fe)' ) ;
47+ } ) . on ( 'mouseleave' , function ( ) {
48+ $ ( this ) . css ( 'background' , '' ) ;
49+ } ) ;
50+ $dropdown . append ( $item ) ;
51+ }
52+ }
53+
54+ let isOpen = false ;
55+
56+ function openDropdown ( ) {
57+ if ( isOpen ) return ;
58+ isOpen = true ;
59+ $dropdown . css ( { maxHeight : '200px' , opacity : 1 , pointerEvents : 'auto' } ) ;
60+ const val = $input . val ( ) as string ;
61+ if ( val ) {
62+ $dropdown . children ( ) . each ( function cb ( ) {
63+ if ( $ ( this ) . text ( ) !== val ) return ;
64+ const el = this as HTMLElement ;
65+ el . parentElement ! . scrollTop = el . offsetTop - el . parentElement ! . offsetTop - 80 ;
66+ } ) ;
67+ }
68+ }
69+
70+ function closeDropdown ( ) {
71+ if ( ! isOpen ) return ;
72+ isOpen = false ;
73+ $dropdown . css ( { maxHeight : 0 , opacity : 0 , pointerEvents : 'none' } ) ;
74+ }
75+
76+ $input . after ( $dropdown ) ;
77+ $input . on ( 'focus' , openDropdown ) ;
78+ // Only close when the element actually loses focus within the page,
79+ // not when the whole window loses focus (alt-tab)
80+ $input . on ( 'blur' , ( ) => {
81+ if ( document . hasFocus ( ) ) closeDropdown ( ) ;
82+ } ) ;
83+ }
884
985const datepickerPage = new AutoloadPage ( 'datepickerPage' , async ( ) => {
1086 $ ( '[data-pick-date]' ) . each ( function ( ) {
1187 flatpickr ( this , { allowInput : true } ) ;
1288 } ) ;
1389 $ ( '[data-pick-time]' ) . each ( function ( ) {
14- const $this = $ ( this ) ;
15- if ( ! $this . data ( 'pickatime' ) ) {
16- // eslint-disable-next-line no-new
17- new Picker ( this , 'pickatime' , TimePicker , {
18- format : 'H:i' ,
19- editable : true ,
20- interval : 15 ,
21- clear : false ,
22- onSet ( ) { $this . trigger ( 'change' ) ; } ,
23- } ) ;
24- }
90+ initTimePicker ( this as HTMLInputElement ) ;
2591 } ) ;
2692} ) ;
2793
0 commit comments