Merge "Metadata widget multivalue selection support"
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<div class="metadata-tree-item" ng-form="itemForm">
|
||||
<div class="input-group input-group-sm"
|
||||
ng-switch on="item.leaf.type"
|
||||
ng-if="item.leaf.type !== 'array'"
|
||||
ng-class="{'has-error': itemForm.property.$invalid && itemForm.property.$dirty}">
|
||||
<span class="input-group-addon"
|
||||
title="{$ ::item.leaf.name $}"
|
||||
@@ -26,14 +27,6 @@
|
||||
ng-options="op for op in item.leaf.enum"
|
||||
ng-disabled="item.leaf.readonly">
|
||||
</select>
|
||||
<select ng-switch-when="array"
|
||||
name="property"
|
||||
class="form-control"
|
||||
required
|
||||
ng-model="item.leaf.value"
|
||||
ng-options="op for op in item.leaf.items.enum"
|
||||
ng-disabled="item.leaf.readonly">
|
||||
</select>
|
||||
<input ng-switch-when="integer"
|
||||
name="property"
|
||||
type="number"
|
||||
@@ -68,6 +61,50 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="item.leaf.type === 'array'"
|
||||
class="panel panel-default multiselect">
|
||||
<div class="panel-heading">
|
||||
<div ng-click="open()">
|
||||
<span class="fa fa-fw"
|
||||
ng-class="item.leaf.readonly ? '' : opened ? 'fa-chevron-down' : 'fa-chevron-right'">
|
||||
</span>
|
||||
<span ng-bind="::item.leaf.name"></span>
|
||||
<div class="text-right">
|
||||
<a class="btn btn-xs btn-default" ng-click="action()">
|
||||
<i class="fa fa-minus"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body values"
|
||||
ng-class="{disabled: item.leaf.readonly}">
|
||||
<span ng-repeat="val in item.leaf.value">
|
||||
<span class="label label-default"
|
||||
ng-click="remove(val)">
|
||||
<span ng-bind="::val"></span>
|
||||
<span class="fa fa-times" ng-if="!item.leaf.readonly"></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<ul class="list-group options" ng-show="opened">
|
||||
<li class="list-group-item"
|
||||
ng-repeat="val in values"
|
||||
ng-click="add(val)">
|
||||
<span ng-bind="::val"></span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="panel-footer" ng-show="opened">
|
||||
<div class="form-inline clearfix">
|
||||
<div class="form-group pull-right">
|
||||
<label>Operator</label>
|
||||
<select class="form-control input-sm"
|
||||
ng-model="item.leaf.operator"
|
||||
ng-options="val for val in item.leaf.operators">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label label-info">
|
||||
<span ng-bind="::item.breadcrumb()"></span>
|
||||
</div>
|
||||
|
@@ -49,6 +49,8 @@
|
||||
* @property {string} default Property default value
|
||||
* @property {string} type Property type
|
||||
* @property {boolean} readonly Property readonly state
|
||||
* @property {string[]} operators Property available operators when type='array'
|
||||
* @property {string} operator Property operator when type='array'
|
||||
*/
|
||||
function Property(name, json) {
|
||||
this.name = name;
|
||||
@@ -58,7 +60,9 @@
|
||||
this.default = null;
|
||||
this.type = 'string';
|
||||
this.readonly = false;
|
||||
this.operators = ['<in>'];
|
||||
angular.extend(this, json);
|
||||
this.operator = this.operators[0];
|
||||
this.setValue(this.default);
|
||||
}
|
||||
|
||||
@@ -69,14 +73,19 @@
|
||||
*/
|
||||
Property.prototype.setValue = function(value) {
|
||||
if(value === null) {
|
||||
this.value = null;
|
||||
this.value = this.type !== 'array' ? null : [];
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.type) {
|
||||
case 'integer': this.value = parseInt(value); break;
|
||||
case 'number': this.value = parseFloat(value); break;
|
||||
case 'array': this.value = value.replace(/^<in> /, ''); break;
|
||||
case 'array':
|
||||
var data = /^(<.*?>) (.*)$/.exec(value);
|
||||
if(data) {
|
||||
this.operator = data[1];
|
||||
this.value = data[2].split(',');
|
||||
} break;
|
||||
case 'boolean': this.value = parseBool(value); break;
|
||||
default: this.value = value;
|
||||
}
|
||||
@@ -89,7 +98,7 @@
|
||||
*/
|
||||
Property.prototype.getValue = function() {
|
||||
switch (this.type) {
|
||||
case 'array': return '<in> ' + this.value;
|
||||
case 'array': return this.operator + ' ' + this.value.join(',');
|
||||
default: return this.value;
|
||||
}
|
||||
};
|
||||
|
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group" ng-cloak>
|
||||
<ul class="list-group metadata-list-group" ng-cloak>
|
||||
<li class="list-group-item" ng-form="customItemForm">
|
||||
<div class="input-group input-group-sm"
|
||||
ng-class="{'has-error': customItemForm.$invalid && customItemForm.$dirty}">
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group" ng-cloak>
|
||||
<ul class="list-group metadata-list-group" ng-cloak>
|
||||
<li ng-repeat="item in existingList = (tree.flatTree | filter:{$:filterText.existing, added:true, leaf:'!null'} | orderBy:'leaf.name')"
|
||||
ng-class="{'active': tree.selected===item}"
|
||||
ng-class-odd="'dark-stripe'"
|
||||
|
@@ -183,6 +183,46 @@
|
||||
return $scope.text.required;
|
||||
}
|
||||
};
|
||||
|
||||
function remove(array, value) {
|
||||
var index = array.indexOf(value);
|
||||
if (index > -1) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
$scope.opened = false;
|
||||
|
||||
if($scope.item.leaf.type === 'array') {
|
||||
|
||||
$scope.values = $scope.item.leaf.items.enum.filter(function(i) {
|
||||
return $scope.item.leaf.value.indexOf(i) < 0;
|
||||
}).sort();
|
||||
|
||||
if(!$scope.item.leaf.readonly) {
|
||||
$scope.add = function (val) {
|
||||
$scope.item.leaf.value.push(val);
|
||||
$scope.item.leaf.value.sort();
|
||||
remove($scope.values, val);
|
||||
};
|
||||
|
||||
$scope.remove = function (val) {
|
||||
remove($scope.item.leaf.value, val);
|
||||
$scope.values.push(val);
|
||||
$scope.values.sort();
|
||||
if ($scope.item.leaf.value.length === 0) {
|
||||
$scope.opened = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.open = function () {
|
||||
$scope.opened = !$scope.opened;
|
||||
};
|
||||
|
||||
$scope.opened = $scope.item.leaf.value.length === 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.metadata-tree {
|
||||
min-height: 200px;
|
||||
|
||||
.panel .list-group {
|
||||
.metadata-list-group {
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -61,6 +61,56 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
margin: 0;
|
||||
color: $text-color;
|
||||
|
||||
.panel-heading {
|
||||
padding: 4px;
|
||||
|
||||
&>* {
|
||||
display: table;
|
||||
width: 100%;
|
||||
|
||||
&>* {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
padding: 3px 5px 5px;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.values .label {
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.name {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.options {
|
||||
max-height: 180px;
|
||||
overflow-y: auto;
|
||||
|
||||
&>*:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: $input-bg-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
.label-info {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
@@ -49,9 +49,10 @@ describe('hz.widget.metadata-tree module', function() {
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"val-1", "val-2", "val-3"
|
||||
"val-1", "val-2", "val-3", "val-4"
|
||||
]
|
||||
}
|
||||
},
|
||||
"default": "<in> val-2,val-3"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -146,5 +147,43 @@ describe('hz.widget.metadata-tree module', function() {
|
||||
expect($element.find('ul.list-group:last li[ng-repeat].active').scope().item.leaf.name).toBe('custom');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hzMetadataTreeItem directive', function() {
|
||||
var $scope, $element, item;
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
var $compile = $injector.get('$compile');
|
||||
$scope = $injector.get('$rootScope').$new();
|
||||
|
||||
item = new ($injector.get('metadataTreeService').Item)();
|
||||
$scope.item = item.fromProperty('test', namespaces[0].properties['test:A:6']);
|
||||
|
||||
var markup =
|
||||
'<hz-metadata-tree-item item="item" text="text" action=""></hz-metadata-tree-item>';
|
||||
|
||||
$element = angular.element(markup);
|
||||
$compile($element)($scope);
|
||||
$scope.$digest();
|
||||
}));
|
||||
|
||||
it('should have additional methods for array ', function () {
|
||||
expect($element.isolateScope().opened).toBe(false);
|
||||
expect($element.isolateScope().add).toBeDefined();
|
||||
expect($element.isolateScope().remove).toBeDefined();
|
||||
expect($element.isolateScope().open).toBeDefined();
|
||||
});
|
||||
|
||||
it('should add values to array ', function () {
|
||||
$element.find('.options li:last').trigger('click');
|
||||
expect(item.leaf.getValue()).toBe('<in> val-2,val-3,val-4');
|
||||
$element.find('.options li:first').trigger('click');
|
||||
expect(item.leaf.getValue()).toBe('<in> val-1,val-2,val-3,val-4');
|
||||
});
|
||||
|
||||
it('should remove value from array ', function () {
|
||||
$element.find('.values .label:first').trigger('click');
|
||||
expect(item.leaf.getValue()).toBe('<in> val-3');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user