Added the property grouping support to the Inspector

This commit is contained in:
alekseybobkov 2014-06-29 14:28:07 +11:00
parent 43dde06559
commit 478ddabeca
3 changed files with 346 additions and 48 deletions

View File

@ -11406,6 +11406,29 @@ html.cssanimations .fancy-layout .form-tabless-fields .loading-indicator-contain
-moz-border-radius: 0 0 2px 0;
border-radius: 0 0 2px 0;
}
.inspector-fields tr.group {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.inspector-fields tr.group th {
background: #e0e4e5;
font-weight: 600;
cursor: pointer;
}
.inspector-fields tr.collapsed {
display: none;
}
.inspector-fields tr.expanded {
display: table-row;
}
.inspector-fields.has-groups th {
padding-left: 20px;
}
.inspector-fields.has-groups tr.grouped th {
padding-left: 35px;
}
.inspector-fields td {
font-weight: 300;
border-left: 1px solid #f2f2f2;
@ -11447,16 +11470,18 @@ html.cssanimations .fancy-layout .form-tabless-fields .loading-indicator-contain
}
.inspector-fields th > div {
position: relative;
}
.inspector-fields th > div > div {
white-space: nowrap;
padding-right: 10px;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
}
.inspector-fields th > div span.info {
.inspector-fields th > div > div span.info {
display: inline-block;
position: absolute;
right: -6px;
right: -1px;
top: 3px;
font-size: 14px;
width: 10px;
@ -11465,10 +11490,57 @@ html.cssanimations .fancy-layout .form-tabless-fields .loading-indicator-contain
opacity: 0.4;
filter: alpha(opacity=40);
}
.inspector-fields th > div span.info:hover {
.inspector-fields th > div > div span.info:before {
margin-left: 3px;
}
.inspector-fields th > div > div span.info:hover {
opacity: 1;
filter: alpha(opacity=100);
}
.inspector-fields th > div a.expandControl {
display: block;
position: absolute;
width: 12px;
height: 12px;
left: -15px;
top: 2px;
text-indent: -100000em;
}
.inspector-fields th > div a.expandControl span {
position: absolute;
display: inline-block;
left: 0;
top: 0;
width: 12px;
height: 12px;
}
.inspector-fields th > div a.expandControl span:after {
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
text-decoration: inherit;
-webkit-font-smoothing: antialiased;
*margin-right: .3em;
content: "\f105";
position: absolute;
left: 4px;
top: -2px;
width: 12px;
height: 12px;
font-size: 13px;
color: #333333;
text-indent: 0;
}
.inspector-fields th > div a.expandControl.expanded span:after {
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
text-decoration: inherit;
-webkit-font-smoothing: antialiased;
*margin-right: .3em;
content: "\f107";
left: 2px;
}
.inspector-fields input[type=text] {
display: block;
width: 100%;
@ -11560,9 +11632,9 @@ div.control-popover.control-inspector > div:after {
top: 5px;
color: #95a5a6;
}
.select2-drop.ocInspectorDropdown .select2-search .select2-input {
.select2-drop.ocInspectorDropdown .select2-search input.select2-input {
min-height: 26px;
background: transparent;
background: transparent!important;
padding-left: 12px;
padding-right: 12px;
}

View File

@ -21,6 +21,7 @@
* Each element in the array is an object with the following properties:
* - property
* - title
* - group (optional)
* - type (currently supported types are: string, checkbox, dropdown)
* - description (optional)
* - validationPattern (regex pattern for for validating the value, supported by the text editor)
@ -84,42 +85,47 @@
'an hidden input element with the data-inspector-values property.')
}
Inspector.prototype.getPopoverTemplate = function() {
return ' \
<div class="popover-head"> \
<h3>{{title}}</h3> \
{{#description}} \
<p>{{description}}</p> \
{{/description}} \
<button type="button" class="close" \
data-dismiss="popover" \
aria-hidden="true">&times;</button> \
</div> \
<form> \
<table class="inspector-fields"> \
{{#properties}} \
<tr id="{{#propFormat}}{{property}}{{/propFormat}}"> \
<th><div title="{{title}}"> \
{{title}} \
{{#info}}{{/info}} \
</div></th> \
{{#editor}}{{/editor}} \
</tr> \
{{/properties}} \
</table> \
<form> \
Inspector.prototype.getPopoverTemplate = function() {
return ' \
<div class="popover-head"> \
<h3>{{title}}</h3> \
{{#description}} \
<p>{{description}}</p> \
{{/description}} \
<button type="button" class="close" \
data-dismiss="popover" \
aria-hidden="true">&times;</button> \
</div> \
<form> \
<table class="inspector-fields {{#tableClass}}{{/tableClass}}"> \
{{#properties}} \
<tr id="{{#propFormat}}{{property}}{{/propFormat}}" \
{{#dataGroupIndex}}{{/dataGroupIndex}} \
class="{{#cellClass}}{{/cellClass}}"> \
<th {{#colspan}}{{/colspan}}><div><div class="title-element" title="{{title}}"> \
{{#expandControl}}{{/expandControl}} \
{{title}} \
{{#info}}{{/info}} \
</div></div></th> \
{{#editor}}{{/editor}} \
</tr> \
{{/properties}} \
</table> \
<form> \
'
}
Inspector.prototype.init = function() {
var self = this,
fieldsConfig = this.preprocessConfig(),
data = {
title: this.$el.data('inspector-title'),
description: this.$el.data('inspector-description'),
properties: this.config,
properties: fieldsConfig.properties,
editor: function() {
return function(text, render) {
return self.renderEditor(this, render)
if (this.itemType == 'property')
return self.renderEditor(this, render)
}
},
info: function() {
@ -132,6 +138,41 @@
return function(text, render) {
return 'prop-'+render(text).replace('.', '-')
}
},
colspan: function() {
return function(text, render) {
return this.itemType == 'group' ? 'colspan="2"' : null
}
},
tableClass: function() {
return function(text, render) {
return fieldsConfig.hasGroups ? 'has-groups' : null
}
},
cellClass: function() {
return function(text, render) {
var result = this.itemType + ((this.itemType == 'property' && this.groupIndex !== undefined) ? ' grouped' : '')
if (this.itemType == 'property' && this.groupIndex !== undefined)
result += self.groupExpanded(this.group) ? ' expanded' : ' collapsed'
return result
}
},
expandControl: function() {
return function(text, render) {
if (this.itemType == 'group') {
this.itemStatus = self.groupExpanded(this.title) ? 'expanded' : ''
return render('<a class="expandControl {{itemStatus}}" href="javascript:;" data-group-index="{{groupIndex}}"><span>Expand/collapse</span></a>', this)
}
}
},
dataGroupIndex: function() {
return function(text, render) {
return this.groupIndex !== undefined && this.itemType == 'property' ? render('data-group-index={{groupIndex}}', this) : ''
}
}
}
@ -190,6 +231,12 @@
})
$('[data-toggle=tooltip]', self.$el.data('oc.popover').$container).tooltip({placement: 'auto right', container: 'body'})
var $container = self.$el.data('oc.popover').$container
$container.on('click', 'tr.group', function(){
self.toggleGroup($('a.expandControl', this), $container)
return false
})
}
var e = $.Event('showing.oc.inspector')
@ -201,6 +248,118 @@
displayPopover()
}
// Creates group nodes in the property set
//
Inspector.prototype.preprocessConfig = function() {
var fields = [],
result = {
hasGroups: false,
properties: []
},
groupIndex = 0
function findGroup(title) {
var groups = $.grep(fields, function(item) {
return item.itemType !== undefined && item.itemType == 'group' && item.title == title
})
if (groups.length > 0)
return groups[0]
return null
}
$.each(this.config, function() {
this.itemType = 'property'
if (this.group === undefined)
fields.push(this)
else {
var group = findGroup(this.group)
if (!group) {
group = {
itemType: 'group',
title: this.group,
properties: [],
groupIndex: groupIndex
}
groupIndex++
fields.push(group)
}
this.groupIndex = group.groupIndex
group.properties.push(this)
}
})
$.each(fields, function() {
result.properties.push(this)
if (this.itemType == 'group') {
result.hasGroups = true
$.each(this.properties, function() {
result.properties.push(this)
})
delete this.properties
}
})
return result
}
Inspector.prototype.toggleGroup = function(link, $container) {
var $link = $(link),
groupIndex = $link.data('group-index'),
propertyRows = $('tr[data-group-index='+groupIndex+']', $container),
duration = Math.round(100 / propertyRows.length),
collapse = true,
statuses = this.loadGroupExpandedStatuses(),
title = $('div.title-element', $link.closest('tr')).attr('title')
if ($link.hasClass('expanded')) {
$link.removeClass('expanded')
statuses[title] = false
} else {
$link.addClass('expanded')
collapse = false
statuses[title] = true
}
propertyRows.each(function(index){
var self = $(this)
setTimeout(function(){
self.toggleClass('collapsed', collapse)
self.toggleClass('expanded', !collapse)
}, index*duration)
})
this.writeGroupExpandedStatuses(statuses)
}
Inspector.prototype.loadGroupExpandedStatuses = function() {
var statuses = this.$el.data('inspector-group-statuses')
return statuses !== undefined ? JSON.parse(statuses) : {}
}
Inspector.prototype.writeGroupExpandedStatuses = function(statuses) {
this.$el.data('inspector-group-statuses', JSON.stringify(statuses))
}
Inspector.prototype.groupExpanded = function(title) {
var statuses = this.loadGroupExpandedStatuses()
if (statuses[title] !== undefined)
return statuses[title]
return false
}
Inspector.prototype.initProperties = function() {
var propertyValuesStr = $.trim(this.propertyValuesField.val())

View File

@ -23,6 +23,31 @@
}
}
tr.group {
.user-select(none);
th {
background: #e0e4e5;
font-weight: 600;
cursor: pointer;
}
}
tr {
&.collapsed {display: none;}
&.expanded {display: table-row;}
}
&.has-groups {
th {
padding-left: 20px;
}
tr.grouped th {
padding-left: 35px;
}
}
td {
font-weight: 300;
border-left: 1px solid @color-inspector-bg;
@ -72,24 +97,66 @@
> div {
position: relative;
white-space: nowrap;
padding-right: 10px;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
span.info {
display: inline-block;
> div {
white-space: nowrap;
padding-right: 10px;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
span.info {
display: inline-block;
position: absolute;
right: -1px;
top: 3px;
font-size: 14px;
width: 10px;
height: 12px;
line-height: 80%;
.opacity(0.4);
&:before {
margin-left: 3px;
}
&:hover {
.opacity(1);
}
}
}
a.expandControl {
display: block;
position: absolute;
right: -6px;
top: 3px;
font-size: 14px;
width: 10px;
width: 12px;
height: 12px;
line-height: 80%;
.opacity(0.4);
&:hover {
.opacity(1);
left: -15px;
top: 2px;
text-indent: -100000em;
span {
position: absolute;
display: inline-block;
left: 0;
top: 0;
width: 12px;
height: 12px;
&:after {
.icon(@angle-right);
position: absolute;
left: 4px;
top: -2px;
width: 12px;
height: 12px;
font-size: 13px;
color: #333333;
text-indent: 0;
}
}
&.expanded span:after {
.icon(@angle-down);
left: 2px;
}
}
}
@ -210,9 +277,9 @@ div.control-popover {
color: #95a5a6;
}
.select2-input {
input.select2-input {
min-height: 26px;
background: transparent;
background: transparent!important;
padding-left: 12px;
padding-right: 12px;
}