mirror of
https://github.com/openwrt/luci.git
synced 2026-04-15 19:01:56 +00:00
luci-base: refresh table generation
Tables are now structured with standard HTML tags: table -> thead -> tr rows table -> tbody -> tr rows table -> tfoot -> tr rows - wrap table header rows in a thead element - wrap table body rows in a tbody element - wrap footer rowss in a tfoot element Footer row data can be provided by initializing any of the form table types with .footer set to a string or function, or overriding the renderFooterRows method. Signed-off-by: Paul Donald <newtwen+github@gmail.com>
This commit is contained in:
@@ -2545,6 +2545,24 @@ const CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection
|
||||
* @default null
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optional footer row for table sections.
|
||||
*
|
||||
* Set `footer` to one of:
|
||||
* - a function that returns a table row (`tr`) or node `E('...')`
|
||||
* - an array of string cell contents (first entry maps to the name column
|
||||
* if present).
|
||||
*
|
||||
* This is useful for providing sum totals, extra function buttons or extra
|
||||
* space.
|
||||
*
|
||||
* The default implementation returns an empty node.
|
||||
*
|
||||
* @name LuCI.form.TableSection.prototype#footer
|
||||
* @type string[]|function
|
||||
* @default E([])
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set to `true`, a sort button is added to the last column, allowing
|
||||
* the user to reorder the section instances mapped by the section form
|
||||
@@ -2611,13 +2629,28 @@ const CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection
|
||||
'class': 'table cbi-section-table'
|
||||
});
|
||||
|
||||
const theadEl = E('thead', {
|
||||
'class': 'thead cbi-section-thead'
|
||||
});
|
||||
|
||||
const tbodyEl = E('tbody', {
|
||||
'class': 'tbody cbi-section-tbody'
|
||||
});
|
||||
|
||||
const tfootEl = E('tfoot', {
|
||||
'class': 'tfoot cbi-section-tfoot'
|
||||
});
|
||||
|
||||
if (this.title != null && this.title != '' && !this.hidetitle)
|
||||
sectionEl.appendChild(E('h3', {}, this.title));
|
||||
|
||||
if (this.description != null && this.description != '')
|
||||
sectionEl.appendChild(E('div', { 'class': 'cbi-section-descr' }, this.description));
|
||||
|
||||
tableEl.appendChild(this.renderHeaderRows(false));
|
||||
theadEl.appendChild(this.renderHeaderRows(false));
|
||||
|
||||
if(theadEl.hasChildNodes())
|
||||
tableEl.appendChild(theadEl);
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let sectionname = this.titleFn('sectiontitle', cfgsections[i]);
|
||||
@@ -2640,7 +2673,7 @@ const CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection
|
||||
});
|
||||
|
||||
if (this.extedit || this.rowcolors)
|
||||
trEl.classList.add(!(tableEl.childNodes.length % 2)
|
||||
trEl.classList.add(!(tbodyEl.childNodes.length % 2)
|
||||
? 'cbi-rowstyle-1' : 'cbi-rowstyle-2');
|
||||
|
||||
if (sectionname && (!this.anonymous || this.sectiontitle)) {
|
||||
@@ -2653,13 +2686,20 @@ const CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection
|
||||
trEl.appendChild(nodes[i].firstChild);
|
||||
|
||||
trEl.appendChild(this.renderRowActions(cfgsections[i], has_more ? _('More…') : null));
|
||||
tableEl.appendChild(trEl);
|
||||
tbodyEl.appendChild(trEl);
|
||||
}
|
||||
|
||||
if (nodes.length == 0)
|
||||
tableEl.appendChild(E('tr', { 'class': 'tr cbi-section-table-row placeholder' },
|
||||
tbodyEl.appendChild(E('tr', { 'class': 'tr cbi-section-table-row placeholder' },
|
||||
E('td', { 'class': 'td' }, this.renderSectionPlaceholder())));
|
||||
|
||||
tableEl.appendChild(tbodyEl);
|
||||
|
||||
tfootEl.appendChild(this.renderFooterRows(false));
|
||||
|
||||
if (tfootEl.hasChildNodes())
|
||||
tableEl.appendChild(tfootEl);
|
||||
|
||||
sectionEl.appendChild(tableEl);
|
||||
|
||||
sectionEl.appendChild(this.renderSectionAdd('cbi-tblsection-create'));
|
||||
@@ -2768,6 +2808,43 @@ const CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection
|
||||
return trEls;
|
||||
},
|
||||
|
||||
/** @private */
|
||||
renderFooterRows(has_action) {
|
||||
if (this.footer == null)
|
||||
return E([]);
|
||||
|
||||
const max_cols = this.max_cols ?? this.children.length;
|
||||
const has_more = max_cols < this.children.length;
|
||||
const anon_class = (!this.anonymous || this.sectiontitle) ? 'named' : 'anonymous';
|
||||
|
||||
if (typeof this.footer === 'function') {
|
||||
const node = this.footer.call(this, has_action);
|
||||
return node || E([]);
|
||||
}
|
||||
|
||||
const values = Array.isArray(this.footer) ? this.footer : [];
|
||||
let idx = 0;
|
||||
const trEl = E('tr', { 'class': `tr cbi-section-table-footer ${anon_class}` });
|
||||
|
||||
if (!this.anonymous || this.sectiontitle) {
|
||||
trEl.appendChild(E('td', { 'class': 'td cbi-value-field cbi-section-table-titles' }, values[idx++] ?? null));
|
||||
}
|
||||
|
||||
for (let i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) {
|
||||
if (opt.modalonly)
|
||||
continue;
|
||||
|
||||
trEl.appendChild(E('td', { 'class': 'td', 'data-widget': opt.__name__ }, values[idx++] ?? null));
|
||||
}
|
||||
|
||||
if (this.sortable || this.extedit || this.addremove || has_more || has_action || this.cloneable) {
|
||||
trEl.appendChild(E('td', { 'class': 'td cbi-section-actions' }, values[idx++] ?? null));
|
||||
}
|
||||
|
||||
return trEl;
|
||||
},
|
||||
|
||||
|
||||
/** @private */
|
||||
renderRowActions(section_id, more_label, trEl) {
|
||||
const config_name = this.uciconfig ?? this.map.config;
|
||||
|
||||
Reference in New Issue
Block a user