Skip to content

Commit e9778f7

Browse files
committed
Merge pull request #171 from pgelinas/gh-pages
Fix for issue #170
2 parents 5b26def + cc79580 commit e9778f7

6 files changed

Lines changed: 143 additions & 24 deletions

File tree

css/bootstrap-timepicker.css

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
height: 16px;
3333
}
3434
.bootstrap-timepicker-widget.dropdown-menu {
35-
padding: 2px 3px 2px 2px;
35+
padding: 4px;
3636
}
3737
.bootstrap-timepicker-widget.dropdown-menu.open {
3838
display: inline-block;
@@ -43,20 +43,44 @@
4343
border-right: 7px solid transparent;
4444
content: "";
4545
display: inline-block;
46-
left: 9px;
4746
position: absolute;
48-
top: -7px;
4947
}
5048
.bootstrap-timepicker-widget.dropdown-menu:after {
5149
border-bottom: 6px solid #FFFFFF;
5250
border-left: 6px solid transparent;
5351
border-right: 6px solid transparent;
5452
content: "";
5553
display: inline-block;
56-
left: 10px;
5754
position: absolute;
55+
}
56+
.bootstrap-timepicker-widget.timepicker-orient-left:before {
57+
left: 6px;
58+
}
59+
.bootstrap-timepicker-widget.timepicker-orient-left:after {
60+
left: 7px;
61+
}
62+
.bootstrap-timepicker-widget.timepicker-orient-right:before {
63+
right: 6px;
64+
}
65+
.bootstrap-timepicker-widget.timepicker-orient-right:after {
66+
right: 7px;
67+
}
68+
.bootstrap-timepicker-widget.timepicker-orient-top:before {
69+
top: -7px;
70+
}
71+
.bootstrap-timepicker-widget.timepicker-orient-top:after {
5872
top: -6px;
5973
}
74+
.bootstrap-timepicker-widget.timepicker-orient-bottom:before {
75+
bottom: -7px;
76+
border-bottom: 0;
77+
border-top: 7px solid #999;
78+
}
79+
.bootstrap-timepicker-widget.timepicker-orient-bottom:after {
80+
bottom: -6px;
81+
border-bottom: 0;
82+
border-top: 6px solid #ffffff;
83+
}
6084
.bootstrap-timepicker-widget a.btn,
6185
.bootstrap-timepicker-widget input {
6286
border-radius: 4px;

css/bootstrap-timepicker.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/bootstrap-timepicker.js

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
this.isOpen = options.isOpen;
2222
this.minuteStep = options.minuteStep;
2323
this.modalBackdrop = options.modalBackdrop;
24+
this.orientation = options.orientation;
2425
this.secondStep = options.secondStep;
2526
this.showInputs = options.showInputs;
2627
this.showMeridian = options.showMeridian;
@@ -69,7 +70,7 @@
6970
}
7071

7172
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));
7374
} else {
7475
this.$widget = false;
7576
}
@@ -350,6 +351,8 @@
350351
$(document).off('mousedown.timepicker, touchend.timepicker');
351352

352353
this.isOpen = false;
354+
// show/hide approach taken by datepicker
355+
this.$widget.detach();
353356
},
354357

355358
highlightUnit: function() {
@@ -603,6 +606,62 @@
603606
return false;
604607
},
605608

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+
606665
remove: function() {
607666
$('document').off('.timepicker');
608667
if (this.$widget) {
@@ -794,10 +853,15 @@
794853
return;
795854
}
796855

856+
// show/hide approach taken by datepicker
857+
this.$widget.appendTo(this.appendWidgetTo);
797858
var self = this;
798859
$(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)) {
801865
self.hideWidget();
802866
}
803867
});
@@ -813,6 +877,7 @@
813877
}
814878
});
815879

880+
this.place();
816881
if (this.disableFocus) {
817882
this.$element.blur();
818883
}
@@ -1017,12 +1082,13 @@
10171082
isOpen: false,
10181083
minuteStep: 15,
10191084
modalBackdrop: false,
1085+
orientation: { x: 'auto', y: 'auto'},
10201086
secondStep: 15,
10211087
showSeconds: false,
10221088
showInputs: true,
10231089
showMeridian: true,
10241090
template: 'dropdown',
1025-
appendWidgetTo: '.bootstrap-timepicker',
1091+
appendWidgetTo: 'body',
10261092
showWidgetOnAddonClick: true
10271093
};
10281094

0 commit comments

Comments
 (0)