',
+ '
',
' ',
'
',
@@ -418,8 +430,8 @@
* This is computed statically now, but can be changed to be measured if the circumstances
* of calendar sizing are changed.
*/
- var TIME_PANE_HEIGHT = { MIN5: { GTSM: 172 + 20, SM: 292 + 20 },
- MIN1: { GTSM: 364 + 20, SM: 454 + 20 } };
+ var TIME_PANE_HEIGHT = { MIN5: { GTXS: 172 + 20, XS: 291 + 20 },
+ MIN1: { GTXS: 364 + 20, XS: 454 + 20 } };
/**
* Width of the calendar pane used to check if the pane is going outside the boundary of
@@ -429,7 +441,7 @@
* This is computed statically now, but can be changed to be measured if the circumstances
* of calendar sizing are changed.
*/
- var TIME_PANE_WIDTH = { GTSM: 510 + 20, SM: 272 + 20 };
+ var TIME_PANE_WIDTH = { GTXS: 510 + 20, XS: 274 + 20 };
/**
* Controller for sg-timepicker.
@@ -624,7 +636,7 @@
if (this.$attrs.ngDisabled) {
// The expression is to be evaluated against the directive element's scope and not
// the directive's isolate scope.
- var scope = this.$mdUtil.validateScope(this.$element) ? this.$element.scope() : null;
+ var scope = this.$scope.$parent;
if (scope) {
scope.$watch(this.$attrs.ngDisabled, function(isDisabled) {
self.setDisabled(isDisabled);
@@ -731,7 +743,6 @@
TimePickerCtrl.prototype.attachTimePane = function() {
var timePane = this.timePane;
this.$element.addClass('sg-timepicker-open');
- this.$element.find('button').addClass('md-primary');
var elementRect = this.inputContainer.getBoundingClientRect();
var bodyRect = document.body.getBoundingClientRect();
@@ -741,26 +752,48 @@
var paneTop = elementRect.top - bodyRect.top;
var paneLeft = elementRect.left - bodyRect.left;
+ // If ng-material has disabled body scrolling (for example, if a dialog is open),
+ // then it's possible that the already-scrolled body has a negative top/left. In this case,
+ // we want to treat the "real" top as (0 - bodyRect.top). In a normal scrolling situation,
+ // though, the top of the viewport should just be the body's scroll position.
+ var viewportTop = (bodyRect.top < 0 && document.body.scrollTop === 0) ?
+ -bodyRect.top :
+ document.body.scrollTop;
+
+ var viewportLeft = (bodyRect.left < 0 && document.body.scrollLeft === 0) ?
+ -bodyRect.left :
+ document.body.scrollLeft;
+
+ var viewportBottom = viewportTop + this.$window.innerHeight;
+ var viewportRight = viewportLeft + this.$window.innerWidth;
+
// If the right edge of the pane would be off the screen and shifting it left by the
- // difference would not go past the left edge of the screen.
- var paneWidth = this.$mdMedia('sm')? TIME_PANE_WIDTH.SM : TIME_PANE_WIDTH.GTSM;
- if (paneLeft + paneWidth > bodyRect.right &&
- bodyRect.right - paneWidth > 0) {
- paneLeft = bodyRect.right - paneWidth;
+ // difference would not go past the left edge of the screen. If the time pane is too
+ // big to fit on the screen at all, move it to the left of the screen and scale the entire
+ // element down to fit.
+ var paneWidth = this.$mdMedia('xs')? TIME_PANE_WIDTH.XS : TIME_PANE_WIDTH.GTXS;
+ if (paneLeft + paneWidth > viewportRight) {
+ if (viewportRight - paneWidth > 0) {
+ paneLeft = viewportRight - paneWidth;
+ } else {
+ paneLeft = viewportLeft;
+ var scale = this.$window.innerWidth / paneWidth;
+ timePane.style.transform = 'scale(' + scale + ')';
+ }
timePane.classList.add('sg-timepicker-pos-adjusted');
}
- timePane.style.left = paneLeft + 'px';
// If the bottom edge of the pane would be off the screen and shifting it up by the
// difference would not go past the top edge of the screen.
var min = (typeof this.time == 'object' && this.time.getMinutes() % 5 === 0)? 'MIN5' : 'MIN1';
- var paneHeight = this.$mdMedia('sm')? TIME_PANE_HEIGHT[min].SM : TIME_PANE_HEIGHT[min].GTSM;
- if (paneTop + paneHeight > bodyRect.bottom &&
- bodyRect.bottom - paneHeight > 0) {
- paneTop = bodyRect.bottom - paneHeight;
+ var paneHeight = this.$mdMedia('xs')? TIME_PANE_HEIGHT[min].XS : TIME_PANE_HEIGHT[min].GTXS;
+ if (paneTop + paneHeight > viewportBottom &&
+ viewportBottom - paneHeight > viewportTop) {
+ paneTop = viewportBottom - paneHeight;
timePane.classList.add('sg-timepicker-pos-adjusted');
}
+ timePane.style.left = paneLeft + 'px';
timePane.style.top = paneTop + 'px';
document.body.appendChild(timePane);
@@ -779,10 +812,13 @@
/** Detach the floating time pane from the document. */
TimePickerCtrl.prototype.detachTimePane = function() {
this.$element.removeClass('sg-timepicker-open');
- this.$element.find('button').removeClass('md-primary');
this.timePane.classList.remove('md-pane-open');
this.timePane.classList.remove('md-timepicker-pos-adjusted');
+ if (this.isTimeOpen) {
+ this.$mdUtil.enableScrolling();
+ }
+
if (this.timePane.parentNode) {
// Use native DOM removal because we do not want any of the angular state of this element
// to be disposed.
@@ -822,11 +858,12 @@
/** Close the floating time pane. */
TimePickerCtrl.prototype.closeTimePane = function() {
if (this.isTimeOpen) {
- this.isTimeOpen = false;
this.detachTimePane();
+ this.isTimeOpen = false;
this.timePaneOpenedFrom.focus();
this.timePaneOpenedFrom = null;
- this.$mdUtil.enableScrolling();
+
+ this.ngModelCtrl.$setTouched();
document.body.removeEventListener('click', this.bodyClickHandler);
window.removeEventListener('resize', this.windowResizeHandler);
@@ -853,6 +890,9 @@
* @param {boolean} isFocused
*/
TimePickerCtrl.prototype.setFocused = function(isFocused) {
+ if (!isFocused) {
+ this.ngModelCtrl.$setTouched();
+ }
this.isFocused = isFocused;
};
diff --git a/UI/WebServerResources/scss/components/timepicker/timepicker-default-theme.css b/UI/WebServerResources/scss/components/timepicker/timepicker-default-theme.css
index 95030874c..df593e041 100644
--- a/UI/WebServerResources/scss/components/timepicker/timepicker-default-theme.css
+++ b/UI/WebServerResources/scss/components/timepicker/timepicker-default-theme.css
@@ -3,17 +3,19 @@
sg-timepicker.md-THEME_NAME-theme {
background: white; }
-.md-THEME_NAME-theme .sg-timepicker-input-container {
- border-bottom-color: '{{background-300}}'; }
- .md-THEME_NAME-theme .sg-timepicker-input-container.sg-timepicker-focused {
+.md-THEME_NAME-theme {
+ .sg-timepicker-input-container {
+ border-bottom-color: '{{background-300}}'; }
+ .sg-timepicker-input-container.sg-timepicker-focused {
border-bottom-color: '{{primary-500}}'; }
- .md-THEME_NAME-theme .sg-timepicker-input-container.sg-timepicker-invalid {
+ .sg-timepicker-input-container.sg-timepicker-invalid {
border-bottom-color: '{{warn-500}}'; }
-.md-THEME_NAME-theme .sg-timepicker-time-pane {
+ .sg-timepicker-time-pane {
border-color: '{{background-300}}'; }
-.md-THEME_NAME-theme .sg-timepicker-triangle-button:hover .sg-timepicker-expand-triangle {
+ .sg-timepicker-triangle-button:hover .sg-timepicker-expand-triangle {
border-top-color: '{{foreground-2}}'; }
-.md-THEME_NAME-theme .sg-timepicker-open .sg-timepicker-time-icon {
+ .sg-timepicker-open .sg-timepicker-time-icon {
fill: '{{primary-500}}'; }
-.md-THEME_NAME-theme .sg-timepicker-calendar {
+ .sg-timepicker-calendar {
background: white; }
+}
\ No newline at end of file
diff --git a/UI/WebServerResources/scss/components/timepicker/timepicker.scss b/UI/WebServerResources/scss/components/timepicker/timepicker.scss
index b90ad17e2..8a0ce510c 100644
--- a/UI/WebServerResources/scss/components/timepicker/timepicker.scss
+++ b/UI/WebServerResources/scss/components/timepicker/timepicker.scss
@@ -1,9 +1,11 @@
/** Styles for sgTimePane. */
+
$sg-time-pane-cell-size: 40px;
$sg-time-width: (12 * $sg-time-pane-cell-size) + (2 * $md-calendar-side-padding);
+$sg-time-font-size: 13px;
-sg-time-pane {
- font-size: 13px;
+.sg-time-pane {
+ font-size: $sg-time-font-size;
user-select: none;
}
@@ -12,11 +14,6 @@ sg-time-pane {
border-bottom: solid 1px rgb(224,224,224);
}
-.toggle-pane {
- // TODO: should use background-200
- border-top: solid 1px rgb(224,224,224);
-}
-
.sg-time-scroll-mask {
display: inline-block;
overflow: hidden;
@@ -39,35 +36,53 @@ sg-time-pane {
padding: 0 $md-calendar-side-padding;
}
-.md-button.md-fab.hourBtn,
-.md-button.md-fab.minuteBtn,
+// Circle element inside of every hour/minute cell used to indicate selection or focus.
+.sg-time-selection-indicator {
+ transition: background-color, color $swift-ease-out-duration $swift-ease-out-timing-function;
+
+ border-radius: 50%;
+ display: inline-block;
+
+ font-size: $sg-time-font-size;
+ font-weight: normal;
+
+ width: $md-calendar-cell-emphasis-size;
+ min-width: $md-calendar-cell-emphasis-size;
+ height: $md-calendar-cell-emphasis-size;
+ line-height: $md-calendar-cell-emphasis-size;
+ margin: 0;
+
+// .md-calendar-date:not(.md-disabled) & {
+// cursor: pointer;
+// }
+
+ &:hover {
+ background: $colorGrey300; // {{background-300}}
+ }
+
+ &.md-focus {
+ background: $colorGrey200; // {{background-hue-1}}
+ }
+
+ &.sg-time-selected, &:hover.sg-time-selected, &.md-focus.sg-time-selected {
+ background: sg-color($sogoBlue, 500); // {{primary-500}}
+ color: #fff; // {{primary-500-contrast}}
+ border-color: transparent;
+ }
+}
+
.md-button.md-fab.toggleBtn,
-.md-button.md-fab.hourBtn.md-focused,
-.md-button.md-fab.minuteBtn.md-focused,
.md-button.md-fab.toggleBtn.md-focused,
-.md-button.md-fab.hourBtn.md-focus,
-.md-button.md-fab.minuteBtn.md-focus,
.md-button.md-fab.toggleBtn.md-focus {
min-width: 10px;
min-height: 10px;
border-color: transparent;
font-weight:normal;
- color: rgba(0,0,0,0.5);
+ color: #fff;
height: $sg-time-pane-cell-size;
width: $sg-time-pane-cell-size;
line-height: $sg-time-pane-cell-size;
box-shadow: none;
- margin: 0;
- &:not(.md-bg):not(.toggleBtn) {
- background-color: transparent;
- &:hover {
- background-color: lightgrey;
- color: #666666;
- }
- }
-}
-.md-button.md-fab.toggleBtn {
- color: white;
margin: 5px;
}
@@ -189,18 +204,26 @@ sg-timepicker[disabled] {
// Open state for all of the elements of the picker.
.sg-timepicker-open {
.sg-timepicker-input-container {
- margin-left: -$md-datepicker-button-gap;
+ @include rtl-prop(margin-left, margin-right, -$md-datepicker-button-gap);
+
+ // The negative bottom margin prevents the content around the datepicker
+ // from jumping when it gets opened.
+ margin-bottom: -$md-datepicker-border-bottom-gap;
border: none;
}
.sg-timepicker-input {
- margin-left: 24px;
+ @include rtl-prop(margin-left, margin-right, 24px);
height: 40px;
}
.sg-timepicker-triangle-button {
display: none;
}
+
+ .sg-timepicker-icon {
+ color: sg-color($sogoBlue, 500); //'{{primary-500}}';
+ }
}
// When the position of the floating calendar pane is adjusted to remain inside