mirror of
https://github.com/wintercms/winter.git
synced 2024-06-28 05:33:29 +02:00
Styling and column alignemnt
This commit is contained in:
parent
1f420c88fd
commit
a73ef52d36
@ -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)
|
110
modules/backend/widgets/table/assets/css/table.css
Normal file
110
modules/backend/widgets/table/assets/css/table.css
Normal 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;
|
||||
}
|
@ -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]
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
||||
|
143
modules/backend/widgets/table/assets/less/table.less
Normal file
143
modules/backend/widgets/table/assets/less/table.less
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user