mirror of
https://github.com/nasa/openmct.git
synced 2025-06-29 20:23:04 +00:00
Compare commits
12 Commits
vue-hack
...
inline-edi
Author | SHA1 | Date | |
---|---|---|---|
889350623a | |||
aac1f02bd6 | |||
e759761a04 | |||
490567c8e8 | |||
ede5b85c93 | |||
82f32a57f4 | |||
0dd6a4eb44 | |||
4c03a3b31d | |||
aaeffb16e3 | |||
41f6047c96 | |||
c35cdf176f | |||
05227286c4 |
@ -26,6 +26,7 @@ define([
|
|||||||
"./src/InspectorPaneController",
|
"./src/InspectorPaneController",
|
||||||
"./src/BrowseObjectController",
|
"./src/BrowseObjectController",
|
||||||
"./src/MenuArrowController",
|
"./src/MenuArrowController",
|
||||||
|
"./src/ObjectHeaderController",
|
||||||
"./src/navigation/NavigationService",
|
"./src/navigation/NavigationService",
|
||||||
"./src/navigation/NavigateAction",
|
"./src/navigation/NavigateAction",
|
||||||
"./src/navigation/OrphanNavigationHandler",
|
"./src/navigation/OrphanNavigationHandler",
|
||||||
@ -48,6 +49,7 @@ define([
|
|||||||
InspectorPaneController,
|
InspectorPaneController,
|
||||||
BrowseObjectController,
|
BrowseObjectController,
|
||||||
MenuArrowController,
|
MenuArrowController,
|
||||||
|
ObjectHeaderController,
|
||||||
NavigationService,
|
NavigationService,
|
||||||
NavigateAction,
|
NavigateAction,
|
||||||
OrphanNavigationHandler,
|
OrphanNavigationHandler,
|
||||||
@ -140,6 +142,13 @@ define([
|
|||||||
"$location",
|
"$location",
|
||||||
"$attrs"
|
"$attrs"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "ObjectHeaderController",
|
||||||
|
"implementation": ObjectHeaderController,
|
||||||
|
"depends": [
|
||||||
|
"$scope"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"representations": [
|
"representations": [
|
||||||
|
@ -20,9 +20,14 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
|
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
|
||||||
<span class="l-elem-wrapper l-flex-row flex-elem grows">
|
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
|
||||||
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
|
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
|
||||||
<span class='title-label flex-elem holder flex-can-shrink'>{{model.name}}</span>
|
<span contenteditable="true"
|
||||||
|
class='title-label flex-elem holder flex-can-shrink s-inline-edit'
|
||||||
|
ng-class="{'s-status-editing': inlineEdit}"
|
||||||
|
ng-click="controller.edit()"
|
||||||
|
ng-blur="controller.updateName($event)"
|
||||||
|
ng-keypress="controller.updateName($event)">{{model.name}}</span>
|
||||||
<span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
|
<span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
|
||||||
<mct-representation
|
<mct-representation
|
||||||
key="'menu-arrow'"
|
key="'menu-arrow'"
|
||||||
|
76
platform/commonUI/browse/src/ObjectHeaderController.js
Normal file
76
platform/commonUI/browse/src/ObjectHeaderController.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 to provide the ability to inline edit an object name.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
|
*/
|
||||||
|
function ObjectHeaderController($scope) {
|
||||||
|
this.$scope = $scope;
|
||||||
|
this.$scope.inlineEdit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the blur and enter/return key press events
|
||||||
|
* to update the object name.
|
||||||
|
*
|
||||||
|
* @param event the mouse event
|
||||||
|
*/
|
||||||
|
ObjectHeaderController.prototype.updateName = function (event) {
|
||||||
|
if (event && (event.type === 'blur' || event.which === 13)) {
|
||||||
|
var name = event.currentTarget.innerHTML;
|
||||||
|
|
||||||
|
if (name.length === 0) {
|
||||||
|
name = "Unnamed " + this.$scope.domainObject.getCapability("type").typeDef.name;
|
||||||
|
event.currentTarget.innerHTML = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name !== this.$scope.domainObject.model.name) {
|
||||||
|
this.$scope.domainObject.getCapability('mutation').mutate(function (model) {
|
||||||
|
model.name = name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$scope.inlineEdit = false;
|
||||||
|
|
||||||
|
if (event.which === 13) {
|
||||||
|
event.currentTarget.blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the click event to mark the filed as inline edit.
|
||||||
|
*/
|
||||||
|
ObjectHeaderController.prototype.edit = function () {
|
||||||
|
this.$scope.inlineEdit = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ObjectHeaderController;
|
||||||
|
}
|
||||||
|
);
|
94
platform/commonUI/browse/test/ObjectHeaderControllerSpec.js
Normal file
94
platform/commonUI/browse/test/ObjectHeaderControllerSpec.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/ObjectHeaderController"],
|
||||||
|
function (ObjectHeaderController) {
|
||||||
|
|
||||||
|
describe("The object header controller", function () {
|
||||||
|
var mockScope,
|
||||||
|
mockDomainObject,
|
||||||
|
mockMutationCapability,
|
||||||
|
mockEvent,
|
||||||
|
mockCurrentTarget,
|
||||||
|
controller;
|
||||||
|
|
||||||
|
function getModel() {
|
||||||
|
return {
|
||||||
|
name: 'Test name'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
|
||||||
|
|
||||||
|
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "model"]);
|
||||||
|
mockDomainObject.model = getModel();
|
||||||
|
mockDomainObject.getCapability.andReturn(mockMutationCapability);
|
||||||
|
|
||||||
|
mockScope = jasmine.createSpyObj("$scope", ["name"]);
|
||||||
|
mockScope.domainObject = mockDomainObject;
|
||||||
|
|
||||||
|
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur"]);
|
||||||
|
mockCurrentTarget.blur.andReturn({ blur: function () {} });
|
||||||
|
|
||||||
|
mockEvent = jasmine.createSpyObj('event', ["which"]);
|
||||||
|
mockEvent.currentTarget = mockCurrentTarget;
|
||||||
|
|
||||||
|
controller = new ObjectHeaderController(mockScope);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates the model with new name", function () {
|
||||||
|
mockScope.name = 'New name';
|
||||||
|
controller.updateName();
|
||||||
|
|
||||||
|
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not update the model for blank names", function () {
|
||||||
|
mockScope.name = "";
|
||||||
|
controller.updateName();
|
||||||
|
|
||||||
|
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates the model on enter keypress event only", function () {
|
||||||
|
mockScope.name = 'New name';
|
||||||
|
controller.updateName(mockEvent);
|
||||||
|
|
||||||
|
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
mockEvent.which = 13;
|
||||||
|
controller.updateName(mockEvent);
|
||||||
|
|
||||||
|
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("blurs the field on enter key press", function () {
|
||||||
|
mockEvent.which = 13;
|
||||||
|
controller.updateName(mockEvent);
|
||||||
|
|
||||||
|
expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -111,7 +111,9 @@ $bubbleMaxW: 300px;
|
|||||||
$reqSymbolW: 15px;
|
$reqSymbolW: 15px;
|
||||||
$reqSymbolM: $interiorMargin * 2;
|
$reqSymbolM: $interiorMargin * 2;
|
||||||
$reqSymbolFontSize: 0.75em;
|
$reqSymbolFontSize: 0.75em;
|
||||||
$inputTextP: 3px 5px;
|
$inputTextPTopBtm: 3px;
|
||||||
|
$inputTextPLeftRight: 5px;
|
||||||
|
$inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
||||||
/*************** Wait Spinner Defaults */
|
/*************** Wait Spinner Defaults */
|
||||||
$waitSpinnerD: 32px;
|
$waitSpinnerD: 32px;
|
||||||
$waitSpinnerTreeD: 20px;
|
$waitSpinnerTreeD: 20px;
|
||||||
|
@ -316,23 +316,25 @@
|
|||||||
text-shadow: $shdwItemText;
|
text-shadow: $shdwItemText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin input-base($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
|
@mixin input-base() {
|
||||||
@include appearance(none);
|
@include appearance(none);
|
||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
box-shadow: inset $shdw;
|
&:focus { outline: 0; }
|
||||||
background: $bg;
|
|
||||||
border: none;
|
|
||||||
color: $fg;
|
|
||||||
outline: none;
|
|
||||||
&.error {
|
&.error {
|
||||||
background-color: $colorFormFieldErrorBg;
|
background-color: $colorFormFieldErrorBg;
|
||||||
color: $colorFormFieldErrorFg;
|
color: $colorFormFieldErrorFg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg) {
|
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
|
||||||
@include input-base($bg, $fg);
|
@include input-base();
|
||||||
|
background: $bg;
|
||||||
|
box-shadow: inset $shdw;
|
||||||
|
border: none;
|
||||||
|
color: $fg;
|
||||||
|
outline: none;
|
||||||
|
padding: $inputTextPTopBtm $inputTextPLeftRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin contextArrow() {
|
@mixin contextArrow() {
|
||||||
@ -344,7 +346,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin nice-textarea($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
@mixin nice-textarea($bg: $colorBodyBg, $fg: $colorBodyFg) {
|
||||||
@include input-base($bg, $fg);
|
@include nice-input($bg, $fg);
|
||||||
padding: $interiorMargin;
|
padding: $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +243,24 @@ input[type="number"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span[contenteditable].s-inline-edit {
|
||||||
|
@include trans-prop-nice((padding), 250ms);
|
||||||
|
@include input-base();
|
||||||
|
border: 1px solid transparent;
|
||||||
|
min-width: 20px;
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba($colorBodyFg, 0.2);
|
||||||
|
padding-left: $inputTextPLeftRight;
|
||||||
|
padding-right: $inputTextPLeftRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span[contenteditable].s-inline-edit.s-status-editing {
|
||||||
|
@include nice-input();
|
||||||
|
vertical-align: baseline;
|
||||||
|
padding: 0 $inputTextPLeftRight;
|
||||||
|
}
|
||||||
|
|
||||||
.l-input-sm {
|
.l-input-sm {
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="search"],
|
input[type="search"],
|
||||||
|
@ -129,9 +129,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.s-filter {
|
.s-filter {
|
||||||
input[type="search"] {
|
|
||||||
@include input-base();
|
|
||||||
}
|
|
||||||
.clear-icon,
|
.clear-icon,
|
||||||
.menu-icon,
|
.menu-icon,
|
||||||
&:before {
|
&:before {
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<!-- look at action-button for example -->
|
<!-- look at action-button for example -->
|
||||||
<span class="t-filter l-filter s-filter"
|
<span class="t-filter l-filter"
|
||||||
ng-controller="GetterSetterController">
|
ng-controller="GetterSetterController">
|
||||||
<input type="search"
|
<input type="search"
|
||||||
class="t-filter-input"
|
class="t-filter-input"
|
||||||
|
Reference in New Issue
Block a user