Styling and column alignemnt

This commit is contained in:
alekseybobkov 2014-12-01 22:31:11 -08:00
parent 1f420c88fd
commit a73ef52d36
7 changed files with 323 additions and 15 deletions

View File

@ -128,6 +128,6 @@ Columns are defined as array with the `columns` property. The array keys corresp
- `title`
- `type` (string, checkbox, dropdown, autocomplete)
- `width`
- `width` - sets the column width, can be specified in percents (10%) or pixels (50px). There could be a single column without the width specified. It will be stretched to take the available space.
- `readonly`
- `options` (for drop-down elements and autocomplete types)

View File

@ -0,0 +1,110 @@
/*
* General control styling
*/
.table-control {
/* TODO: this should be applied only when the control is active */
}
.table-control .table-container {
border: 1px solid #808c8d;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
overflow: hidden;
}
.table-control table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
.table-control table td,
.table-control table th {
padding: 0;
font-size: 13px;
color: #555555;
}
.table-control table [data-view-container] {
padding: 5px 10px;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.table-control table.headers:after {
content: ' ';
display: block;
position: absolute;
left: 1px;
right: 1px;
border-bottom: 1px solid #bdc3c7;
}
.table-control table.headers th {
padding: 7px 10px;
font-size: 13px;
text-transform: uppercase;
font-weight: 600;
color: #333333;
background: white;
border-right: 1px solid #ecf0f1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.table-control table.headers th:last-child {
border-right: none;
}
.table-control table.data td {
border: 1px solid #ecf0f1;
}
.table-control table.data td .content-container {
position: relative;
padding: 1px;
}
.table-control table.data td.active {
border-color: #2f99da;
}
.table-control table.data td.active .content-container {
padding: 0;
border: 1px solid #2f99da;
}
.table-control table.data td.active .content-container:before,
.table-control table.data td.active .content-container:after {
content: ' ';
background: #2f99da;
position: absolute;
left: -2px;
top: -2px;
}
.table-control table.data td.active .content-container:before {
width: 1px;
bottom: -2px;
}
.table-control table.data td.active .content-container:after {
right: -2px;
height: 1px;
}
.table-control table.data tr {
background-color: white;
}
.table-control table.data tr:nth-child(2n) {
background-color: #fbfbfb;
}
.table-control table.data tr:last-child td {
border-bottom: none;
}
.table-control table.data td:first-child {
border-left: none;
}
.table-control table.data td:last-child {
border-right: none;
}
/*
* String editor
*/
.table-control td[data-column-type=string] input[type=text] {
width: 100%;
height: 100%;
display: block;
outline: none;
border: none;
padding: 5px 10px;
}

View File

@ -35,6 +35,9 @@
// A reference to the currently active table cell
this.activeCell = null
// A reference to the tables container
this.tableContainer = null
// The key of the row which is being edited at the moment.
// This key corresponds the data source row key which
// uniquely identifies the row in the data set. When the
@ -45,6 +48,9 @@
// A reference to the data table
this.dataTable = null
// A reference to the header table
this.headerTable = null
// Event handlers
this.clickHandler = this.onClick.bind(this)
this.keydownHandler = this.onKeydown.bind(this)
@ -148,8 +154,14 @@
}
Table.prototype.buildTables = function() {
this.tableContainer = document.createElement('div')
this.tableContainer.setAttribute('class', 'table-container')
// Build the headers table
this.el.appendChild(this.buildHeaderTable())
this.tableContainer.appendChild(this.buildHeaderTable())
// Append the table container to the element
this.el.insertBefore(this.tableContainer, this.el.children[0])
// Build the data table
this.updateDataTable()
@ -164,6 +176,10 @@
for (var i = 0, len = this.options.columns.length; i < len; i++) {
var header = document.createElement('th')
if (this.options.columns[i].width)
header.setAttribute('style', 'width: '+this.options.columns[i].width)
header.textContent !== undefined ?
header.textContent = this.options.columns[i].title :
header.innerText = this.options.columns[i].title
@ -171,6 +187,8 @@
row.appendChild(header)
}
this.headerTable = headersTable
return headersTable
}
@ -189,10 +207,22 @@
})
}
Table.prototype.updateColumnWidth = function() {
var headerCells = this.headerTable.querySelectorAll('th'),
dataCells = this.dataTable.querySelectorAll('tr:first-child td')
for (var i = 0, len = headerCells.length; i < len; i++) {
if (dataCells[i])
dataCells[i].setAttribute('style', headerCells[i].getAttribute('style'))
}
}
Table.prototype.buildDataTable = function(records, totalCount) {
var dataTable = document.createElement('table'),
tbody = document.createElement('tbody')
dataTable.setAttribute('class', 'data')
for (var i = 0, len = records.length; i < len; i++) {
var row = document.createElement('tr')
@ -203,6 +233,7 @@
for (var j = 0, colsLen = this.options.columns.length; j < colsLen; j++) {
var cell = document.createElement('td'),
dataContainer = document.createElement('input'),
cellContentContainer = document.createElement('div'),
column = this.options.columns[j],
columnName = column.key,
cellProcessor = this.getCellProcessor(columnName)
@ -216,7 +247,11 @@
records[i][columnName] :
""
cellProcessor.renderCell(records[i][columnName], cell)
cellContentContainer.setAttribute('class', 'content-container')
cellProcessor.renderCell(records[i][columnName], cellContentContainer)
cell.appendChild(cellContentContainer)
cell.appendChild(dataContainer)
row.appendChild(cell)
@ -229,12 +264,15 @@
// Inject the data table to the DOM or replace the existing table
if (this.dataTable !== null)
this.el.replaceChild(dataTable, this.dataTable)
this.tableContainer.replaceChild(dataTable, this.dataTable)
else
this.el.appendChild(dataTable)
this.tableContainer.appendChild(dataTable)
this.dataTable = dataTable
// Update column widths
this.updateColumnWidth()
// Update the pagination links
this.navigation.buildPagination(totalCount)
}
@ -307,9 +345,13 @@
if (!processor)
throw new Error("Cell processor not found for the column "+columnName)
if (this.activeCell)
this.activeCell.setAttribute('class', '')
if (this.activeCell !== cellElement) {
this.setActiveProcessor(processor)
this.activeCell = cellElement
this.activeCell.setAttribute('class', 'active')
}
// If the cell belongs to other row than the currently edited,
@ -477,6 +519,7 @@
// Remove references to DOM elements
this.dataTable = null
this.headerTable = null
// Dispose cell processors
this.disposeCellProcessors()
@ -485,13 +528,14 @@
this.navigation.dispose()
this.navigation = null
// Delete the reference to the control HTML element.
// Delete references to the control HTML elements.
// The script doesn't remove any DOM elements themselves.
// If it's needed it should be done by the outer script,
// we only make sure that the table widget doesn't hold
// references to the detached DOM tree so that the garbage
// collector can delete the elements if needed.
this.el = null
this.tableContainer = null
// Delete references to other DOM elements
this.activeCell = null
@ -505,6 +549,10 @@
return this.el
}
Table.prototype.getTableContainer = function() {
return this.tableContainer
}
Table.prototype.getDataTableBody = function() {
return this.dataTable.children[0]
}

View File

@ -43,7 +43,7 @@
/*
* Renders the cell in the normal (no edit) mode
*/
Base.prototype.renderCell = function(value, cellElement) {
Base.prototype.renderCell = function(value, cellContentContainer) {
}
/*
@ -87,18 +87,25 @@
return true
}
/*
* Returns the content container element of a cell
*/
Base.prototype.getCellContentContainer = function(cellElement) {
return cellElement.querySelector('.content-container')
}
/*
* Creates a cell view data container (a DIV element that contains
* the current cell value). This functionality is required for most
* of the processors, perhaps except the checkbox cell processor.
*/
Base.prototype.createViewContainer = function(cellElement, value) {
Base.prototype.createViewContainer = function(cellContentContainer, value) {
var viewContainer = document.createElement('div')
viewContainer.setAttribute('data-view-container', 'data-view-container')
viewContainer.textContent = value
cellElement.appendChild(viewContainer)
cellContentContainer.appendChild(viewContainer)
}
/*

View File

@ -45,8 +45,8 @@
/*
* Renders the cell in the normal (no edit) mode
*/
StringProcessor.prototype.renderCell = function(value, cellElement) {
this.createViewContainer(cellElement, value)
StringProcessor.prototype.renderCell = function(value, cellContentContainer) {
this.createViewContainer(cellContentContainer, value)
}
/*
@ -58,7 +58,7 @@
return
this.activeCell = cellElement
this.buildEditor(cellElement)
this.buildEditor(cellElement, this.getCellContentContainer(cellElement))
}
/*
@ -82,7 +82,7 @@
this.activeCell = null
}
StringProcessor.prototype.buildEditor = function(cellElement) {
StringProcessor.prototype.buildEditor = function(cellElement, cellContentContainer) {
// Hide the view container
this.hideViewContainer(this.activeCell)
@ -91,7 +91,7 @@
input.setAttribute('type', 'text')
input.setAttribute('class', 'string-input')
input.value = this.tableObj.getCellValue(cellElement)
cellElement.appendChild(input)
cellContentContainer.appendChild(input)
this.setCaretPosition(input, 0)

View File

@ -0,0 +1,143 @@
@import "../../../../../backend/assets/less/core/boot.less";
/*
* General control styling
*/
.table-control {
.table-container {
border: 1px solid #808c8d;
.border-radius(4px);
overflow: hidden;
}
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
td, th {
padding: 0;
font-size: 13px;
color: #555555;
}
[data-view-container] {
padding: 5px 10px;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
table.headers {
&:after {
content: ' ';
display: block;
position: absolute;
left: 1px;
right: 1px;
border-bottom: 1px solid #bdc3c7;
}
th {
padding: 7px 10px;
font-size: 13px;
text-transform: uppercase;
font-weight: 600;
color: #333333;
background: white;
border-right: 1px solid #ecf0f1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&:last-child {
border-right: none;
}
}
}
table.data {
td {
border: 1px solid #ecf0f1;
.content-container {
position: relative;
padding: 1px;
}
&.active {
border-color: #2f99da;
.content-container {
padding: 0;
border: 1px solid #2f99da;
&:before, &:after {
content: ' ';
background: #2f99da;
position: absolute;
left: -2px;
top: -2px;
}
&:before {
width: 1px;
bottom: -2px;
}
&:after {
right: -2px;
height: 1px;
}
}
}
}
tr {
background-color: white;
}
tr:nth-child(2n) {
background-color: #fbfbfb;
}
}
/* TODO: this should be applied only when the control is active */
table.data {
tr:first-child td {
}
tr:last-child td {
border-bottom: none;
}
td:first-child {
border-left: none;
}
td:last-child {
border-right: none;
}
}
}
/*
* String editor
*/
.table-control {
td[data-column-type=string] {
input[type=text] {
width: 100%;
height: 100%;
display: block;
outline: none;
border: none;
padding: 5px 10px;
}
}
}

View File

@ -331,4 +331,4 @@
<!-- <div data-control="table" data-row-sorting="1" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>"></div> -->
<div data-control="table" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>" data-records-per-page="10"></div>
<div data-control="table" class="table-control" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>" data-records-per-page="10"></div>