UI: Implement tagging widget

Implement a special form on input text field, for handling tag-based
fields. This will tags as a set of list items, which can be removed
and added to. This is for any comma-delimited field.

Currently, this is only supported on detail view widgets, by adding
'isTag: true' as a new attribute for any tag field. Tags are modified
when clicking the 'edit' action.
This commit is contained in:
bfederle 2012-07-18 11:01:42 -07:00
parent ba7d0ba4f9
commit c69da45217
5 changed files with 182 additions and 0 deletions

View File

@ -8951,6 +8951,89 @@ div.panel.ui-dialog div.list-view div.fixed-header {
background: #DFE1E3;
}
/*Tagger*/
.tagger {
overflow: hidden;
width: 95%;
background: #000000;
}
.tagger input {
overflow: hidden;
position: absolute;
border: 1px solid #B2B2B2;
background: #FFFFFF;
height: 15px;
padding: 2px;
border-left: none;
}
.tagger ul {
height: 19px;
border: 1px solid #B2B2B2;
border-right: none;
display: block;
position: absolute;
top: 2px;
left: 13px;
background: #FFFFFF;
overflow: hidden;
}
.tagger ul li {
background: #DFDFDF 0px 4px;
height: 15px;
padding: 0px 18px 0 7px;
display: inline-block;
float: left;
margin-right: 2px;
/*+border-radius:4px;*/
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
/*+placement:shift 0px 2px;*/
position: relative;
left: 0px;
top: 2px;
}
.tagger ul li span {
width: auto !important;
top: 2px !important;
left: 5px !important;
color: #000000;
}
.tagger ul li span.label {
display: none;
/*+placement:shift 12px 2px;*/
position: relative !important;
left: 12px !important;
top: 2px !important;
}
.tagger ul li span.remove {
width: 15px !important;
overflow: hidden !important;
height: 11px !important;
background: #DFDFDF url(../images/sprites.png) no-repeat -595px -1183px;
display: block;
top: 0px !important;
left: -3px !important;
text-indent: 4px;
padding: 4px 0px 0px 8px;
font-size: 8px;
font-weight: bold;
cursor: pointer;
position: absolute !important;
color: #5B5B5B;
}
.tagger ul li span.remove:hover {
color: #000000;
}
/*VPC / vApps*/
.vpc-chart {
width: 100%;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 175 KiB

View File

@ -1614,6 +1614,7 @@
<script type="text/javascript" src="scripts/ui/widgets/cloudBrowser.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/listView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/detailView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/tagger.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/treeView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/notifications.js?t=<%=now%>"></script>

View File

@ -487,6 +487,10 @@
value: data
}).data('original-value', data)
);
if ($value.closest('tr').data('detail-view-is-tagged')) {
$value.find('input').tagger();
}
}
if (rules && rules.required) {
@ -758,6 +762,10 @@
// Set up validation metadata
$value.data('validation-rules', value.validation);
if (value.isTag) {
$detail.data('detail-view-is-tagged', true);
}
// Set up editable metadata
if(typeof(value.isEditable) == 'function')
$value.data('detail-view-is-editable', value.isEditable());

View File

@ -0,0 +1,90 @@
(function($) {
var elems = {
tagItem: function(title, onRemove) {
var $li = $('<li>');
var $label = $('<span>').addClass('label').html(title);
var $remove = $('<span>').addClass('remove').html('X');
$remove.click(function() {
$li.remove();
if (onRemove) onRemove();
});
$li.append($remove, $label);
return $li;
}
};
$.widget('cloudStack.tagger', {
_init: function() {
var $container = $('<div>').addClass('tagger');
var $tagArea = $('<ul>').addClass('tags');
var $originalInput = this.element;
var $input = $('<input>').attr('type', 'text');
$originalInput.hide();
$originalInput.after($container);
$container.append($tagArea, $input);
// Reposition input to fit tag list
var relayout = function() {
$input.width(
$container.width() - $tagArea.width() - 25
);
$input.css({
left: $tagArea.width(),
top: $tagArea.position().top
});
};
var onRemove = function() {
syncInputs(true);
relayout();
};
// sync original input box and tag list values
//
// flag == true: Sync tags->text
// flag == false: Sync text->tags
var syncInputs = function(flag) {
if (flag) {
$originalInput.val(
$tagArea.find('li').map(function(index, tag) {
return $(tag).find('span.label').html();
}).toArray().join(',')
);
} else if ($originalInput.val()) {
$($originalInput.val().split(',')).map(function(index, tag) {
elems.tagItem(tag, onRemove).appendTo($tagArea);
});
$tagArea.show();
relayout();
}
};
// Tag detection (comma-delimited)
$input.keypress(function(event) {
var tagCode = 44; // Symbol used to indicate a new tag
if (event.which == tagCode) {
$tagArea.show();
elems.tagItem($input.val(), onRemove).appendTo($tagArea);
$input.val('');
relayout();
syncInputs(true);
return false; // Don't allow delineator to be added to input box
}
return true;
});
$tagArea.hide();
relayout();
syncInputs(false);
}
});
}(jQuery));