|
21 | 21 | this.isOpen = options.isOpen; |
22 | 22 | this.minuteStep = options.minuteStep; |
23 | 23 | this.modalBackdrop = options.modalBackdrop; |
| 24 | + this.orientation = options.orientation; |
24 | 25 | this.secondStep = options.secondStep; |
25 | 26 | this.showInputs = options.showInputs; |
26 | 27 | this.showMeridian = options.showMeridian; |
|
69 | 70 | } |
70 | 71 |
|
71 | 72 | if (this.template !== false) { |
72 | | - this.$widget = $(this.getTemplate()).prependTo(this.$element.parents(this.appendWidgetTo)).on('click', $.proxy(this.widgetClick, this)); |
| 73 | + this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this)); |
73 | 74 | } else { |
74 | 75 | this.$widget = false; |
75 | 76 | } |
|
350 | 351 | $(document).off('mousedown.timepicker, touchend.timepicker'); |
351 | 352 |
|
352 | 353 | this.isOpen = false; |
| 354 | + // show/hide approach taken by datepicker |
| 355 | + this.$widget.detach(); |
353 | 356 | }, |
354 | 357 |
|
355 | 358 | highlightUnit: function() { |
|
603 | 606 | return false; |
604 | 607 | }, |
605 | 608 |
|
| 609 | + // This method was adapted from bootstrap-datepicker. |
| 610 | + place : function() { |
| 611 | + if (this.isInline) { |
| 612 | + return; |
| 613 | + } |
| 614 | + var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth = |
| 615 | + $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop(); |
| 616 | + |
| 617 | + var zIndex = parseInt(this.$element.parents().filter(function() {}).first().css('z-index'), 10) + 10; |
| 618 | + var offset = this.component ? this.component.parent().offset() : this.$element.offset(); |
| 619 | + var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false); |
| 620 | + var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false); |
| 621 | + var left = offset.left, top = offset.top; |
| 622 | + |
| 623 | + this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left'); |
| 624 | + |
| 625 | + if (this.orientation.x !== 'auto') { |
| 626 | + this.picker.addClass('datepicker-orient-' + this.orientation.x); |
| 627 | + if (this.orientation.x === 'right') { |
| 628 | + left -= widgetWidth - width; |
| 629 | + } |
| 630 | + } else{ |
| 631 | + // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways |
| 632 | + // Default to left |
| 633 | + this.$widget.addClass('timepicker-orient-left'); |
| 634 | + if (offset.left < 0) { |
| 635 | + left -= offset.left - visualPadding; |
| 636 | + } else if (offset.left + widgetWidth > windowWidth) { |
| 637 | + left = windowWidth - widgetWidth - visualPadding; |
| 638 | + } |
| 639 | + } |
| 640 | + // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget |
| 641 | + var yorient = this.orientation.y, topOverflow, bottomOverflow; |
| 642 | + if (yorient === 'auto') { |
| 643 | + topOverflow = -scrollTop + offset.top - widgetHeight; |
| 644 | + bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight); |
| 645 | + if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) { |
| 646 | + yorient = 'top'; |
| 647 | + } else { |
| 648 | + yorient = 'bottom'; |
| 649 | + } |
| 650 | + } |
| 651 | + this.$widget.addClass('timepicker-orient-' + yorient); |
| 652 | + if (yorient === 'top'){ |
| 653 | + top += height; |
| 654 | + } else{ |
| 655 | + top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10); |
| 656 | + } |
| 657 | + |
| 658 | + this.$widget.css({ |
| 659 | + top : top, |
| 660 | + left : left, |
| 661 | + zIndex : zIndex |
| 662 | + }); |
| 663 | + }, |
| 664 | + |
606 | 665 | remove: function() { |
607 | 666 | $('document').off('.timepicker'); |
608 | 667 | if (this.$widget) { |
|
794 | 853 | return; |
795 | 854 | } |
796 | 855 |
|
| 856 | + // show/hide approach taken by datepicker |
| 857 | + this.$widget.appendTo(this.appendWidgetTo); |
797 | 858 | var self = this; |
798 | 859 | $(document).on('mousedown.timepicker, touchend.timepicker', function (e) { |
799 | | - // Clicked outside the timepicker, hide it |
800 | | - if ($(e.target).closest('.bootstrap-timepicker-widget').length === 0) { |
| 860 | + // This condition was inspired by bootstrap-datepicker. |
| 861 | + // The element the timepicker is invoked on is the input but it has a sibling for addon/button. |
| 862 | + if (!(self.$element.parent().find(e.target).length || |
| 863 | + self.$widget.is(e.target) || |
| 864 | + self.$widget.find(e.target).length)) { |
801 | 865 | self.hideWidget(); |
802 | 866 | } |
803 | 867 | }); |
|
813 | 877 | } |
814 | 878 | }); |
815 | 879 |
|
| 880 | + this.place(); |
816 | 881 | if (this.disableFocus) { |
817 | 882 | this.$element.blur(); |
818 | 883 | } |
|
1017 | 1082 | isOpen: false, |
1018 | 1083 | minuteStep: 15, |
1019 | 1084 | modalBackdrop: false, |
| 1085 | + orientation: { x: 'auto', y: 'auto'}, |
1020 | 1086 | secondStep: 15, |
1021 | 1087 | showSeconds: false, |
1022 | 1088 | showInputs: true, |
1023 | 1089 | showMeridian: true, |
1024 | 1090 | template: 'dropdown', |
1025 | | - appendWidgetTo: '.bootstrap-timepicker', |
| 1091 | + appendWidgetTo: 'body', |
1026 | 1092 | showWidgetOnAddonClick: true |
1027 | 1093 | }; |
1028 | 1094 |
|
|
0 commit comments