Added the object list Inspector editor.
This commit is contained in:
parent
83b4994d61
commit
e54352b62e
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
$form.request('onInspectableGetOptions', {
|
||||
data: data,
|
||||
}).done(function optionsRequestDoneClosure(data) {
|
||||
}).done(function dropdownOptionsRequestDoneClosure(data) {
|
||||
self.optionsRequestDone(data, currentValue, true)
|
||||
}).always(
|
||||
this.proxy(this.hideLoadingIndicator)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* Inspector object list editor class.
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
|
||||
var Base = $.oc.inspector.propertyEditors.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
var ObjectListEditor = function(inspector, propertyDefinition, containerCell) {
|
||||
this.currentRowInspector = null
|
||||
this.popup = null
|
||||
|
||||
if (propertyDefinition.titleProperty === undefined) {
|
||||
throw new Error('The titleProperty property should be specified in the objectList editor configuration. Property: ' + propertyDefinition.property)
|
||||
}
|
||||
|
||||
if (propertyDefinition.itemProperties === undefined) {
|
||||
throw new Error('The itemProperties property should be specified in the objectList editor configuration. Property: ' + propertyDefinition.property)
|
||||
}
|
||||
|
||||
Base.call(this, inspector, propertyDefinition, containerCell)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype = Object.create(BaseProto)
|
||||
ObjectListEditor.prototype.constructor = Base
|
||||
|
||||
ObjectListEditor.prototype.dispose = function() {
|
||||
this.unregisterHandlers()
|
||||
this.removeControls()
|
||||
|
||||
this.currentRowInspector = null
|
||||
this.popup = null
|
||||
|
||||
BaseProto.dispose.call(this)
|
||||
}
|
||||
|
||||
//
|
||||
// Building
|
||||
//
|
||||
|
||||
ObjectListEditor.prototype.build = function() {
|
||||
var link = document.createElement('a')
|
||||
|
||||
$.oc.foundation.element.addClass(link, 'trigger')
|
||||
link.setAttribute('href', '#')
|
||||
this.setLinkText(link)
|
||||
|
||||
$.oc.foundation.element.addClass(this.containerCell, 'trigger-cell')
|
||||
|
||||
this.containerCell.appendChild(link)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.setLinkText = function(link, value) {
|
||||
var value = value !== undefined ? value
|
||||
: this.inspector.getPropertyValue(this.propertyDefinition.property)
|
||||
|
||||
if (value === undefined) {
|
||||
var placeholder = this.propertyDefinition.placeholder
|
||||
|
||||
if (placeholder !== undefined) {
|
||||
$.oc.foundation.element.addClass(link, 'placeholder')
|
||||
link.textContent = placeholder
|
||||
}
|
||||
else {
|
||||
link.textContent = 'Items: 0'
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (value.length === undefined) {
|
||||
throw new Error('Object list value an array. Property: ' + this.propertyDefinition.property)
|
||||
}
|
||||
|
||||
$.oc.foundation.element.removeClass(link, 'placeholder')
|
||||
link.textContent = 'Items: ' + value.length
|
||||
}
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.getPopupContent = function() {
|
||||
return '<form> \
|
||||
<div class="modal-header"> \
|
||||
<button type="button" class="close" data-dismiss="popup">×</button> \
|
||||
<h4 class="modal-title">{{property}}</h4> \
|
||||
</div> \
|
||||
<div> \
|
||||
<div class="layout inspector-columns-editor"> \
|
||||
<div class="layout-row"> \
|
||||
<div class="layout-cell"> \
|
||||
<div class="layout-relative"> \
|
||||
<div class="layout"> \
|
||||
<div class="layout-row min-size"> \
|
||||
<div class="control-toolbar toolbar-padded"> \
|
||||
<div class="toolbar-item"> \
|
||||
<div class="btn-group"> \
|
||||
<button type="button" class="btn btn-primary \
|
||||
oc-icon-plus" \
|
||||
data-cmd="create-item">Add</button> \
|
||||
<button type="button" class="btn btn-default \
|
||||
empty oc-icon-trash-o" \
|
||||
data-cmd="delete-item"></button> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class="layout-row"> \
|
||||
<div class="layout-cell"> \
|
||||
<div class="layout-relative"> \
|
||||
<div class="layout-absolute"> \
|
||||
<div class="control-scrollpad" \
|
||||
data-control="scrollpad"> \
|
||||
<div class="scroll-wrapper"> \
|
||||
<table class="table data \
|
||||
no-offset-bottom \
|
||||
inspector-table-list"> \
|
||||
</table> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class="layout-cell"> \
|
||||
<div class="layout-relative"> \
|
||||
<div class="layout-absolute"> \
|
||||
<div class="control-scrollpad" data-control="scrollpad"> \
|
||||
<div class="scroll-wrapper inspector-wrapper"> \
|
||||
<div data-inspector-container> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class="modal-footer"> \
|
||||
<button type="submit" class="btn btn-primary">OK</button> \
|
||||
<button type="button" class="btn btn-default"data-dismiss="popup">Cancel</button> \
|
||||
</div> \
|
||||
</form>'
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.buildPopupContents = function(popup) {
|
||||
this.buildItemsTable(popup)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.buildItemsTable = function(popup) {
|
||||
var table = popup.querySelector('table'),
|
||||
tbody = document.createElement('tbody'),
|
||||
items = this.inspector.getPropertyValue(this.propertyDefinition.property),
|
||||
titleProperty = this.propertyDefinition.titleProperty
|
||||
|
||||
if (items === undefined || items.length === 0) {
|
||||
var row = this.buildEmptyRow()
|
||||
|
||||
tbody.appendChild(row)
|
||||
}
|
||||
else {
|
||||
var firstRow = undefined
|
||||
|
||||
for (var i = 0, len = items.length; i < len; i++) {
|
||||
var item = items[i],
|
||||
itemText = item[titleProperty],
|
||||
row = this.buildTableRow(itemText, 'rowlink')
|
||||
|
||||
row.setAttribute('data-inspector-values', JSON.stringify(item))
|
||||
tbody.appendChild(row)
|
||||
|
||||
if (firstRow === undefined) {
|
||||
firstRow = row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.appendChild(tbody)
|
||||
|
||||
if (firstRow !== undefined) {
|
||||
this.selectRow(firstRow)
|
||||
}
|
||||
|
||||
this.updateScrollpads()
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.buildEmptyRow = function() {
|
||||
return this.buildTableRow('No items found', 'no-data', 'nolink')
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.removeEmptyRow = function() {
|
||||
var tbody = this.getTableBody(),
|
||||
row = tbody.querySelector('tr.no-data')
|
||||
|
||||
if (row) {
|
||||
tbody.removeChild(row)
|
||||
}
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.buildTableRow = function(text, rowClass, cellClass) {
|
||||
var row = document.createElement('tr'),
|
||||
cell = document.createElement('td')
|
||||
|
||||
cell.textContent = text
|
||||
|
||||
if (rowClass !== undefined) {
|
||||
$.oc.foundation.element.addClass(row, rowClass)
|
||||
}
|
||||
|
||||
if (cellClass !== undefined) {
|
||||
$.oc.foundation.element.addClass(cell, cellClass)
|
||||
}
|
||||
|
||||
row.appendChild(cell)
|
||||
return row
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.updateScrollpads = function() {
|
||||
$('.control-scrollpad', this.popup).scrollpad('update')
|
||||
}
|
||||
|
||||
//
|
||||
// Built-in Inspector management
|
||||
//
|
||||
|
||||
ObjectListEditor.prototype.selectRow = function(row) {
|
||||
var tbody = row.parentNode,
|
||||
inspectorContainer = this.getInspectorContainer(),
|
||||
selectedRow = this.getSelectedRow()
|
||||
|
||||
if (selectedRow) {
|
||||
// TODO: validation of the currently existing Inspector is required
|
||||
this.applyDataToRow(selectedRow)
|
||||
$.oc.foundation.element.removeClass(selectedRow, 'active')
|
||||
}
|
||||
|
||||
this.disposeInspector()
|
||||
|
||||
$.oc.foundation.element.addClass(row, 'active')
|
||||
|
||||
this.createInspectorForRow(row, inspectorContainer)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.createInspectorForRow = function(row, inspectorContainer) {
|
||||
var dataStr = row.getAttribute('data-inspector-values')
|
||||
|
||||
if (dataStr === undefined || typeof dataStr !== 'string') {
|
||||
throw new Error('Values not found for the selected row.')
|
||||
}
|
||||
|
||||
var properties = this.propertyDefinition.itemProperties,
|
||||
values = $.parseJSON(dataStr),
|
||||
options = {
|
||||
enableExternalParameterEditor: false,
|
||||
onChange: this.proxy(this.onInspectorDataChange)
|
||||
}
|
||||
|
||||
this.currentRowInspector = new $.oc.inspector.surface(inspectorContainer, properties, values,
|
||||
$.oc.inspector.helpers.generateElementUniqueId(inspectorContainer), options)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.disposeInspector = function() {
|
||||
$.oc.foundation.controlUtils.disposeControls(this.popup)
|
||||
this.currentRowInspector = null
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.applyDataToRow = function(row) {
|
||||
if (this.currentRowInspector === null) {
|
||||
return
|
||||
}
|
||||
|
||||
var data = this.currentRowInspector.getValues()
|
||||
row.setAttribute('data-inspector-values', JSON.stringify(data))
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.updateRowText = function(property, value) {
|
||||
var selectedRow = this.getSelectedRow()
|
||||
|
||||
if (!selectedRow) {
|
||||
throw new Exception('A row is not found for the updated data')
|
||||
}
|
||||
|
||||
if (property !== this.propertyDefinition.titleProperty) {
|
||||
return
|
||||
}
|
||||
|
||||
selectedRow.firstChild.textContent = value
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.getSelectedRow = function() {
|
||||
if (!this.popup) {
|
||||
throw new Error('Trying to get selected row without a popup reference.')
|
||||
}
|
||||
|
||||
var rows = this.getTableBody().children
|
||||
|
||||
for (var i = 0, len = rows.length; i < len; i++) {
|
||||
if ($.oc.foundation.element.hasClass(rows[i], 'active')) {
|
||||
return rows[i]
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.createItem = function() {
|
||||
var selectedRow = this.getSelectedRow()
|
||||
|
||||
if (selectedRow) {
|
||||
// TODO: validation of the currently existing Inspector is required
|
||||
this.applyDataToRow(selectedRow)
|
||||
$.oc.foundation.element.removeClass(selectedRow, 'active')
|
||||
}
|
||||
|
||||
this.disposeInspector()
|
||||
|
||||
var title = 'New item',
|
||||
row = this.buildTableRow(title, 'rowlink active'),
|
||||
tbody = this.getTableBody(),
|
||||
data = {}
|
||||
|
||||
data[this.propertyDefinition.titleProperty] = title
|
||||
|
||||
row.setAttribute('data-inspector-values', JSON.stringify(data))
|
||||
tbody.appendChild(row)
|
||||
|
||||
this.selectRow(row)
|
||||
|
||||
this.removeEmptyRow()
|
||||
this.updateScrollpads()
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.deleteItem = function() {
|
||||
var selectedRow = this.getSelectedRow()
|
||||
|
||||
if (!selectedRow) {
|
||||
return
|
||||
}
|
||||
|
||||
var nextRow = selectedRow.nextElementSibling,
|
||||
prevRow = selectedRow.previousElementSibling,
|
||||
tbody = this.getTableBody()
|
||||
|
||||
this.disposeInspector()
|
||||
tbody.removeChild(selectedRow)
|
||||
|
||||
var newSelectedRow = nextRow ? nextRow : prevRow
|
||||
|
||||
if (newSelectedRow) {
|
||||
this.selectRow(newSelectedRow)
|
||||
} else {
|
||||
tbody.appendChild(this.buildEmptyRow())
|
||||
}
|
||||
|
||||
this.updateScrollpads()
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.applyDataToParentInspector = function() {
|
||||
var selectedRow = this.getSelectedRow(),
|
||||
tbody = this.getTableBody(),
|
||||
dataRows = tbody.querySelectorAll('tr[data-inspector-values]'),
|
||||
link = this.getLink(),
|
||||
result = []
|
||||
|
||||
if (selectedRow) {
|
||||
// TODO: validation of the currently existing Inspector is required
|
||||
this.applyDataToRow(selectedRow)
|
||||
}
|
||||
|
||||
for (var i = 0, len = dataRows.length; i < len; i++) {
|
||||
var dataRow = dataRows[i]
|
||||
|
||||
result.push($.parseJSON(dataRow.getAttribute('data-inspector-values')))
|
||||
}
|
||||
|
||||
this.inspector.setPropertyValue(this.propertyDefinition.property, result)
|
||||
this.setLinkText(link, result)
|
||||
|
||||
$(link).popup('hide')
|
||||
return false
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
ObjectListEditor.prototype.getLink = function() {
|
||||
return this.containerCell.querySelector('a.trigger')
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.getPopupFormElement = function() {
|
||||
var form = this.popup.querySelector('form')
|
||||
|
||||
if (!form) {
|
||||
throw new Error('Cannot find form element in the popup window.')
|
||||
}
|
||||
|
||||
return form
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.getInspectorContainer = function() {
|
||||
return this.popup.querySelector('div[data-inspector-container]')
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.getTableBody = function() {
|
||||
return this.popup.querySelector('table.inspector-table-list tbody')
|
||||
}
|
||||
|
||||
//
|
||||
// Event handlers
|
||||
//
|
||||
|
||||
ObjectListEditor.prototype.registerHandlers = function() {
|
||||
var link = this.getLink(),
|
||||
$link = $(link)
|
||||
|
||||
link.addEventListener('click', this.proxy(this.onTriggerClick))
|
||||
$link.on('shown.oc.popup', this.proxy(this.onPopupShown))
|
||||
$link.on('hidden.oc.popup', this.proxy(this.onPopupHidden))
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.unregisterHandlers = function() {
|
||||
var link = this.getLink(),
|
||||
$link = $(link)
|
||||
|
||||
link.removeEventListener('click', this.proxy(this.onTriggerClick))
|
||||
$link.off('shown.oc.popup', this.proxy(this.onPopupShown))
|
||||
$link.off('hidden.oc.popup', this.proxy(this.onPopupHidden))
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onTriggerClick = function(ev) {
|
||||
$.oc.foundation.event.stop(ev)
|
||||
|
||||
var content = this.getPopupContent()
|
||||
|
||||
content = content.replace('{{property}}', this.propertyDefinition.title)
|
||||
|
||||
$(ev.target).popup({
|
||||
content: content
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onPopupShown = function(ev, link, popup) {
|
||||
$(popup).on('submit.inspector', 'form', this.proxy(this.onSubmit))
|
||||
$(popup).on('click', 'tr.rowlink', this.proxy(this.onRowClick))
|
||||
$(popup).on('click.inspector', '[data-cmd]', this.proxy(this.onCommand))
|
||||
|
||||
this.popup = popup.get(0)
|
||||
|
||||
this.buildPopupContents(this.popup)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onPopupHidden = function(ev, link, popup) {
|
||||
$(popup).off('.inspector', this.proxy(this.onSubmit))
|
||||
$(popup).off('click', 'tr.rowlink', this.proxy(this.onRowClick))
|
||||
$(popup).off('click.inspector', '[data-cmd]', this.proxy(this.onCommand))
|
||||
|
||||
this.disposeInspector()
|
||||
this.popup = null
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onSubmit = function(ev) {
|
||||
this.applyDataToParentInspector()
|
||||
|
||||
ev.preventDefault()
|
||||
return false
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onRowClick = function(ev) {
|
||||
this.selectRow(ev.currentTarget)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onInspectorDataChange = function(property, value) {
|
||||
this.updateRowText(property, value)
|
||||
}
|
||||
|
||||
ObjectListEditor.prototype.onCommand = function(ev) {
|
||||
var command = ev.currentTarget.getAttribute('data-cmd')
|
||||
|
||||
switch (command) {
|
||||
case 'create-item' :
|
||||
this.createItem()
|
||||
break;
|
||||
case 'delete-item' :
|
||||
this.deleteItem()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Disposing
|
||||
//
|
||||
|
||||
ObjectListEditor.prototype.removeControls = function() {
|
||||
if (this.popup) {
|
||||
this.disposeInspector(this.popup)
|
||||
}
|
||||
}
|
||||
|
||||
$.oc.inspector.propertyEditors.objectList = ObjectListEditor
|
||||
}(window.jQuery);
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
var SetEditor = function(inspector, propertyDefinition, containerCell) {
|
||||
this.editors = []
|
||||
this.loadedItems = null
|
||||
|
||||
Base.call(this, inspector, propertyDefinition, containerCell)
|
||||
}
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
|
||||
SetEditor.prototype.dispose = function() {
|
||||
this.disposeEditors()
|
||||
this.disposeControls()
|
||||
|
||||
this.editors = null
|
||||
|
||||
|
|
@ -30,10 +32,6 @@
|
|||
//
|
||||
|
||||
SetEditor.prototype.build = function() {
|
||||
if (!this.propertyDefinition.items) {
|
||||
throw new Error('The items are not defined for the set-typed property "' + this.propertyDefinition.property + '"')
|
||||
}
|
||||
|
||||
var link = document.createElement('a')
|
||||
|
||||
$.oc.foundation.element.addClass(link, 'trigger')
|
||||
|
|
@ -41,10 +39,19 @@
|
|||
link.setAttribute('data-group-index', this.getGroupIndex())
|
||||
this.setLinkText(link)
|
||||
|
||||
$.oc.foundation.element.addClass(this.containerCell, 'set')
|
||||
$.oc.foundation.element.addClass(this.containerCell, 'trigger-cell')
|
||||
|
||||
this.containerCell.appendChild(link)
|
||||
|
||||
if (this.propertyDefinition.items !== undefined) {
|
||||
this.loadStaticItems()
|
||||
}
|
||||
else {
|
||||
this.loadDynamicItems()
|
||||
}
|
||||
}
|
||||
|
||||
SetEditor.prototype.loadStaticItems = function() {
|
||||
for (var itemValue in this.propertyDefinition.items) {
|
||||
this.buildItemEditor(itemValue, this.propertyDefinition.items[itemValue])
|
||||
}
|
||||
|
|
@ -52,14 +59,14 @@
|
|||
|
||||
SetEditor.prototype.setLinkText = function(link, value) {
|
||||
var value = value !== undefined ? value
|
||||
: this.inspector.getPropertyValue(this.propertyDefinition.property),
|
||||
text = '[]'
|
||||
: this.getNormalizedValue(),
|
||||
text = '[ ]'
|
||||
|
||||
if (value === undefined) {
|
||||
value = this.propertyDefinition.default
|
||||
}
|
||||
|
||||
if (value !== undefined && value.length !== undefined && value.length > 0) {
|
||||
if (value !== undefined && value.length !== undefined && value.length > 0 && typeof value !== 'string') {
|
||||
var textValues = []
|
||||
for (var i = 0, len = value.length; i < len; i++) {
|
||||
textValues.push(this.valueToText(value[i]))
|
||||
|
|
@ -108,7 +115,48 @@
|
|||
|
||||
return this.propertyDefinition.default.indexOf(value) > -1
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Dynamic items
|
||||
//
|
||||
|
||||
SetEditor.prototype.showLoadingIndicator = function() {
|
||||
$(this.getLink()).loadIndicator()
|
||||
}
|
||||
|
||||
SetEditor.prototype.hideLoadingIndicator = function() {
|
||||
$(this.getLink()).loadIndicator('hide')
|
||||
}
|
||||
|
||||
SetEditor.prototype.loadDynamicItems = function() {
|
||||
var link = this.getLink(),
|
||||
data = this.inspector.getValues(),
|
||||
$form = $(link).closest('form')
|
||||
|
||||
$.oc.foundation.element.addClass(link, 'loading-indicator-container size-small')
|
||||
this.showLoadingIndicator()
|
||||
|
||||
$form.request('onInspectableGetOptions', {
|
||||
data: data,
|
||||
})
|
||||
.done(this.proxy(this.itemsRequestDone))
|
||||
.always(this.proxy(this.hideLoadingIndicator))
|
||||
}
|
||||
|
||||
SetEditor.prototype.itemsRequestDone = function(data, currentValue, initialization) {
|
||||
this.loadedItems = {}
|
||||
|
||||
if (data.options) {
|
||||
for (var i = 0, len = data.options.length; i < len; i++) {
|
||||
this.buildItemEditor(data.options[i].value, data.options[i].title)
|
||||
|
||||
this.loadedItems[data.options[i].value] = data.options[i].title
|
||||
}
|
||||
}
|
||||
|
||||
this.setLinkText(this.getLink())
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
|
@ -117,20 +165,67 @@
|
|||
return this.containerCell.querySelector('a.trigger')
|
||||
}
|
||||
|
||||
SetEditor.prototype.getItemsSource = function() {
|
||||
if (this.propertyDefinition.items !== undefined) {
|
||||
return this.propertyDefinition.items
|
||||
}
|
||||
|
||||
return this.loadedItems
|
||||
}
|
||||
|
||||
SetEditor.prototype.valueToText = function(value) {
|
||||
if (!this.propertyDefinition.items) {
|
||||
var source = this.getItemsSource()
|
||||
|
||||
if (!source) {
|
||||
return value
|
||||
}
|
||||
|
||||
for (var itemValue in this.propertyDefinition.items) {
|
||||
for (var itemValue in source) {
|
||||
if (itemValue == value) {
|
||||
return this.propertyDefinition.items[itemValue]
|
||||
return source[itemValue]
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes items that don't exist in the defined items from
|
||||
* the value.
|
||||
*/
|
||||
SetEditor.prototype.cleanUpValue = function(value) {
|
||||
if (!value) {
|
||||
return value
|
||||
}
|
||||
|
||||
var result = [],
|
||||
source = this.getItemsSource()
|
||||
|
||||
for (var i = 0, len = value.length; i < len; i++) {
|
||||
var currentValue = value[i]
|
||||
|
||||
if (source[currentValue] !== undefined) {
|
||||
result.push(currentValue)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
SetEditor.prototype.getNormalizedValue = function() {
|
||||
var value = this.inspector.getPropertyValue(this.propertyDefinition.property)
|
||||
|
||||
if (value === undefined) {
|
||||
return value
|
||||
}
|
||||
|
||||
if (value.length === undefined || typeof value === 'string') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
//
|
||||
// Editor API methods
|
||||
//
|
||||
|
|
@ -159,7 +254,7 @@
|
|||
// current set value is [create] and checkboxValue is "create".
|
||||
// The result of the method will be TRUE.
|
||||
|
||||
var value = this.inspector.getPropertyValue(this.propertyDefinition.property)
|
||||
var value = this.getNormalizedValue()
|
||||
|
||||
if (value === undefined) {
|
||||
return this.isCheckedByDefault(checkboxValue)
|
||||
|
|
@ -173,7 +268,7 @@
|
|||
}
|
||||
|
||||
SetEditor.prototype.setPropertyValue = function(checkboxValue, isChecked) {
|
||||
var currentValue = this.inspector.getPropertyValue(this.propertyDefinition.property)
|
||||
var currentValue = this.getNormalizedValue()
|
||||
|
||||
if (currentValue === undefined) {
|
||||
currentValue = this.propertyDefinition.default
|
||||
|
|
@ -195,7 +290,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
this.inspector.setPropertyValue(this.propertyDefinition.property, currentValue)
|
||||
this.inspector.setPropertyValue(this.propertyDefinition.property, this.cleanUpValue(currentValue))
|
||||
this.setLinkText(this.getLink())
|
||||
}
|
||||
|
||||
|
|
@ -215,5 +310,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
SetEditor.prototype.disposeControls = function() {
|
||||
var link = this.getLink()
|
||||
|
||||
if (this.propertyDefinition.items === undefined) {
|
||||
$(link).loadIndicator('destroy')
|
||||
}
|
||||
|
||||
link.parentNode.removeChild(link)
|
||||
}
|
||||
|
||||
$.oc.inspector.propertyEditors.set = SetEditor
|
||||
}(window.jQuery);
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
link.setAttribute('href', '#')
|
||||
this.setLinkText(link)
|
||||
|
||||
$.oc.foundation.element.addClass(this.containerCell, 'text-multiline')
|
||||
$.oc.foundation.element.addClass(this.containerCell, 'trigger-cell')
|
||||
|
||||
this.containerCell.appendChild(link)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
this.externalParameterEditors = null
|
||||
this.values = null
|
||||
this.originalValues = null
|
||||
this.options.onChange = null
|
||||
|
||||
BaseProto.dispose.call(this)
|
||||
}
|
||||
|
|
@ -230,16 +231,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
Surface.prototype.applyGroupIndexAttribute = function(property, row) {
|
||||
if (property.groupIndex !== undefined && property.itemType == 'property') {
|
||||
row.setAttribute('data-group-index', property.groupIndex)
|
||||
}
|
||||
}
|
||||
|
||||
Surface.prototype.getRowCssClass = function(property) {
|
||||
var result = property.itemType
|
||||
|
||||
if (property.itemType == 'property' && property.groupIndex !== undefined) {
|
||||
// The property.groupedControl flag doesn't allow to collapse the grouped control row itself.
|
||||
if (property.itemType == 'property' && property.groupIndex !== undefined && !property.groupedControl) {
|
||||
result += ' grouped'
|
||||
result += this.isGroupExpanded(property.group) ? ' expanded' : ' collapsed'
|
||||
}
|
||||
|
|
@ -315,6 +311,12 @@
|
|||
// Field grouping
|
||||
//
|
||||
|
||||
Surface.prototype.applyGroupIndexAttribute = function(property, row) {
|
||||
if (property.groupIndex !== undefined && property.itemType == 'property' && !property.groupedControl) {
|
||||
row.setAttribute('data-group-index', property.groupIndex)
|
||||
}
|
||||
}
|
||||
|
||||
Surface.prototype.isGroupExpanded = function(group) {
|
||||
var statuses = this.loadGroupStatuses()
|
||||
|
||||
|
|
@ -417,6 +419,7 @@
|
|||
$.oc.foundation.element.addClass(row, 'control-group')
|
||||
|
||||
property.groupIndex = editor.getGroupIndex()
|
||||
property.groupedControl = true
|
||||
this.buildGroupExpandControl(row.querySelector('span.title-element'), property, true)
|
||||
}
|
||||
|
||||
|
|
@ -437,46 +440,11 @@
|
|||
return this.values[property]
|
||||
}
|
||||
|
||||
Surface.prototype.getValues = function() {
|
||||
var result = {}
|
||||
|
||||
// TODO: implement validation in this method. It should be optional,
|
||||
// as the method is used by other classes internally, but the validation
|
||||
// is required only for the external callers.
|
||||
|
||||
for (var i=0, len = this.parsedProperties.properties.length; i < len; i++) {
|
||||
var property = this.parsedProperties.properties[i]
|
||||
|
||||
if (property.itemType !== 'property') {
|
||||
continue
|
||||
}
|
||||
|
||||
var value = null,
|
||||
externalParameterEditor = this.findExternalParameterEditor(property.property)
|
||||
|
||||
if (!externalParameterEditor || !externalParameterEditor.isEditorVisible()) {
|
||||
value = this.getPropertyValue(property.property)
|
||||
|
||||
if (value === undefined) {
|
||||
value = property.default
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = externalParameterEditor.getValue()
|
||||
value = '{{ ' + value + ' }}'
|
||||
}
|
||||
|
||||
result[property.property] = value
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
Surface.prototype.setPropertyValue = function(property, value, supressChangeEvents, forceEditorUpdate) {
|
||||
this.values[property] = value
|
||||
|
||||
if (!supressChangeEvents) {
|
||||
if (this.originalValues[property] === undefined || this.originalValues[property] != value) {
|
||||
if (this.originalValues[property] === undefined || !this.comparePropertyValues(this.originalValues[property], value)) {
|
||||
this.markPropertyChanged(property, true)
|
||||
}
|
||||
else {
|
||||
|
|
@ -484,6 +452,10 @@
|
|||
}
|
||||
|
||||
this.notifyEditorsPropertyChanged(property, value)
|
||||
|
||||
if (this.options.onChange !== null) {
|
||||
this.options.onChange(property, value)
|
||||
}
|
||||
}
|
||||
|
||||
if (forceEditorUpdate) {
|
||||
|
|
@ -598,6 +570,61 @@
|
|||
return div.innerHTML
|
||||
}
|
||||
|
||||
Surface.prototype.comparePropertyValues = function(oldValue, newValue) {
|
||||
if (oldValue === undefined && newValue !== undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (oldValue !== undefined && newValue === undefined) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (typeof oldValue == 'object' && typeof newValue == 'object') {
|
||||
return JSON.stringify(oldValue) == JSON.stringify(newValue)
|
||||
}
|
||||
|
||||
return oldValue == newValue
|
||||
}
|
||||
|
||||
//
|
||||
// External API
|
||||
//
|
||||
|
||||
Surface.prototype.getValues = function() {
|
||||
var result = {}
|
||||
|
||||
// TODO: implement validation in this method. It should be optional,
|
||||
// as the method is used by other classes internally, but the validation
|
||||
// is required only for the external callers.
|
||||
|
||||
for (var i=0, len = this.parsedProperties.properties.length; i < len; i++) {
|
||||
var property = this.parsedProperties.properties[i]
|
||||
|
||||
if (property.itemType !== 'property') {
|
||||
continue
|
||||
}
|
||||
|
||||
var value = null,
|
||||
externalParameterEditor = this.findExternalParameterEditor(property.property)
|
||||
|
||||
if (!externalParameterEditor || !externalParameterEditor.isEditorVisible()) {
|
||||
value = this.getPropertyValue(property.property)
|
||||
|
||||
if (value === undefined) {
|
||||
value = property.default
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = externalParameterEditor.getValue()
|
||||
value = '{{ ' + value + ' }}'
|
||||
}
|
||||
|
||||
result[property.property] = value
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// EVENT HANDLERS
|
||||
//
|
||||
|
||||
|
|
@ -614,7 +641,8 @@
|
|||
// ============================
|
||||
|
||||
Surface.DEFAULTS = {
|
||||
enableExternalParameterEditor: false
|
||||
enableExternalParameterEditor: false,
|
||||
onChange: null
|
||||
}
|
||||
|
||||
// REGISTRATION
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@
|
|||
this.tally++
|
||||
}
|
||||
|
||||
LoadIndicator.prototype.destroy = function() {
|
||||
this.$el.removeData('oc.loadIndicator')
|
||||
this.$el = null
|
||||
}
|
||||
|
||||
LoadIndicator.DEFAULTS = {
|
||||
text: ''
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,9 +116,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.text-multiline, &.set {
|
||||
&.trigger-cell {
|
||||
padding: 0!important;
|
||||
|
||||
a.trigger {
|
||||
display: block;
|
||||
padding: 5px 12px 7px 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: @color-inspector-text;
|
||||
|
|
@ -127,6 +130,16 @@
|
|||
&.placeholder {
|
||||
color: #b5babd;
|
||||
}
|
||||
|
||||
.loading-indicator {
|
||||
background-color: @color-inspector-bg;
|
||||
|
||||
span {
|
||||
margin-top: -12px;
|
||||
right: 10px;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +330,7 @@
|
|||
|
||||
.select2-selection {
|
||||
background: transparent;
|
||||
height: 30px;
|
||||
height: 29px;
|
||||
line-height: 29px;
|
||||
padding: 0 3px 0 12px;
|
||||
.border-radius(0) !important;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ table.table.data {
|
|||
|
||||
font-size: 12px;
|
||||
|
||||
&.no-offset-bottom {
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
|
||||
thead {
|
||||
background: @color-list-head-bg;
|
||||
|
||||
|
|
@ -228,6 +232,12 @@ table.table.data {
|
|||
}
|
||||
}
|
||||
|
||||
&.no-active-indicator tbody {
|
||||
tr td:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
|
||||
tfoot {
|
||||
a { color: @color-list-text; text-decoration: none; }
|
||||
td, th {
|
||||
|
|
|
|||
|
|
@ -1786,6 +1786,8 @@ if(this.options.opaque!==undefined){indicator.addClass('is-opaque')}
|
|||
this.$el.prepend(indicator)
|
||||
this.$el.addClass('in-progress')
|
||||
this.tally++}
|
||||
LoadIndicator.prototype.destroy=function(){this.$el.removeData('oc.loadIndicator')
|
||||
this.$el=null}
|
||||
LoadIndicator.DEFAULTS={text:''}
|
||||
var old=$.fn.loadIndicator
|
||||
$.fn.loadIndicator=function(option){var args=arguments;return this.each(function(){var $this=$(this)
|
||||
|
|
|
|||
|
|
@ -2320,6 +2320,7 @@ table td[class*="col-"],table th[class*="col-"]{position:static;float:none;displ
|
|||
.table-responsive > .table-bordered > tbody > tr:last-child > th,.table-responsive > .table-bordered > tfoot > tr:last-child > th,.table-responsive > .table-bordered > tbody > tr:last-child > td,.table-responsive > .table-bordered > tfoot > tr:last-child > td{border-bottom:0}
|
||||
}
|
||||
table.table.data{font-size:12px}
|
||||
table.table.data.no-offset-bottom{margin-bottom:0 !important}
|
||||
table.table.data thead{background:#ffffff}
|
||||
table.table.data thead td,table.table.data thead th{border-width:1px;border-top:1px solid #e2e2e2 !important;border-color:#e2e2e2;padding:0;font-weight:normal}
|
||||
table.table.data thead td > a,table.table.data thead th > a,table.table.data thead td > span,table.table.data thead th > span{display:block;padding:13px 15px;text-transform:uppercase;color:#333333;text-decoration:none}
|
||||
|
|
@ -2359,6 +2360,7 @@ table.table.data tbody td.column-slim{padding-left:0;padding-right:0}
|
|||
table.table.data tbody.icons td i[class^="icon-"]{display:inline-block;margin-right:7px;font-size:15px;color:#95a5a6;position:relative;top:1px}
|
||||
table.table.data tbody.clickable{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
table.table.data tbody td.column-compact{padding:0}
|
||||
table.table.data.no-active-indicator tbody tr td:first-child{border-left:none}
|
||||
table.table.data tfoot a{color:#666666;text-decoration:none}
|
||||
table.table.data tfoot td,table.table.data tfoot th{border-color:#e2e2e2;padding:10px 15px}
|
||||
table.table.data th.list-cell-type-switch,table.table.data td.list-cell-type-switch{text-align:center}
|
||||
|
|
@ -2440,8 +2442,11 @@ table.table.data tr.list-tree-level-10 td.list-cell-index-1{padding-left:125px}
|
|||
.inspector-fields td.text input[type=text]::-moz-placeholder{font-weight:normal !important;color:#b5babd}
|
||||
.inspector-fields td.text input[type=text]:-ms-input-placeholder{font-weight:normal !important;color:#b5babd}
|
||||
.inspector-fields td.text.active{background:#ffffff;border-left:1px solid #c8cccd}
|
||||
.inspector-fields td.text-multiline a.trigger,.inspector-fields td.set a.trigger{display:block;overflow:hidden;text-overflow:ellipsis;color:#333333;text-decoration:none}
|
||||
.inspector-fields td.text-multiline a.trigger.placeholder,.inspector-fields td.set a.trigger.placeholder{color:#b5babd}
|
||||
.inspector-fields td.trigger-cell{padding:0 !important}
|
||||
.inspector-fields td.trigger-cell a.trigger{display:block;padding:5px 12px 7px 12px;overflow:hidden;text-overflow:ellipsis;color:#333333;text-decoration:none}
|
||||
.inspector-fields td.trigger-cell a.trigger.placeholder{color:#b5babd}
|
||||
.inspector-fields td.trigger-cell a.trigger .loading-indicator{background-color:#f2f2f2}
|
||||
.inspector-fields td.trigger-cell a.trigger .loading-indicator span{margin-top:-12px;right:10px;left:auto}
|
||||
.inspector-fields td.dropdown{padding:0 !important}
|
||||
.inspector-fields td select{width:90%}
|
||||
.inspector-fields td div.external-param-editor-container{position:relative;padding-right:15px}
|
||||
|
|
@ -2467,7 +2472,7 @@ table.table.data tr.list-tree-level-10 td.list-cell-index-1{padding-left:125px}
|
|||
.inspector-fields div.custom-checkbox{margin-top:0;margin-bottom:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
.inspector-fields div.custom-checkbox label:before{top:-12px}
|
||||
.inspector-fields .select2-container{width:100% !important}
|
||||
.inspector-fields .select2-container .select2-selection{background:transparent;height:30px;line-height:29px;padding:0 3px 0 12px;-webkit-border-radius:0 !important;-moz-border-radius:0 !important;border-radius:0 !important;border:none !important;font-size:12px}
|
||||
.inspector-fields .select2-container .select2-selection{background:transparent;height:29px;line-height:29px;padding:0 3px 0 12px;-webkit-border-radius:0 !important;-moz-border-radius:0 !important;border-radius:0 !important;border:none !important;font-size:12px}
|
||||
.inspector-fields .select2-container .select2-selection.select2-default{font-weight:normal !important}
|
||||
.inspector-fields .select2-container .loading-indicator > span{top:15px}
|
||||
.inspector-fields .select2-container.select2-container--open{-webkit-border-radius:0 !important;-moz-border-radius:0 !important;border-radius:0 !important;border:none !important}
|
||||
|
|
|
|||
Loading…
Reference in New Issue