PHP Classes

File: modules/system/assets/ui/js/inspector.editor.objectlist.js

Recommend this page to a friend!
  Packages of Luke Towers   Winter   modules/system/assets/ui/js/inspector.editor.objectlist.js   Download  
File: modules/system/assets/ui/js/inspector.editor.objectlist.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Winter
Content management system that uses MVC
Author: By
Last change:
Date: 7 months ago
Size: 26,057 bytes
 

Contents

Class file image Download
/* * Inspector object list editor class. */ +function ($) { "use strict"; var Base = $.wn.inspector.propertyEditors.base, BaseProto = Base.prototype var ObjectListEditor = function(inspector, propertyDefinition, containerCell, group) { 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, group) } ObjectListEditor.prototype = Object.create(BaseProto) ObjectListEditor.prototype.constructor = Base ObjectListEditor.prototype.init = function() { if (this.isKeyValueMode()) { var keyProperty = this.getKeyProperty() if (!keyProperty) { throw new Error('Object list key property ' + this.propertyDefinition.keyProperty + ' is not defined in itemProperties. Property: ' + this.propertyDefinition.property) } } BaseProto.init.call(this) } ObjectListEditor.prototype.dispose = function() { this.unregisterHandlers() this.removeControls() this.currentRowInspector = null this.popup = null BaseProto.dispose.call(this) } ObjectListEditor.prototype.supportsExternalParameterEditor = function() { return false } // // Building // ObjectListEditor.prototype.build = function() { var link = document.createElement('a') $.wn.foundation.element.addClass(link, 'trigger') link.setAttribute('href', '#') this.setLinkText(link) $.wn.foundation.element.addClass(this.containerCell, 'trigger-cell') this.containerCell.appendChild(link) } ObjectListEditor.prototype.setLinkText = function(link, value) { var value = value !== undefined && value !== null ? value : this.inspector.getPropertyValue(this.propertyDefinition.property) if (value === null) { value = undefined } if (value === undefined) { var placeholder = this.propertyDefinition.placeholder if (placeholder !== undefined) { $.wn.foundation.element.addClass(link, 'placeholder') link.textContent = placeholder } else { link.textContent = 'Items: 0' } } else { var itemCount = 0 if (!this.isKeyValueMode()) { if (value.length === undefined) { throw new Error('Object list value should be an array. Property: ' + this.propertyDefinition.property) } itemCount = value.length } else { if (typeof value !== 'object') { throw new Error('Object list value should be an object. Property: ' + this.propertyDefinition.property) } itemCount = this.getValueKeys(value).length } $.wn.foundation.element.removeClass(link, 'placeholder') link.textContent = 'Items: ' + itemCount } } ObjectListEditor.prototype.getPopupContent = function() { return '<form> \ <div class="modal-header"> \ <button type="button" class="close" data-dismiss="popup">&times;</button> \ <h4 class="modal-title">{{property}}</h4> \ </div> \ <div> \ <div class="layout inspector-columns-editor"> \ <div class="layout-row"> \ <div class="layout-cell items-column"> \ <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 \ wn-icon-plus" \ data-cmd="create-item">Add</button> \ <button type="button" class="btn btn-default \ empty wn-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 || this.getValueKeys(items).length === 0) { var row = this.buildEmptyRow() tbody.appendChild(row) } else { var firstRow = undefined for (var key in items) { var item = items[key], itemInspectorValue = this.addKeyProperty(key, item), itemText = item[titleProperty], row = this.buildTableRow(itemText, 'rowlink') row.setAttribute('data-inspector-values', JSON.stringify(itemInspectorValue)) tbody.appendChild(row) if (firstRow === undefined) { firstRow = row } } } table.appendChild(tbody) if (firstRow !== undefined) { this.selectRow(firstRow, true) } 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) { $.wn.foundation.element.addClass(row, rowClass) } if (cellClass !== undefined) { $.wn.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, forceSelect) { var tbody = row.parentNode, inspectorContainer = this.getInspectorContainer(), selectedRow = this.getSelectedRow() if (selectedRow === row && !forceSelect) { return } if (selectedRow) { if (!this.validateKeyValue()) { return } if (this.currentRowInspector) { if (!this.currentRowInspector.validate()) { return } } this.applyDataToRow(selectedRow) $.wn.foundation.element.removeClass(selectedRow, 'active') } this.disposeInspector() $.wn.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 = JSON.parse(dataStr), options = { enableExternalParameterEditor: false, onChange: this.proxy(this.onInspectorDataChange), inspectorClass: this.inspector.options.inspectorClass, parentContainer: this.getRootSurface(), } this.currentRowInspector = new $.wn.inspector.surface(inspectorContainer, properties, values, $.wn.inspector.helpers.generateElementUniqueId(inspectorContainer), options, null, null, this.propertyDefinition.property) } ObjectListEditor.prototype.disposeInspector = function() { $.wn.foundation.controlUtils.disposeControls(this.popup.querySelector('[data-inspector-container]')) 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 } value = $.trim(value) if (value.length === 0) { value = '[No title]' $.wn.foundation.element.addClass(selectedRow, 'disabled') } else { $.wn.foundation.element.removeClass(selectedRow, 'disabled') } 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 ($.wn.foundation.element.hasClass(rows[i], 'active')) { return rows[i] } } return null } ObjectListEditor.prototype.createItem = function() { var selectedRow = this.getSelectedRow() if (selectedRow) { if (!this.validateKeyValue()) { return } if (this.currentRowInspector) { if (!this.currentRowInspector.validate()) { return } } this.applyDataToRow(selectedRow) $.wn.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, true) 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 = this.getEmptyValue() if (selectedRow) { if (!this.validateKeyValue()) { return } if (this.currentRowInspector) { if (!this.currentRowInspector.validate()) { return } } this.applyDataToRow(selectedRow) } for (var i = 0, len = dataRows.length; i < len; i++) { var dataRow = dataRows[i], rowData = JSON.parse(dataRow.getAttribute('data-inspector-values')) if (!this.isKeyValueMode()) { result.push(rowData) } else { var rowKey = rowData[this.propertyDefinition.keyProperty] result[rowKey] = this.removeKeyProperty(rowData) } } this.inspector.setPropertyValue(this.propertyDefinition.property, result) this.setLinkText(link, result) $(link).popup('hide') return false } ObjectListEditor.prototype.validateKeyValue = function() { if (!this.isKeyValueMode()) { return true } if (this.currentRowInspector === null) { return true } var data = this.currentRowInspector.getValues(), keyProperty = this.propertyDefinition.keyProperty if (data[keyProperty] === undefined) { throw new Error('Key property ' + keyProperty + ' is not found in the Inspector data. Property: ' + this.propertyDefinition.property) } var keyPropertyValue = data[keyProperty], keyPropertyTitle = this.getKeyProperty().title if (typeof keyPropertyValue !== 'string') { throw new Error('Key property (' + keyProperty + ') value should be a string. Property: ' + this.propertyDefinition.property) } if ($.trim(keyPropertyValue).length === 0) { $.wn.flashMsg({text: 'The value of key property ' + keyPropertyTitle + ' cannot be empty.', 'class': 'error', 'interval': 3}) return false } var selectedRow = this.getSelectedRow(), tbody = this.getTableBody(), dataRows = tbody.querySelectorAll('tr[data-inspector-values]') for (var i = 0, len = dataRows.length; i < len; i++) { var dataRow = dataRows[i], rowData = JSON.parse(dataRow.getAttribute('data-inspector-values')) if (selectedRow == dataRow) { continue } if (rowData[keyProperty] == keyPropertyValue) { $.wn.flashMsg({text: 'The value of key property ' + keyPropertyTitle + ' should be unique.', 'class': 'error', 'interval': 3}) return false } } return true } // // Helpers // ObjectListEditor.prototype.getLink = function() { return this.containerCell.querySelector('a.trigger') } ObjectListEditor.prototype.getPopupFormElement = function() { var form = this.popup.querySelector('form') if (!form) { this.throwError('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') } ObjectListEditor.prototype.isKeyValueMode = function() { return this.propertyDefinition.keyProperty !== undefined } ObjectListEditor.prototype.getKeyProperty = function() { for (var i = 0, len = this.propertyDefinition.itemProperties.length; i < len; i++) { var property = this.propertyDefinition.itemProperties[i] if (property.property == this.propertyDefinition.keyProperty) { return property } } } ObjectListEditor.prototype.getValueKeys = function(value) { var result = [] for (var key in value) { result.push(key) } return result } ObjectListEditor.prototype.addKeyProperty = function(key, value) { if (!this.isKeyValueMode()) { return value } value[this.propertyDefinition.keyProperty] = key return value } ObjectListEditor.prototype.removeKeyProperty = function(value) { if (!this.isKeyValueMode()) { return value } var result = value if (result[this.propertyDefinition.keyProperty] !== undefined) { delete result[this.propertyDefinition.keyProperty] } return result } ObjectListEditor.prototype.getEmptyValue = function() { if (this.isKeyValueMode()) { return {} } else { return [] } } // // 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) { $.wn.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) this.getRootSurface().popupDisplayed() } 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() $.wn.foundation.controlUtils.disposeControls(this.popup) this.popup = null this.getRootSurface().popupHidden() } 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) } } $.wn.inspector.propertyEditors.objectList = ObjectListEditor }(window.jQuery);