mirror of
https://github.com/nasa/openmct.git
synced 2025-04-08 20:04:27 +00:00
[CLOCK] Issue #1273 : Allow clock to set timezone with autocomplete dropdown option.
This commit is contained in:
parent
1bdc0497c7
commit
893e24ff98
@ -22,6 +22,7 @@
|
||||
"eventemitter3": "^1.2.0",
|
||||
"lodash": "3.10.1",
|
||||
"almond": "~0.3.2",
|
||||
"html2canvas": "^0.4.1"
|
||||
"html2canvas": "^0.4.1",
|
||||
"moment-timezone": "^0.5.13"
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ requirejs.config({
|
||||
"html2canvas": "bower_components/html2canvas/build/html2canvas.min",
|
||||
"moment": "bower_components/moment/moment",
|
||||
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
|
||||
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
|
||||
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
|
||||
"screenfull": "bower_components/screenfull/dist/screenfull.min",
|
||||
"text": "bower_components/text/text",
|
||||
|
@ -297,6 +297,39 @@ textarea.lg { position: relative; height: 300px; }
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** AUTOCOMPLETE */
|
||||
.autocomplete {
|
||||
input {
|
||||
width: 226px;
|
||||
padding: 5px 0px 5px 7px;
|
||||
}
|
||||
.icon-arrow-down {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 210px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.autocompleteOptions {
|
||||
border: 1px solid $colorFormLines;
|
||||
border-radius: 5px;
|
||||
width: 224px;
|
||||
max-height: 170px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
li {
|
||||
border: 1px solid $colorFormLines;
|
||||
padding: 8px 0px 8px 5px;
|
||||
.optionText {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.optionPreSelected {
|
||||
background-color: $colorInspectorSectionHeaderBg;
|
||||
color: $colorInspectorSectionHeaderFg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** OBJECT-HEADER */
|
||||
.object-header {
|
||||
font-size: 1em;
|
||||
|
@ -21,6 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"moment-timezone",
|
||||
"./src/indicators/ClockIndicator",
|
||||
"./src/services/TickerService",
|
||||
"./src/controllers/ClockController",
|
||||
@ -32,6 +33,7 @@ define([
|
||||
"text!./res/templates/timer.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
MomentTimezone,
|
||||
ClockIndicator,
|
||||
TickerService,
|
||||
ClockController,
|
||||
@ -200,13 +202,20 @@ define([
|
||||
"cssClass": "l-inline"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "timezone",
|
||||
"name": "Timezone",
|
||||
"control": "autocomplete",
|
||||
"options": MomentTimezone.tz.names()
|
||||
}
|
||||
],
|
||||
"model": {
|
||||
"clockFormat": [
|
||||
"YYYY/MM/DD hh:mm:ss",
|
||||
"clock12"
|
||||
]
|
||||
],
|
||||
"timezone": "UTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -20,9 +20,14 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
define([
|
||||
'moment',
|
||||
'moment-timezone'
|
||||
],
|
||||
function (
|
||||
moment,
|
||||
momentTimezone
|
||||
) {
|
||||
|
||||
/**
|
||||
* Controller for views of a Clock domain object.
|
||||
@ -37,10 +42,13 @@ define(
|
||||
var lastTimestamp,
|
||||
unlisten,
|
||||
timeFormat,
|
||||
zoneName,
|
||||
self = this;
|
||||
|
||||
function update() {
|
||||
var m = moment.utc(lastTimestamp);
|
||||
var m = zoneName ?
|
||||
moment.utc(lastTimestamp).tz(zoneName) : moment.utc(lastTimestamp);
|
||||
self.zoneAbbr = zoneName ? m.zoneAbbr() : "UTC";
|
||||
self.textValue = timeFormat && m.format(timeFormat);
|
||||
self.ampmValue = m.format("A"); // Just the AM or PM part
|
||||
}
|
||||
@ -50,21 +58,23 @@ define(
|
||||
update();
|
||||
}
|
||||
|
||||
function updateFormat(clockFormat) {
|
||||
function updateModel(model) {
|
||||
var baseFormat;
|
||||
if (model !== undefined) {
|
||||
baseFormat = model.clockFormat[0];
|
||||
|
||||
if (clockFormat !== undefined) {
|
||||
baseFormat = clockFormat[0];
|
||||
|
||||
self.use24 = clockFormat[1] === 'clock24';
|
||||
self.use24 = model.clockFormat[1] === 'clock24';
|
||||
timeFormat = self.use24 ?
|
||||
baseFormat.replace('hh', "HH") : baseFormat;
|
||||
|
||||
update();
|
||||
// If wrong timezone is provided, the UTC will be used
|
||||
zoneName = momentTimezone.tz.names().includes(model.timezone) ?
|
||||
model.timezone : "UTC";
|
||||
}
|
||||
update();
|
||||
}
|
||||
// Pull in the clock format from the domain object model
|
||||
$scope.$watch('model.clockFormat', updateFormat);
|
||||
|
||||
// Pull in the model (clockFormat and timezone) from the domain object model
|
||||
$scope.$watch('model', updateModel);
|
||||
|
||||
// Listen for clock ticks ... and stop listening on destroy
|
||||
unlisten = tickerService.listen(tick);
|
||||
@ -76,7 +86,7 @@ define(
|
||||
* @returns {string}
|
||||
*/
|
||||
ClockController.prototype.zone = function () {
|
||||
return "UTC";
|
||||
return this.zoneAbbr;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* Open MCT, Copyright (c) 2009-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@ -43,9 +43,9 @@ define(
|
||||
controller = new ClockController(mockScope, mockTicker);
|
||||
});
|
||||
|
||||
it("watches for clock format from the domain object model", function () {
|
||||
it("watches for model (clockFormat and timezone) from the domain object model", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"model.clockFormat",
|
||||
"model",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
@ -67,29 +67,35 @@ define(
|
||||
|
||||
it("formats using the format string from the model", function () {
|
||||
mockTicker.listen.mostRecentCall.args[0](TEST_TIMESTAMP);
|
||||
mockScope.$watch.mostRecentCall.args[1]([
|
||||
"YYYY-DDD hh:mm:ss",
|
||||
"clock24"
|
||||
]);
|
||||
mockScope.$watch.mostRecentCall.args[1]({
|
||||
"clockFormat": [
|
||||
"YYYY-DDD hh:mm:ss",
|
||||
"clock24"
|
||||
],
|
||||
"timezone": "Canada/Eastern"
|
||||
});
|
||||
|
||||
expect(controller.zone()).toEqual("UTC");
|
||||
expect(controller.text()).toEqual("2015-154 17:56:14");
|
||||
expect(controller.zone()).toEqual("EDT");
|
||||
expect(controller.text()).toEqual("2015-154 13:56:14");
|
||||
expect(controller.ampm()).toEqual("");
|
||||
});
|
||||
|
||||
it("formats 12-hour time", function () {
|
||||
mockTicker.listen.mostRecentCall.args[0](TEST_TIMESTAMP);
|
||||
mockScope.$watch.mostRecentCall.args[1]([
|
||||
"YYYY-DDD hh:mm:ss",
|
||||
"clock12"
|
||||
]);
|
||||
mockScope.$watch.mostRecentCall.args[1]({
|
||||
"clockFormat": [
|
||||
"YYYY-DDD hh:mm:ss",
|
||||
"clock12"
|
||||
],
|
||||
"timezone": ""
|
||||
});
|
||||
|
||||
expect(controller.zone()).toEqual("UTC");
|
||||
expect(controller.text()).toEqual("2015-154 05:56:14");
|
||||
expect(controller.ampm()).toEqual("PM");
|
||||
});
|
||||
|
||||
it("does not throw exceptions when clockFormat is undefined", function () {
|
||||
it("does not throw exceptions when model is undefined", function () {
|
||||
mockTicker.listen.mostRecentCall.args[0](TEST_TIMESTAMP);
|
||||
expect(function () {
|
||||
mockScope.$watch.mostRecentCall.args[1](undefined);
|
||||
|
@ -24,10 +24,12 @@ define([
|
||||
"./src/MCTForm",
|
||||
"./src/MCTToolbar",
|
||||
"./src/MCTControl",
|
||||
"./src/controllers/AutocompleteController",
|
||||
"./src/controllers/DateTimeController",
|
||||
"./src/controllers/CompositeController",
|
||||
"./src/controllers/ColorController",
|
||||
"./src/controllers/DialogButtonController",
|
||||
"text!./res/templates/controls/autocomplete.html",
|
||||
"text!./res/templates/controls/checkbox.html",
|
||||
"text!./res/templates/controls/datetime.html",
|
||||
"text!./res/templates/controls/select.html",
|
||||
@ -44,10 +46,12 @@ define([
|
||||
MCTForm,
|
||||
MCTToolbar,
|
||||
MCTControl,
|
||||
AutocompleteController,
|
||||
DateTimeController,
|
||||
CompositeController,
|
||||
ColorController,
|
||||
DialogButtonController,
|
||||
autocompleteTemplate,
|
||||
checkboxTemplate,
|
||||
datetimeTemplate,
|
||||
selectTemplate,
|
||||
@ -85,6 +89,10 @@ define([
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"key": "autocomplete",
|
||||
"template": autocompleteTemplate
|
||||
},
|
||||
{
|
||||
"key": "checkbox",
|
||||
"template": checkboxTemplate
|
||||
@ -131,6 +139,13 @@ define([
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "AutocompleteController",
|
||||
"implementation": AutocompleteController,
|
||||
"depends": [
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "DateTimeController",
|
||||
"implementation": DateTimeController,
|
||||
|
43
platform/forms/res/templates/controls/autocomplete.html
Normal file
43
platform/forms/res/templates/controls/autocomplete.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div ng-controller="AutocompleteController"
|
||||
class='form-control autocomplete' >
|
||||
<input type="text"
|
||||
ng-model="ngModel[field]"
|
||||
ng-change="filterOptions(ngModel[field])"
|
||||
ng-click="inputClicked($event)"
|
||||
ng-keydown="keyDown($event)"/>
|
||||
<span class="icon-arrow-down"></span>
|
||||
<div class="autocompleteOptions"
|
||||
onload="hideOptions = false"
|
||||
ng-hide="hideOptions">
|
||||
<ul>
|
||||
<li ng-repeat="opt in filteredOptions"
|
||||
ng-click="fillInput(opt.name)"
|
||||
ng-mouseover="optionMouseover(opt.optionId)"
|
||||
ng-class="optionIndex === opt.optionId ? 'optionPreSelected' : ''">
|
||||
<span class="optionText">{{opt.name}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
128
platform/forms/src/controllers/AutocompleteController.js
Normal file
128
platform/forms/src/controllers/AutocompleteController.js
Normal file
@ -0,0 +1,128 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Controller for the `autocomplete` form control.
|
||||
*
|
||||
* @memberof platform/forms
|
||||
* @constructor
|
||||
*/
|
||||
function AutocompleteController($scope) {
|
||||
|
||||
var key = {
|
||||
down: 40,
|
||||
up: 38,
|
||||
enter: 13
|
||||
}
|
||||
|
||||
if($scope.options[0].name) {
|
||||
// If "options" include name, value pair
|
||||
$scope.optionNames = $scope.options.map(function(opt) {
|
||||
return opt.name;
|
||||
})
|
||||
} else {
|
||||
// If options is only an array of string.
|
||||
$scope.optionNames = $scope.options;
|
||||
}
|
||||
|
||||
function decrementOptionIndex() {
|
||||
if($scope.optionIndex === 0) {
|
||||
$scope.optionIndex = $scope.filteredOptions.length;
|
||||
}
|
||||
$scope.optionIndex--;
|
||||
}
|
||||
|
||||
function incrementOptionIndex() {
|
||||
if($scope.optionIndex === $scope.filteredOptions.length-1) {
|
||||
$scope.optionIndex = -1;
|
||||
}
|
||||
$scope.optionIndex++;
|
||||
}
|
||||
|
||||
function fillInputWithString(string) {
|
||||
$scope.hideOptions = true;
|
||||
// Hard coded!!
|
||||
$scope.ngModel[4] = string;
|
||||
}
|
||||
|
||||
function fillInputWithIndexedOption() {
|
||||
$scope.ngModel[4] = $scope.filteredOptions[$scope.optionIndex].name;
|
||||
}
|
||||
|
||||
$scope.keyDown = function($event) {
|
||||
if($scope.filteredOptions) {
|
||||
var keyCode = $event.keyCode;
|
||||
switch(keyCode) {
|
||||
case key.down:
|
||||
incrementOptionIndex();
|
||||
fillInputWithIndexedOption();
|
||||
break;
|
||||
case key.up:
|
||||
$event.preventDefault(); // Prevents cursor jumping back and forth
|
||||
decrementOptionIndex();
|
||||
fillInputWithIndexedOption();
|
||||
break;
|
||||
case key.enter:
|
||||
if($scope.filteredOptions[$scope.optionIndex]) {
|
||||
fillInputWithString($scope.filteredOptions[$scope.optionIndex].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.filterOptions = function(string) {
|
||||
$scope.hideOptions = false;
|
||||
$scope.filteredOptions = $scope.optionNames.filter(function(option) {
|
||||
return option.toLowerCase().indexOf(string.toLowerCase()) >= 0;
|
||||
}).map(function(option, index) {
|
||||
return {
|
||||
optionId: index,
|
||||
name: option
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.inputClicked = function($event) {
|
||||
var target = $event.target;
|
||||
target.select();
|
||||
$scope.hideOptions = false;
|
||||
$scope.filterOptions(target.value);
|
||||
$scope.optionIndex = 0;
|
||||
}
|
||||
|
||||
$scope.fillInput = function(string) {
|
||||
fillInputWithString(string);
|
||||
}
|
||||
|
||||
$scope.optionMouseover = function(optionId) {
|
||||
$scope.optionIndex = optionId;
|
||||
}
|
||||
}
|
||||
|
||||
return AutocompleteController;
|
||||
|
||||
}
|
||||
);
|
@ -0,0 +1,63 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
["../../src/controllers/AutocompleteController"],
|
||||
function (AutocompleteController) {
|
||||
|
||||
describe("The autocomplete controller", function () {
|
||||
var mockScope,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
||||
mockScope.options = ['Asia/Dhaka', 'UTC', 'Toronto', 'Asia/Shanghai', 'Hotel California'];
|
||||
mockScope.ngModel = [null, null, null, null, null];
|
||||
controller = new AutocompleteController(mockScope);
|
||||
});
|
||||
|
||||
it("makes optionNames array equal to options if options is an array of string", function () {
|
||||
expect(mockScope.optionNames).toEqual(mockScope.options);
|
||||
});
|
||||
|
||||
it("filters options by returning array containing optionId and name", function () {
|
||||
mockScope.filterOptions('Asia');
|
||||
var filteredOptions = [ { optionId : 0, name : 'Asia/Dhaka' },
|
||||
{ optionId : 1, name : 'Asia/Shanghai' } ];
|
||||
expect(mockScope.filteredOptions).toEqual(filteredOptions);
|
||||
});
|
||||
|
||||
it("fills input with given string", function () {
|
||||
var str = "UTC";
|
||||
mockScope.fillInput(str);
|
||||
expect(mockScope.hideOptions).toEqual(true);
|
||||
expect(mockScope.ngModel[4]).toEqual(str);
|
||||
});
|
||||
|
||||
it("sets a new optionIndex on mouse hover", function () {
|
||||
mockScope.optionMouseover(1);
|
||||
expect(mockScope.optionIndex).toEqual(1);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -58,6 +58,7 @@ requirejs.config({
|
||||
"html2canvas": "bower_components/html2canvas/build/html2canvas.min",
|
||||
"moment": "bower_components/moment/moment",
|
||||
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
|
||||
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
|
||||
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
|
||||
"screenfull": "bower_components/screenfull/dist/screenfull.min",
|
||||
"text": "bower_components/text/text",
|
||||
|
Loading…
x
Reference in New Issue
Block a user