574 lines
18 KiB
HTML
574 lines
18 KiB
HTML
<% /*
|
|
File: PDA/resultset_table.inc
|
|
|
|
$Revision$
|
|
$Id$
|
|
|
|
PAS OP: Soms gebruikt in combinatie met shared/data_recordset.inc.
|
|
Zie het commentaar daarin met betrekking tot het case-sensitive
|
|
zijn van bijvoorbeeld oRs.EOF
|
|
*/
|
|
%>
|
|
|
|
<%
|
|
|
|
function ResultsetTable(params)
|
|
{
|
|
this.emptySetString = L("lcl_empty_rstable");
|
|
this.sql = null;
|
|
this.dataset = null; // of sql of dataset meegeven. Data is dan een array van objecten met properies
|
|
this.ID = null;
|
|
this.rowNum = 0;
|
|
this.showAll = null;
|
|
|
|
// Mobile params
|
|
this.noSearch = null;
|
|
this.searchInputHtml = "<input type='search' class='list-group-filter " + MOBILE_UI_CLASSES.input + "' placeholder='Filter items...'>";
|
|
this.inset = false;
|
|
this.Counter = {};
|
|
|
|
// Card layout params
|
|
this.wrapper = { "layout": "vertical" };
|
|
|
|
var param;
|
|
// Neem alle meegegeven parameters mee.
|
|
for (param in params) {
|
|
this[param] = params[param];
|
|
}
|
|
}
|
|
|
|
/*
|
|
ResultsetTable heeft overigens niets meer met <table>'s te maken
|
|
De rows zijn dan ook geen <tr>'s, maar list items (<li>)
|
|
*/
|
|
ResultsetTable.prototype.processResultset = __rsProcessResultset;
|
|
ResultsetTable.prototype.makeTableRow = __rsMakeTableRow;
|
|
ResultsetTable.prototype.countHistogram = __rsCountHistogram;
|
|
ResultsetTable.prototype.enableMultiactions = __rsEnableMultiactions;
|
|
|
|
/*global*/ isData = false;
|
|
|
|
function __rsProcessResultset(processParams)
|
|
{
|
|
this.processParams = processParams;
|
|
var copy;
|
|
|
|
if (this.sql)
|
|
{
|
|
var oRs = Oracle.Execute(this.sql);
|
|
}
|
|
else
|
|
{
|
|
/*global*/isData = true;
|
|
var oRs = new data_recordset( this.dataset );
|
|
}
|
|
|
|
if (oRs == null || oRs.EOF)
|
|
{
|
|
if (!this.emptyWhenNoResult)
|
|
Response.Write("<p>" + this.emptySetString + "</p>");
|
|
if (this.sql) {
|
|
oRs.Close();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
var lastGroup, lastDivider, lastIconHtml = null;
|
|
var html = "";
|
|
var filterCutOff = S("pda_list_show_filter_from");
|
|
|
|
|
|
var lines = [];
|
|
// Heeft groupSelect een waarde, dan wordt voor deze group de lijst getoond.
|
|
if (this.groupSelect == "") {
|
|
html += __multiActions()
|
|
+ "<section class='list-group'" + (this.ID ? " id='" + this.ID + "'" : "") + ">";
|
|
}
|
|
var cnt = 0;
|
|
var trueCount = 0;
|
|
var hasResults = false;
|
|
var initKeyDone = this.initKey == null;
|
|
|
|
if (this.groupColumn && this.groupSelect == "")
|
|
{ // we tonen alleen het aantal regels. Laat dan alle complexe processing achterwege
|
|
ResultsetTable.prototype.makeTableRow = function __rsCountTableRow(oRs, cnt) { return "dummy" };
|
|
} else if (this.layout === "card") {
|
|
ResultsetTable.prototype.makeTableRow = __rsMakeCard;
|
|
}
|
|
|
|
if (this.multiactions && this.multiactions.length > 0) {
|
|
this.hasMultiactions = true;
|
|
for (var i = 0; i < this.multiactions.length; i++) {
|
|
if (this.multiactions[i].fnCheckIfAny) { // Conditioneel aan? Begin dan eerst uit
|
|
this.multiactions[i].enabled = false;
|
|
} else {
|
|
this.multiactions[i].enabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (cnt = 0; (cnt < (S("qp_maxrows_mobile")) || this.showAll ) &&
|
|
(cnt < S("qp_maxrows2")) &&
|
|
!oRs.EOF; cnt++)
|
|
{
|
|
if (this.fnDataFilter && !this.fnDataFilter(oRs))
|
|
{
|
|
oRs.MoveNext();
|
|
continue;
|
|
}
|
|
else if (!hasResults)
|
|
hasResults = true;
|
|
|
|
if (this.dividerColumn)
|
|
{
|
|
var safenextDivider = __fnContent(this.dividerColumn)(oRs);
|
|
if (safenextDivider != lastDivider) {
|
|
lines.push("<div class='list-group-item list-group-header'><h2>" + safenextDivider + "</h2></div>");
|
|
}
|
|
lastDivider = safenextDivider;
|
|
}
|
|
|
|
if (!initKeyDone && this.initKey && this.keyColumn && this.initKey == __fnContent(this.keyColumn)(oRs))
|
|
{
|
|
lines.unshift(this.makeTableRow(oRs, cnt, false));
|
|
initKeyDone = true;
|
|
}
|
|
else
|
|
lines.push(this.makeTableRow(oRs, cnt, false));
|
|
|
|
trueCount++;
|
|
|
|
if (this.buildHistogram)
|
|
this.countHistogram(oRs);
|
|
|
|
if (this.multiactions) {
|
|
this.enableMultiactions(oRs);
|
|
}
|
|
|
|
if ((this.groupColumn || (this.singleLink && trueCount < 2)) && this.linkColumn)
|
|
var lastLink = __fnContent(this.linkColumn)(oRs);
|
|
|
|
var numberInGroup = -1;
|
|
if (this.groupColumn)
|
|
{
|
|
lastGroup = __fnContent(this.groupColumn)(oRs);
|
|
if (this.iconColumn) {
|
|
lastIconHtml = "";
|
|
var icon = __fnContent(this.iconColumn)(oRs, this.processParams)
|
|
if (icon) {
|
|
var iconHtml = "";
|
|
if (icon.match(/^</)) { // Ik ben al een plaatje :) of safe html, bv een <div> of <i>
|
|
iconHtml = icon;
|
|
} else if (icon.match(/^fa-/)) {
|
|
iconHtml = I(icon + " fa-2x");
|
|
} else {
|
|
iconHtml = '<img loading="lazy" src="' + safe.htmlattr(icon) + '" alt="' + L("lcl_photos") + '">';
|
|
}
|
|
lastIconHtml = "<div class='list-illustration flex-center'>" + iconHtml + "</div>";
|
|
}
|
|
}
|
|
if (this.numberInGroup)
|
|
numberInGroup = __fnContent(this.numberInGroup)(oRs);
|
|
}
|
|
|
|
oRs.MoveNext();
|
|
|
|
if (trueCount === 1 && oRs.EOF && this.singleLink && this.linkColumn && lastLink)
|
|
{
|
|
trueCount = -1;
|
|
break;
|
|
}
|
|
|
|
if (this.groupColumn)
|
|
{
|
|
var overLimit = (cnt+1 >= (S("qp_maxrows_mobile")) && !this.showAll ) ||
|
|
(cnt+1 >= S("qp_maxrows2"))
|
|
|
|
if (!oRs.EOF)
|
|
var nextGroup = __fnContent(this.groupColumn)(oRs);
|
|
|
|
// In jquery-mobile-1.4.2 zijn geneste lijsten niet meer toegestaan.
|
|
// De *_list.asp wordt nu geplitst: is groupSelect leeg dan worden de groepen getoond
|
|
// Heeft groupSelect een waarde, dan wordt voor deze group de lijst getoond.
|
|
if (this.groupSelect == "")
|
|
{ // Toon de groepen
|
|
if (oRs.EOF || overLimit || nextGroup != lastGroup)
|
|
{
|
|
html += "<a href='" + lastLink + "' class='list-group-item list-group-item-action'>"
|
|
+ (this.iconColumn ? lastIconHtml : "")
|
|
+ "<h6 class='limit-lines-2'>" + lastGroup + "</h6>"
|
|
+ "<div class='list-aside badge text-bg-secondary'>" + (numberInGroup > 0 ? numberInGroup : lines.length) + "</div>"
|
|
+ "</a>";
|
|
lines = [];
|
|
}
|
|
}
|
|
else
|
|
{ // Toon de lijst van een geselecteerde groep
|
|
if (oRs.EOF || overLimit)
|
|
{
|
|
html += __multiActions()
|
|
if (!this.noSearch) {
|
|
html += this.searchInputHtml;
|
|
}
|
|
html += "<section class='list-group'" + (this.ID ? " id='"+this.ID + "'" : "") + ">"
|
|
+ lines.join("\n")
|
|
+ "</section>";
|
|
lines = [];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (trueCount === -1) // 1 result in list, which we should click instantly
|
|
{
|
|
Response.Write("<script>$(function() { window.location.href = \""+ lastLink.replace(new RegExp("\"", "g"), "'") +"\"; })</script>"); // " (even aantal aanhalingstekens i.v.m. formatting editter).
|
|
if (this.sql) {
|
|
oRs.Close();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (cnt === 0 || !hasResults)
|
|
{
|
|
Response.Write("<p>" + this.emptySetString + "</p>");
|
|
if (this.sql) {
|
|
oRs.Close();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (this.groupSelect == "")
|
|
html += "</section>";
|
|
if (this.layout === "card") {
|
|
html += CARDS_WRAPPER_START_HTML(this.wrapper)
|
|
+ lines.join("")
|
|
+ CARDS_WRAPPER_END_HTML(this.wrapper);
|
|
} else if (!this.groupColumn) {
|
|
var html = __multiActions();
|
|
if (!this.noSearch && cnt > filterCutOff) {
|
|
html += this.searchInputHtml;
|
|
}
|
|
html += "<section class='list-group'" + (this.ID ? " id='" + this.ID + "'" : "") + ">"
|
|
+ lines.join("\n")
|
|
+ "</section>";
|
|
}
|
|
|
|
if (!oRs.EOF) // en dus overLimit
|
|
{
|
|
var maxrows = (this.showAll ? S("qp_maxrows2") : S("qp_maxrows_mobile"));
|
|
html += __multiActions()
|
|
+ "<section class='list-group'><div class='list-group-item'>" + L("lcl_max_lines_reached").format(maxrows) + "</div></section>";
|
|
} else if (false && /* future-use */ cnt > 5) {
|
|
Response.Write('<script>$(function() { $(".count-badge").text("' + cnt + '"); });</script>');
|
|
}
|
|
|
|
Response.Write(html);
|
|
|
|
if (this.sql) {
|
|
oRs.close();
|
|
}
|
|
|
|
if (this.buildHistogram)
|
|
return this.Counter;
|
|
else
|
|
return this.rowNum; // simpel return aantal rows
|
|
}
|
|
|
|
function __multiActions() {
|
|
var html = "";
|
|
var multiactionCount = 0;
|
|
for (var i in this.multiactions) {
|
|
multiactionCount = multiactionCount + (this.multiactions[i].enabled ? 1 : 0);
|
|
}
|
|
if (multiactionCount) {
|
|
html += "<script>"
|
|
+ " function doAm(event, fnAction) {"
|
|
+ " var key_arr = [];"
|
|
+ " $('.bulkable.bulk-selected').each((i, elem) => {"
|
|
+ " key_arr.push($(elem).data('row-key'));"
|
|
+ " });"
|
|
+ " if (key_arr.length === 0) {"
|
|
+ " return;"
|
|
+ " }"
|
|
+ " var confirm_text = key_arr.length === 1 ? L(\"lcl_shared_doaction1\") : L(\"lcl_shared_doaction\");"
|
|
+ " confirm_text = confirm_text.format(event.currentTarget.dataset.title, key_arr.length);"
|
|
+ " FcltMgr.confirm(confirm_text, _ => window[fnAction](key_arr));"
|
|
+ " }"
|
|
+ "</script>"
|
|
+ "<div class='multiactions'>"
|
|
+ " <span class='left multiaction-wrapper'>"
|
|
+ " <span class='cancel multiaction tappable'>" + I("fa-times fa-lg") + "</span>"
|
|
+ " <span class='multiaction-count' data-count='0'></span>"
|
|
+ " </span>"
|
|
+ " <span class='right multiaction-wrapper'>"
|
|
for (var i in this.multiactions) {
|
|
if (this.multiactions[i].enabled) {
|
|
html += "<span class='multiaction tappable' onclick='doAm(event, \"" + safe.htmlattr(this.multiactions[i].action) + "\")' data-title='" + safe.htmlattr(this.multiactions[i].caption) + "'>"
|
|
+ I(this.multiactions[i].icon + " fa-lg") + "</span>"
|
|
}
|
|
}
|
|
html += " </span>"
|
|
+ "</div>";
|
|
}
|
|
return html;
|
|
}
|
|
|
|
function __rsMakeCard(oRs) {
|
|
// HIER START EEN NIEUWE REGEL
|
|
var data = {};
|
|
if (this.data) {
|
|
for (var i in this.data) {
|
|
data[this.data[i]] = oRs(this.data[i]).Value;
|
|
}
|
|
}
|
|
|
|
var icon = "";
|
|
var cardClass = "";
|
|
if (this.hasMultiactions) {
|
|
cardClass = "bulkable";
|
|
}
|
|
if (this.swipeable) {
|
|
cardClass = cardClass + (cardClass ? " " : "") + "swipeable";
|
|
}
|
|
if (this.iconColumn) {
|
|
icon = __fnContent(this.iconColumn)(oRs, this.processParams);
|
|
if (icon) {
|
|
if (icon.match(/^fa-/)) {
|
|
icon = I(icon);
|
|
} else if (!icon.match(/^</)) { // Zal wel een src van een plaatje zijn dan
|
|
icon = '<img loading="lazy" src="' + safe.htmlattr(icon) + '" alt="' + L("lcl_photos") + '">';
|
|
}
|
|
cardClass = cardClass + (cardClass ? " " : "") + "with-icon icon-color";
|
|
}
|
|
}
|
|
|
|
var horiz = this.wrapper.layout === "horizontal";
|
|
|
|
var line = "";
|
|
if (horiz) {
|
|
line += "<div class='row g-0 h-100 flex-nowrap'>";
|
|
}
|
|
|
|
if (icon) {
|
|
line += " <div class='col card-illustration flex-center'>" + icon + "</div>";
|
|
}
|
|
|
|
line += " <div class='col " + (horiz ? "card-content" : "card-body") + "'>";
|
|
|
|
line += " <div class='card-title'>";
|
|
if (this.headerColumn) {
|
|
line += __fnContent(this.headerColumn)(oRs, this.processParams);
|
|
}
|
|
line += " </div>";
|
|
|
|
line += " <div class='card-descr'>";
|
|
if (this.contentColumn) {
|
|
line += __fnContent(this.contentColumn)(oRs, this.processParams);
|
|
}
|
|
line += " </div>";
|
|
|
|
line += " </div>";
|
|
|
|
if (horiz) { // Sluit de row af
|
|
line += "</div>";
|
|
}
|
|
|
|
var cardParams = {
|
|
data: data,
|
|
cls: cardClass,
|
|
noPadding: true
|
|
};
|
|
|
|
// Klikbaar als <a>nchor
|
|
if (this.linkColumn) {
|
|
var lnk = __fnContent(this.linkColumn)(oRs, this.processParams);
|
|
if (lnk) {
|
|
line = "<a href='" + safe.htmlattr(lnk) + "' class='card-link' data-ajax='false'>" + line + "</a>";
|
|
cardParams.card_class = "tappable";
|
|
}
|
|
}
|
|
|
|
// Wrap het in een CARD
|
|
line = CARD_START_HTML(cardParams)
|
|
+ line
|
|
+ CARD_END_HTML(cardParams);
|
|
|
|
this.rowNum++;
|
|
|
|
return line;
|
|
}
|
|
|
|
function __rsMakeTableRow(oRs)
|
|
{
|
|
// HIER START EEN NIEUWE REGEL
|
|
var line = "";
|
|
|
|
/* Layout;
|
|
___________________________
|
|
| | headerColumn |
|
|
| Icon | contentColumn |
|
|
|______|___________________|
|
|
*/
|
|
|
|
this.rowNum ++;
|
|
|
|
// Icon
|
|
var iconHtml = "";
|
|
if (this.iconColumn) {
|
|
var icon = __fnContent(this.iconColumn)(oRs, this.processParams)
|
|
if (icon) {
|
|
if (icon.match(/^<img/)) { // Ik ben al een plaatje :)
|
|
iconHtml = icon;
|
|
} else if (icon.match(/^fa-/)) {
|
|
iconHtml = '<span class="pda-list-icon">' + I(icon + " fa-2x") + '</span>';
|
|
} else if (icon.match(/^</)) { // safe html, bv een <div> of <i>
|
|
iconHtml = '<span class="pda-list-icon">' + icon + '</span>';
|
|
} else {
|
|
iconHtml = '<img loading="lazy" src="' + safe.htmlattr(icon) + '" alt="' + L("lcl_photos") + '">';
|
|
}
|
|
iconHtml = "<div class='list-illustration flex-center'>" + iconHtml + "</div>";
|
|
}
|
|
}
|
|
|
|
// Header
|
|
var headerHtml = "<div class='list-header text-primary'>";
|
|
if (this.headerColumn) {
|
|
var headerText = __fnContent(this.headerColumn)(oRs, this.processParams);
|
|
if (headerText) {
|
|
headerHtml += "<h6 class='limit-lines-2'>" + headerText + "</h6>";
|
|
}
|
|
}
|
|
if (this.detailColumn) {
|
|
var detailText = __fnContent(this.detailColumn)(oRs, this.processParams);
|
|
if (detailText) {
|
|
headerHtml += "<div class='list-header-detail text-secondary'>" + detailText + "</div>";
|
|
}
|
|
}
|
|
headerHtml += "</div>";
|
|
if (this.subheaderColumn) {
|
|
var subheaderText = __fnContent(this.subheaderColumn)(oRs, this.processParams);
|
|
if (subheaderText) {
|
|
headerHtml += "<div class='subheader'>" + subheaderText +"</div>";
|
|
}
|
|
}
|
|
|
|
// Body
|
|
var contentHtml = "<div class='list-body'>";
|
|
|
|
if (this.asideColumn) {
|
|
var asideText = __fnContent(this.asideColumn)(oRs, this.processParams);
|
|
if (asideText) {
|
|
contentHtml += "<div class='list-aside badge text-bg-secondary'>" + asideText + "</div>";
|
|
}
|
|
}
|
|
contentHtml += "</div>";
|
|
|
|
line = iconHtml + "<div class='list-content flex-column'>" + headerHtml + contentHtml + "</div>";
|
|
|
|
var thisRowClass = "flex-center-y gap-3 list-group-item";
|
|
|
|
if (this.hasMultiactions) {
|
|
thisRowClass += " bulkable";
|
|
}
|
|
|
|
if (this.rowClass) {
|
|
thisRowClass += " " + __fnContent(this.rowClass)(oRs, this.processParams);
|
|
}
|
|
|
|
var thisRowDataAttribute = "";
|
|
if (this.multiactions && this.keyColumn) {
|
|
thisRowDataAttribute = " data-row-key='" + oRs(this.keyColumn).Value + "'";
|
|
}
|
|
|
|
var linkAttrHtml = null;
|
|
if (this.linkColumn) {
|
|
linkAttrHtml = "href='" + safe.htmlattr(__fnContent(this.linkColumn)(oRs, this.processParams)) + "'";
|
|
} else if (this.click) {
|
|
linkAttrHtml = "href='#' onclick='" + safe.htmlattr(__fnContent(this.click)(oRs, this.processParams)) + "'";
|
|
}
|
|
if (linkAttrHtml) {
|
|
thisRowClass += " list-group-item-action";
|
|
return "<a " + linkAttrHtml + " class='" + thisRowClass + "'" + thisRowDataAttribute + ">" + line + "</a>";
|
|
}
|
|
|
|
return "<div class='" + thisRowClass + "'" + thisRowDataAttribute + ">" + line + "</div>";
|
|
}
|
|
|
|
function __rsCountHistogram(oRs)
|
|
{
|
|
var i, kolomnaam, kolomval, cnt;
|
|
for (i= 0; i < oRs.Fields.Count; i++)
|
|
{
|
|
kolomnaam = oRs.Fields(i).Name;
|
|
if (kolomnaam.toUpperCase() == this.keyColumn.toUpperCase())
|
|
continue;
|
|
kolomval = oRs.Fields(i).Value;
|
|
if (!this.Counter[kolomnaam])
|
|
this.Counter[kolomnaam] = {};
|
|
if (!this.Counter[kolomnaam][kolomval])
|
|
this.Counter[kolomnaam][kolomval] = 1;
|
|
else
|
|
this.Counter[kolomnaam][kolomval] += 1
|
|
}
|
|
}
|
|
|
|
function __rsEnableMultiactions(oRs) {
|
|
for (var i = 0; i < this.multiactions.length; i++) {
|
|
if (this.multiactions[i].enabled === false) {
|
|
this.multiactions[i].enabled = this.multiactions[i].fnCheckIfAny(oRs);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Levert een html-safe waarde op
|
|
ResultsetTable.formatValue = function (val, params) //datatype, decimals)
|
|
{
|
|
if (val == null)
|
|
{
|
|
return "";
|
|
}
|
|
if (typeof val == "object" && "name" in val) // Vanuit API2
|
|
val = val["name"];
|
|
|
|
// Eerst de geforceerde datatypes
|
|
switch (params.datatype)
|
|
{
|
|
case "date" : return toDateString(val);
|
|
case "datetime": return toDateTimeString(val, false);
|
|
case "time" : { val = toTimeString(val);
|
|
if (params.datatype == "time" && params.nomidnight && val == "00:00")
|
|
val = "";
|
|
return val;
|
|
}
|
|
case "currency": return safe.curr(val);
|
|
case "float" : return safe.displayfloat(val, params.decimals);
|
|
case "number" : return val;
|
|
case "html" : return val;
|
|
}
|
|
|
|
// Autotypering "datum"
|
|
if (typeof val == "date" || val instanceof Date)
|
|
return toDateTimeString(val); // PF: heb ik ff getweakt, moet natuurlijk niet zo (date vs datetime)
|
|
|
|
if (!val)
|
|
return "";
|
|
|
|
// default datatype is "string"
|
|
val = String(val);
|
|
|
|
val = shared.stripbbcodes(val);
|
|
|
|
return safe.html(val); // altijd simpelweg hele tekst
|
|
}
|
|
function __fnContent(fnContent)
|
|
{
|
|
if (fnContent instanceof Function)
|
|
return fnContent;
|
|
|
|
return function (oRs)
|
|
{
|
|
return ResultsetTable.formatValue(oRs.Fields(fnContent).Value, {datatype: this.datatype, decimals: this.decimals, nomidnight: this.nomidnight})
|
|
} ;
|
|
}
|
|
%>
|