2406 lines
68 KiB
JavaScript
2406 lines
68 KiB
JavaScript
(function (window, document) {
|
||
'use strict';
|
||
|
||
var instances = {};
|
||
var documentClickBound = false;
|
||
|
||
function getElement(id) {
|
||
return id ? document.getElementById(id) : null;
|
||
}
|
||
|
||
function toArray(value) {
|
||
return Array.isArray(value) ? value : [];
|
||
}
|
||
|
||
function asBoolean(value) {
|
||
return value === true || value === 'true' || value === 1 || value === '1';
|
||
}
|
||
|
||
function normalizeText(value) {
|
||
return value === null || value === undefined ? '' : String(value);
|
||
}
|
||
|
||
function getProperty(source, propertyName) {
|
||
if (!source || !propertyName) {
|
||
return undefined;
|
||
}
|
||
|
||
if (Object.prototype.hasOwnProperty.call(source, propertyName)) {
|
||
return source[propertyName];
|
||
}
|
||
|
||
var requestedName = String(propertyName).toLowerCase();
|
||
var keys = Object.keys(source);
|
||
|
||
for (var index = 0; index < keys.length; index += 1) {
|
||
if (keys[index].toLowerCase() === requestedName) {
|
||
return source[keys[index]];
|
||
}
|
||
}
|
||
|
||
return undefined;
|
||
}
|
||
|
||
function getColumnName(column) {
|
||
return normalizeText(
|
||
getProperty(column, 'ColumnName') ||
|
||
getProperty(column, 'Name')
|
||
);
|
||
}
|
||
|
||
function getColumnTitle(column) {
|
||
return normalizeText(
|
||
getProperty(column, 'DisplayName') ||
|
||
getProperty(column, 'Title') ||
|
||
getProperty(column, 'HeaderText') ||
|
||
getColumnName(column)
|
||
);
|
||
}
|
||
|
||
function normalizeSortOrders(config, value) {
|
||
var rawValue = value;
|
||
|
||
if (typeof rawValue === 'string') {
|
||
try {
|
||
rawValue = rawValue
|
||
? JSON.parse(rawValue)
|
||
: [];
|
||
} catch (error) {
|
||
rawValue = [];
|
||
}
|
||
}
|
||
|
||
var allowedColumns = {};
|
||
|
||
toArray(config.resultColumns).forEach(function (column) {
|
||
var columnName = getColumnName(column);
|
||
|
||
if (columnName) {
|
||
allowedColumns[columnName.toLowerCase()] =
|
||
columnName;
|
||
}
|
||
});
|
||
|
||
var addedColumns = {};
|
||
var result = [];
|
||
|
||
toArray(rawValue).forEach(function (order) {
|
||
var requestedColumn = normalizeText(
|
||
getProperty(order, 'Columna')
|
||
);
|
||
|
||
var normalizedColumn =
|
||
allowedColumns[
|
||
requestedColumn.toLowerCase()
|
||
];
|
||
|
||
if (
|
||
!normalizedColumn ||
|
||
addedColumns[
|
||
normalizedColumn.toLowerCase()
|
||
]
|
||
) {
|
||
return;
|
||
}
|
||
|
||
addedColumns[
|
||
normalizedColumn.toLowerCase()
|
||
] = true;
|
||
|
||
result.push({
|
||
Columna: normalizedColumn,
|
||
Descendente: asBoolean(
|
||
getProperty(
|
||
order,
|
||
'Descendente'
|
||
)
|
||
)
|
||
});
|
||
});
|
||
|
||
return result;
|
||
}
|
||
|
||
function saveSortOrders(instance) {
|
||
if (!instance.elements.sortOrders) {
|
||
return;
|
||
}
|
||
|
||
instance.elements.sortOrders.value =
|
||
JSON.stringify(
|
||
instance.sortOrders
|
||
);
|
||
}
|
||
|
||
function findSortOrderIndex(
|
||
instance,
|
||
columnName
|
||
) {
|
||
var requestedColumn =
|
||
normalizeText(
|
||
columnName
|
||
).toLowerCase();
|
||
|
||
for (
|
||
var index = 0;
|
||
index < instance.sortOrders.length;
|
||
index += 1
|
||
) {
|
||
if (
|
||
normalizeText(
|
||
instance.sortOrders[index].Columna
|
||
).toLowerCase() ===
|
||
requestedColumn
|
||
) {
|
||
return index;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
function refreshSortHeaders(instance) {
|
||
var headers =
|
||
instance.elements.results.
|
||
querySelectorAll(
|
||
'.ucbc-sortable-header'
|
||
);
|
||
|
||
for (
|
||
var index = 0;
|
||
index < headers.length;
|
||
index += 1
|
||
) {
|
||
var header = headers[index];
|
||
var columnName =
|
||
normalizeText(
|
||
header.getAttribute(
|
||
'data-column'
|
||
)
|
||
);
|
||
|
||
var orderIndex =
|
||
findSortOrderIndex(
|
||
instance,
|
||
columnName
|
||
);
|
||
|
||
var active =
|
||
orderIndex >= 0;
|
||
|
||
var order =
|
||
active
|
||
? instance.sortOrders[
|
||
orderIndex
|
||
]
|
||
: null;
|
||
|
||
var titleButton =
|
||
header.querySelector(
|
||
'.ucbc-sort-title'
|
||
);
|
||
|
||
var direction =
|
||
header.querySelector(
|
||
'.ucbc-sort-direction'
|
||
);
|
||
|
||
var priority =
|
||
header.querySelector(
|
||
'.ucbc-sort-priority'
|
||
);
|
||
|
||
var removeButton =
|
||
header.querySelector(
|
||
'.ucbc-sort-remove'
|
||
);
|
||
|
||
header.classList.toggle(
|
||
'ucbc-sortable-header-active',
|
||
active
|
||
);
|
||
|
||
header.setAttribute(
|
||
'aria-sort',
|
||
!active
|
||
? 'none'
|
||
: order.Descendente
|
||
? 'descending'
|
||
: 'ascending'
|
||
);
|
||
|
||
if (direction) {
|
||
direction.textContent =
|
||
!active
|
||
? ''
|
||
: order.Descendente
|
||
? '▼'
|
||
: '▲';
|
||
}
|
||
|
||
if (priority) {
|
||
priority.textContent =
|
||
active
|
||
? String(orderIndex + 1)
|
||
: '';
|
||
|
||
priority.hidden = !active;
|
||
}
|
||
|
||
if (removeButton) {
|
||
removeButton.hidden = !active;
|
||
removeButton.title =
|
||
active
|
||
? 'Quitar este orden'
|
||
: '';
|
||
}
|
||
|
||
if (titleButton) {
|
||
titleButton.disabled =
|
||
instance.loading;
|
||
|
||
titleButton.title =
|
||
!active
|
||
? 'Ordenar ascendente'
|
||
: order.Descendente
|
||
? 'Cambiar a orden ascendente'
|
||
: 'Cambiar a orden descendente';
|
||
}
|
||
|
||
if (removeButton) {
|
||
removeButton.disabled =
|
||
instance.loading;
|
||
}
|
||
}
|
||
}
|
||
|
||
function toggleSortOrder(
|
||
instance,
|
||
columnName
|
||
) {
|
||
if (instance.loading) {
|
||
return;
|
||
}
|
||
|
||
var orderIndex =
|
||
findSortOrderIndex(
|
||
instance,
|
||
columnName
|
||
);
|
||
|
||
if (orderIndex < 0) {
|
||
instance.sortOrders.push({
|
||
Columna: columnName,
|
||
Descendente: false
|
||
});
|
||
} else {
|
||
instance.sortOrders[
|
||
orderIndex
|
||
].Descendente =
|
||
!instance.sortOrders[
|
||
orderIndex
|
||
].Descendente;
|
||
}
|
||
|
||
saveSortOrders(instance);
|
||
refreshSortHeaders(instance);
|
||
|
||
executeSearch(
|
||
instance,
|
||
1,
|
||
'top'
|
||
);
|
||
}
|
||
|
||
function removeSortOrder(
|
||
instance,
|
||
columnName
|
||
) {
|
||
if (instance.loading) {
|
||
return;
|
||
}
|
||
|
||
var orderIndex =
|
||
findSortOrderIndex(
|
||
instance,
|
||
columnName
|
||
);
|
||
|
||
if (orderIndex < 0) {
|
||
return;
|
||
}
|
||
|
||
instance.sortOrders.splice(
|
||
orderIndex,
|
||
1
|
||
);
|
||
|
||
saveSortOrders(instance);
|
||
refreshSortHeaders(instance);
|
||
|
||
executeSearch(
|
||
instance,
|
||
1,
|
||
'top'
|
||
);
|
||
}
|
||
|
||
function createSortHeader(
|
||
instance,
|
||
column
|
||
) {
|
||
var columnName =
|
||
getColumnName(column);
|
||
|
||
var header =
|
||
document.createElement('th');
|
||
|
||
header.scope = 'col';
|
||
header.className =
|
||
'ucbc-sortable-header';
|
||
|
||
header.setAttribute(
|
||
'data-column',
|
||
columnName
|
||
);
|
||
|
||
var content =
|
||
createElement(
|
||
'div',
|
||
'ucbc-sort-header-content'
|
||
);
|
||
|
||
var titleButton =
|
||
createElement(
|
||
'button',
|
||
'ucbc-sort-title'
|
||
);
|
||
|
||
titleButton.type = 'button';
|
||
|
||
titleButton.textContent =
|
||
getColumnTitle(column);
|
||
|
||
titleButton.addEventListener(
|
||
'click',
|
||
function (event) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
|
||
toggleSortOrder(
|
||
instance,
|
||
columnName
|
||
);
|
||
}
|
||
);
|
||
|
||
var indicators =
|
||
createElement(
|
||
'span',
|
||
'ucbc-sort-indicators'
|
||
);
|
||
|
||
var direction =
|
||
createElement(
|
||
'span',
|
||
'ucbc-sort-direction'
|
||
);
|
||
|
||
direction.setAttribute(
|
||
'aria-hidden',
|
||
'true'
|
||
);
|
||
|
||
var priority =
|
||
createElement(
|
||
'span',
|
||
'ucbc-sort-priority'
|
||
);
|
||
|
||
priority.setAttribute(
|
||
'aria-label',
|
||
'Prioridad de orden'
|
||
);
|
||
|
||
priority.hidden = true;
|
||
|
||
var removeButton =
|
||
createElement(
|
||
'button',
|
||
'ucbc-sort-remove'
|
||
);
|
||
|
||
removeButton.type = 'button';
|
||
removeButton.textContent = '×';
|
||
removeButton.hidden = true;
|
||
|
||
removeButton.setAttribute(
|
||
'aria-label',
|
||
'Quitar orden de ' +
|
||
getColumnTitle(column)
|
||
);
|
||
|
||
removeButton.addEventListener(
|
||
'click',
|
||
function (event) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
|
||
removeSortOrder(
|
||
instance,
|
||
columnName
|
||
);
|
||
}
|
||
);
|
||
|
||
indicators.appendChild(
|
||
direction
|
||
);
|
||
|
||
indicators.appendChild(
|
||
priority
|
||
);
|
||
|
||
content.appendChild(
|
||
titleButton
|
||
);
|
||
|
||
content.appendChild(
|
||
indicators
|
||
);
|
||
|
||
content.appendChild(
|
||
removeButton
|
||
);
|
||
|
||
header.appendChild(
|
||
content
|
||
);
|
||
|
||
return header;
|
||
}
|
||
|
||
function isSearchColumn(column) {
|
||
var value = getProperty(column, 'ForSearch');
|
||
return value === undefined ? true : asBoolean(value);
|
||
}
|
||
|
||
function clearChildren(element) {
|
||
if (!element) {
|
||
return;
|
||
}
|
||
|
||
while (element.firstChild) {
|
||
element.removeChild(element.firstChild);
|
||
}
|
||
}
|
||
|
||
function setVisible(element, visible) {
|
||
if (!element) {
|
||
return;
|
||
}
|
||
|
||
element.hidden = !visible;
|
||
}
|
||
|
||
function createElement(tagName, className) {
|
||
var element = document.createElement(tagName);
|
||
|
||
if (className) {
|
||
element.className = className;
|
||
}
|
||
|
||
return element;
|
||
}
|
||
|
||
function ensureClientElements(instance) {
|
||
var root = instance.root;
|
||
|
||
var clearButton = root.querySelector('[data-ucbc-role="clear"]');
|
||
if (!clearButton) {
|
||
clearButton = createElement('button', 'ucbc-button ucbc-clear-button');
|
||
clearButton.type = 'button';
|
||
clearButton.setAttribute('data-ucbc-role', 'clear');
|
||
clearButton.setAttribute('aria-label', 'Quitar selección');
|
||
clearButton.title = 'Quitar selección';
|
||
clearButton.textContent = '×';
|
||
|
||
if (instance.elements.selectedText &&
|
||
instance.elements.selectedText.parentNode === root) {
|
||
root.insertBefore(
|
||
clearButton,
|
||
instance.elements.selectedText.nextSibling
|
||
);
|
||
} else {
|
||
root.appendChild(clearButton);
|
||
}
|
||
}
|
||
|
||
var selectedColumnLabel = root.querySelector('[data-ucbc-role="selected-column-label"]');
|
||
if (!selectedColumnLabel) {
|
||
selectedColumnLabel = createElement('span', 'ucbc-selected-column-label');
|
||
selectedColumnLabel.setAttribute('data-ucbc-role', 'selected-column-label');
|
||
selectedColumnLabel.hidden = true;
|
||
root.appendChild(selectedColumnLabel);
|
||
}
|
||
|
||
var panel = root.querySelector('[data-ucbc-role="panel"]');
|
||
if (!panel) {
|
||
panel = createElement('div', 'ucbc-panel');
|
||
panel.setAttribute('data-ucbc-role', 'panel');
|
||
panel.hidden = true;
|
||
root.appendChild(panel);
|
||
}
|
||
|
||
var columnMenu = panel.querySelector('[data-ucbc-role="column-menu"]');
|
||
if (!columnMenu) {
|
||
columnMenu = createElement('div', 'ucbc-column-menu');
|
||
columnMenu.setAttribute('data-ucbc-role', 'column-menu');
|
||
columnMenu.hidden = true;
|
||
panel.appendChild(columnMenu);
|
||
}
|
||
|
||
var status = panel.querySelector('[data-ucbc-role="status"]');
|
||
if (!status) {
|
||
status = createElement('div', 'ucbc-status');
|
||
status.setAttribute('data-ucbc-role', 'status');
|
||
status.setAttribute('aria-live', 'polite');
|
||
status.hidden = true;
|
||
panel.appendChild(status);
|
||
}
|
||
|
||
var results = panel.querySelector('[data-ucbc-role="results"]');
|
||
if (!results) {
|
||
results = createElement('div', 'ucbc-results');
|
||
results.setAttribute('data-ucbc-role', 'results');
|
||
panel.appendChild(results);
|
||
}
|
||
|
||
var footer = panel.querySelector('[data-ucbc-role="footer"]');
|
||
if (!footer) {
|
||
footer = createElement('div', 'ucbc-footer');
|
||
footer.setAttribute('data-ucbc-role', 'footer');
|
||
footer.hidden = true;
|
||
panel.appendChild(footer);
|
||
}
|
||
|
||
var firstButton = footer.querySelector('[data-ucbc-role="first"]');
|
||
if (!firstButton) {
|
||
firstButton = createElement('button', 'ucbc-button ucbc-page-button');
|
||
firstButton.type = 'button';
|
||
firstButton.setAttribute('data-ucbc-role', 'first');
|
||
firstButton.textContent = 'Inicio';
|
||
footer.appendChild(firstButton);
|
||
}
|
||
|
||
var previousButton = footer.querySelector('[data-ucbc-role="previous"]');
|
||
if (!previousButton) {
|
||
previousButton = createElement('button', 'ucbc-button ucbc-page-button');
|
||
previousButton.type = 'button';
|
||
previousButton.setAttribute('data-ucbc-role', 'previous');
|
||
previousButton.textContent = 'Anterior';
|
||
footer.appendChild(previousButton);
|
||
}
|
||
|
||
var pageLabel = footer.querySelector('[data-ucbc-role="page-label"]');
|
||
if (!pageLabel) {
|
||
pageLabel = createElement('span', 'ucbc-page-label');
|
||
pageLabel.setAttribute('data-ucbc-role', 'page-label');
|
||
footer.appendChild(pageLabel);
|
||
}
|
||
|
||
var nextButton = footer.querySelector('[data-ucbc-role="next"]');
|
||
if (!nextButton) {
|
||
nextButton = createElement('button', 'ucbc-button ucbc-page-button');
|
||
nextButton.type = 'button';
|
||
nextButton.setAttribute('data-ucbc-role', 'next');
|
||
nextButton.textContent = 'Siguiente';
|
||
footer.appendChild(nextButton);
|
||
}
|
||
|
||
var lastButton = footer.querySelector('[data-ucbc-role="last"]');
|
||
if (!lastButton) {
|
||
lastButton = createElement('button', 'ucbc-button ucbc-page-button');
|
||
lastButton.type = 'button';
|
||
lastButton.setAttribute('data-ucbc-role', 'last');
|
||
lastButton.textContent = 'Final';
|
||
footer.appendChild(lastButton);
|
||
}
|
||
|
||
instance.elements.clearButton = clearButton;
|
||
instance.elements.selectedColumnLabel = selectedColumnLabel;
|
||
instance.elements.panel = panel;
|
||
instance.elements.columnMenu = columnMenu;
|
||
instance.elements.status = status;
|
||
instance.elements.results = results;
|
||
instance.elements.footer = footer;
|
||
instance.elements.firstButton = firstButton;
|
||
instance.elements.previousButton = previousButton;
|
||
instance.elements.pageLabel = pageLabel;
|
||
var pageIntentIndicator = panel.querySelector(
|
||
'[data-ucbc-role="page-intent"]'
|
||
);
|
||
|
||
if (!pageIntentIndicator) {
|
||
pageIntentIndicator = createElement(
|
||
'div',
|
||
'ucbc-page-intent'
|
||
);
|
||
|
||
pageIntentIndicator.setAttribute(
|
||
'data-ucbc-role',
|
||
'page-intent'
|
||
);
|
||
|
||
pageIntentIndicator.setAttribute(
|
||
'aria-live',
|
||
'polite'
|
||
);
|
||
|
||
pageIntentIndicator.setAttribute(
|
||
'aria-atomic',
|
||
'true'
|
||
);
|
||
|
||
pageIntentIndicator.hidden = true;
|
||
|
||
var pageIntentArrow = createElement(
|
||
'span',
|
||
'ucbc-page-intent-arrow'
|
||
);
|
||
|
||
pageIntentArrow.setAttribute(
|
||
'data-ucbc-role',
|
||
'page-intent-arrow'
|
||
);
|
||
|
||
var pageIntentLabel = createElement(
|
||
'span',
|
||
'ucbc-page-intent-label'
|
||
);
|
||
|
||
pageIntentLabel.setAttribute(
|
||
'data-ucbc-role',
|
||
'page-intent-label'
|
||
);
|
||
|
||
var pageIntentDots = createElement(
|
||
'span',
|
||
'ucbc-page-intent-dots'
|
||
);
|
||
|
||
pageIntentDots.setAttribute(
|
||
'data-ucbc-role',
|
||
'page-intent-dots'
|
||
);
|
||
|
||
pageIntentIndicator.appendChild(
|
||
pageIntentArrow
|
||
);
|
||
|
||
pageIntentIndicator.appendChild(
|
||
pageIntentLabel
|
||
);
|
||
|
||
pageIntentIndicator.appendChild(
|
||
pageIntentDots
|
||
);
|
||
|
||
panel.appendChild(
|
||
pageIntentIndicator
|
||
);
|
||
}
|
||
|
||
instance.elements.clearButton = clearButton;
|
||
instance.elements.selectedColumnLabel = selectedColumnLabel;
|
||
instance.elements.panel = panel;
|
||
instance.elements.columnMenu = columnMenu;
|
||
instance.elements.status = status;
|
||
instance.elements.results = results;
|
||
instance.elements.footer = footer;
|
||
instance.elements.firstButton = firstButton;
|
||
instance.elements.previousButton = previousButton;
|
||
instance.elements.pageLabel = pageLabel;
|
||
instance.elements.nextButton = nextButton;
|
||
instance.elements.lastButton = lastButton;
|
||
instance.elements.pageIntentIndicator =
|
||
pageIntentIndicator;
|
||
instance.elements.pageIntentArrow =
|
||
pageIntentIndicator.querySelector(
|
||
'[data-ucbc-role="page-intent-arrow"]'
|
||
);
|
||
instance.elements.pageIntentLabel =
|
||
pageIntentIndicator.querySelector(
|
||
'[data-ucbc-role="page-intent-label"]'
|
||
);
|
||
instance.elements.pageIntentDots =
|
||
pageIntentIndicator.querySelector(
|
||
'[data-ucbc-role="page-intent-dots"]'
|
||
);
|
||
}
|
||
|
||
function getPageTurnSteps(instance) {
|
||
return Math.max(
|
||
1,
|
||
Number(instance.config.pageTurnSteps) || 3
|
||
);
|
||
}
|
||
|
||
function ensurePageIntentDots(instance) {
|
||
var dotsContainer =
|
||
instance.elements.pageIntentDots;
|
||
|
||
if (!dotsContainer) {
|
||
return;
|
||
}
|
||
|
||
var requiredSteps =
|
||
getPageTurnSteps(instance);
|
||
|
||
if (
|
||
dotsContainer.children.length ===
|
||
requiredSteps
|
||
) {
|
||
return;
|
||
}
|
||
|
||
clearChildren(dotsContainer);
|
||
|
||
for (
|
||
var index = 0;
|
||
index < requiredSteps;
|
||
index += 1
|
||
) {
|
||
dotsContainer.appendChild(
|
||
createElement(
|
||
'span',
|
||
'ucbc-page-intent-dot'
|
||
)
|
||
);
|
||
}
|
||
}
|
||
|
||
function hidePageTurnIndicator(instance) {
|
||
var indicator =
|
||
instance.elements.pageIntentIndicator;
|
||
|
||
if (!indicator) {
|
||
return;
|
||
}
|
||
|
||
indicator.classList.remove(
|
||
'ucbc-page-intent-visible',
|
||
'ucbc-page-intent-next',
|
||
'ucbc-page-intent-previous',
|
||
'ucbc-page-intent-complete'
|
||
);
|
||
|
||
indicator.hidden = true;
|
||
}
|
||
|
||
function updatePageTurnIndicator(
|
||
instance,
|
||
completed
|
||
) {
|
||
var state = instance.pageTurnIntent;
|
||
var indicator =
|
||
instance.elements.pageIntentIndicator;
|
||
|
||
if (
|
||
!state ||
|
||
!indicator ||
|
||
state.direction === 0
|
||
) {
|
||
return;
|
||
}
|
||
|
||
ensurePageIntentDots(instance);
|
||
|
||
var isNext =
|
||
state.direction === 1;
|
||
|
||
indicator.hidden = false;
|
||
|
||
indicator.classList.remove(
|
||
'ucbc-page-intent-next',
|
||
'ucbc-page-intent-previous',
|
||
'ucbc-page-intent-complete'
|
||
);
|
||
|
||
indicator.classList.add(
|
||
isNext
|
||
? 'ucbc-page-intent-next'
|
||
: 'ucbc-page-intent-previous'
|
||
);
|
||
|
||
indicator.classList.add(
|
||
'ucbc-page-intent-visible'
|
||
);
|
||
|
||
if (completed) {
|
||
indicator.classList.add(
|
||
'ucbc-page-intent-complete'
|
||
);
|
||
}
|
||
|
||
instance.elements.pageIntentArrow.textContent =
|
||
isNext ? '↓' : '↑';
|
||
|
||
if (completed) {
|
||
instance.elements.pageIntentLabel.textContent =
|
||
isNext
|
||
? 'Cambiando a la siguiente página...'
|
||
: 'Cambiando a la página anterior...';
|
||
} else {
|
||
instance.elements.pageIntentLabel.textContent =
|
||
(
|
||
isNext
|
||
? 'Siguiente página'
|
||
: 'Página anterior'
|
||
) +
|
||
' · ' +
|
||
state.steps +
|
||
' de ' +
|
||
getPageTurnSteps(instance);
|
||
}
|
||
|
||
var dots =
|
||
instance.elements.pageIntentDots.children;
|
||
|
||
for (
|
||
var index = 0;
|
||
index < dots.length;
|
||
index += 1
|
||
) {
|
||
dots[index].classList.toggle(
|
||
'ucbc-page-intent-dot-active',
|
||
completed || index < state.steps
|
||
);
|
||
}
|
||
}
|
||
|
||
function resetPageTurnState(
|
||
instance,
|
||
keepChangingPage
|
||
) {
|
||
var state = instance.pageTurnIntent;
|
||
|
||
if (!state) {
|
||
return;
|
||
}
|
||
|
||
if (state.resetTimer) {
|
||
window.clearTimeout(
|
||
state.resetTimer
|
||
);
|
||
|
||
state.resetTimer = null;
|
||
}
|
||
|
||
state.direction = 0;
|
||
state.steps = 0;
|
||
state.accumulatedDelta = 0;
|
||
state.lastStepAt = 0;
|
||
|
||
if (!keepChangingPage) {
|
||
state.changingPage = false;
|
||
}
|
||
}
|
||
|
||
function cancelPageTurnIntent(instance) {
|
||
if (!instance.pageTurnIntent) {
|
||
return;
|
||
}
|
||
|
||
resetPageTurnState(
|
||
instance,
|
||
false
|
||
);
|
||
|
||
hidePageTurnIndicator(instance);
|
||
}
|
||
|
||
function restartPageTurnResetTimer(instance) {
|
||
var state = instance.pageTurnIntent;
|
||
|
||
if (!state) {
|
||
return;
|
||
}
|
||
|
||
if (state.resetTimer) {
|
||
window.clearTimeout(
|
||
state.resetTimer
|
||
);
|
||
}
|
||
|
||
state.resetTimer =
|
||
window.setTimeout(
|
||
function () {
|
||
cancelPageTurnIntent(instance);
|
||
},
|
||
instance.config
|
||
.pageTurnResetMilliseconds
|
||
);
|
||
}
|
||
|
||
function normalizePageTurnDelta(
|
||
event,
|
||
resultsElement
|
||
) {
|
||
var delta = Number(event.deltaY) || 0;
|
||
|
||
if (event.deltaMode === 1) {
|
||
delta *= 16;
|
||
} else if (event.deltaMode === 2) {
|
||
delta *= resultsElement.clientHeight;
|
||
}
|
||
|
||
return delta;
|
||
}
|
||
|
||
function executePageTurn(
|
||
instance,
|
||
direction
|
||
) {
|
||
var state = instance.pageTurnIntent;
|
||
|
||
if (
|
||
!state ||
|
||
state.changingPage ||
|
||
instance.loading
|
||
) {
|
||
return;
|
||
}
|
||
|
||
state.changingPage = true;
|
||
|
||
if (state.resetTimer) {
|
||
window.clearTimeout(
|
||
state.resetTimer
|
||
);
|
||
|
||
state.resetTimer = null;
|
||
}
|
||
|
||
updatePageTurnIndicator(
|
||
instance,
|
||
true
|
||
);
|
||
|
||
window.setTimeout(
|
||
function () {
|
||
var targetPage =
|
||
direction === 1
|
||
? instance.page + 1
|
||
: instance.page - 1;
|
||
|
||
var restoreScroll =
|
||
direction === 1
|
||
? 'top'
|
||
: 'bottom';
|
||
|
||
resetPageTurnState(
|
||
instance,
|
||
true
|
||
);
|
||
|
||
hidePageTurnIndicator(instance);
|
||
|
||
executeSearch(
|
||
instance,
|
||
targetPage,
|
||
restoreScroll
|
||
);
|
||
},
|
||
220
|
||
);
|
||
}
|
||
|
||
function handlePageTurnWheel(
|
||
instance,
|
||
event
|
||
) {
|
||
var state = instance.pageTurnIntent;
|
||
var results = instance.elements.results;
|
||
|
||
if (
|
||
!state ||
|
||
instance.loading ||
|
||
state.changingPage ||
|
||
getTotalPages(instance) <= 1
|
||
) {
|
||
return;
|
||
}
|
||
|
||
var delta =
|
||
normalizePageTurnDelta(
|
||
event,
|
||
results
|
||
);
|
||
|
||
if (delta === 0) {
|
||
return;
|
||
}
|
||
|
||
var direction =
|
||
delta > 0 ? 1 : -1;
|
||
|
||
var edgeTolerance = 2;
|
||
|
||
var atTop =
|
||
results.scrollTop <=
|
||
edgeTolerance;
|
||
|
||
var atBottom =
|
||
results.scrollTop +
|
||
results.clientHeight >=
|
||
results.scrollHeight -
|
||
edgeTolerance;
|
||
|
||
var canGoNext =
|
||
direction === 1 &&
|
||
atBottom &&
|
||
instance.hasMore;
|
||
|
||
var canGoPrevious =
|
||
direction === -1 &&
|
||
atTop &&
|
||
instance.page > 1;
|
||
|
||
if (
|
||
state.direction !== 0 &&
|
||
state.direction !== direction
|
||
) {
|
||
cancelPageTurnIntent(instance);
|
||
return;
|
||
}
|
||
|
||
if (!canGoNext && !canGoPrevious) {
|
||
if (state.direction !== 0) {
|
||
cancelPageTurnIntent(instance);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
event.preventDefault();
|
||
|
||
if (state.direction === 0) {
|
||
state.direction = direction;
|
||
state.steps = 0;
|
||
state.accumulatedDelta = 0;
|
||
state.lastStepAt = 0;
|
||
}
|
||
|
||
restartPageTurnResetTimer(instance);
|
||
|
||
state.accumulatedDelta +=
|
||
Math.abs(delta);
|
||
|
||
updatePageTurnIndicator(
|
||
instance,
|
||
false
|
||
);
|
||
|
||
var now = Date.now();
|
||
|
||
if (
|
||
state.accumulatedDelta <
|
||
instance.config.pageTurnDeltaThreshold
|
||
) {
|
||
return;
|
||
}
|
||
|
||
if (
|
||
state.lastStepAt > 0 &&
|
||
now - state.lastStepAt <
|
||
instance.config.pageTurnStepDelay
|
||
) {
|
||
return;
|
||
}
|
||
|
||
state.accumulatedDelta = 0;
|
||
state.lastStepAt = now;
|
||
state.steps += 1;
|
||
|
||
updatePageTurnIndicator(
|
||
instance,
|
||
false
|
||
);
|
||
|
||
if (
|
||
state.steps >=
|
||
getPageTurnSteps(instance)
|
||
) {
|
||
executePageTurn(
|
||
instance,
|
||
direction
|
||
);
|
||
}
|
||
}
|
||
|
||
function setStatus(instance, message, statusType) {
|
||
var status = instance.elements.status;
|
||
|
||
status.textContent = normalizeText(message);
|
||
status.className = 'ucbc-status';
|
||
|
||
if (statusType) {
|
||
status.className += ' ucbc-status-' + statusType;
|
||
}
|
||
|
||
setVisible(status, Boolean(message));
|
||
}
|
||
|
||
function showPanel(instance) {
|
||
setVisible(instance.elements.panel, true);
|
||
}
|
||
|
||
function hidePanel(instance) {
|
||
cancelPageTurnIntent(instance);
|
||
setVisible(instance.elements.panel, false);
|
||
setVisible(instance.elements.columnMenu, false);
|
||
}
|
||
|
||
function updateSelectedState(instance) {
|
||
var selectedValue = normalizeText(instance.elements.selectedValue.value);
|
||
var hasSelection = selectedValue.length > 0;
|
||
|
||
setVisible(instance.elements.clearButton, hasSelection && instance.enabled);
|
||
instance.root.classList.toggle('ucbc-has-selection', hasSelection);
|
||
}
|
||
|
||
function getSelectedColumn(instance) {
|
||
var column = normalizeText(instance.elements.selectedColumn.value);
|
||
|
||
if (!column) {
|
||
column = instance.config.allColumnsValue;
|
||
instance.elements.selectedColumn.value = column;
|
||
}
|
||
|
||
return column;
|
||
}
|
||
|
||
function findConfiguredColumn(instance, columnName) {
|
||
var columns = toArray(instance.config.columns);
|
||
|
||
for (var index = 0; index < columns.length; index += 1) {
|
||
if (getColumnName(columns[index]).toLowerCase() === normalizeText(columnName).toLowerCase()) {
|
||
return columns[index];
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function updateSelectedColumnPresentation(instance) {
|
||
var selectedColumn = getSelectedColumn(instance);
|
||
var isAllColumns = selectedColumn.toLowerCase() === normalizeText(instance.config.allColumnsValue).toLowerCase();
|
||
var title = 'Todos los campos';
|
||
|
||
if (!isAllColumns) {
|
||
var column = findConfiguredColumn(instance, selectedColumn);
|
||
title = column ? getColumnTitle(column) : selectedColumn;
|
||
}
|
||
|
||
instance.elements.columnsButton.title = 'Buscar por: ' + title;
|
||
instance.elements.columnsButton.setAttribute('aria-label', 'Buscar por: ' + title);
|
||
instance.elements.selectedColumnLabel.textContent = title;
|
||
}
|
||
|
||
function positionColumnMenu(instance) {
|
||
var menu = instance.elements.columnMenu;
|
||
var button = instance.elements.columnsButton;
|
||
var panel = instance.elements.panel;
|
||
|
||
if (!menu || !button || !panel || menu.hidden || panel.hidden) {
|
||
return;
|
||
}
|
||
|
||
var buttonRect = button.getBoundingClientRect();
|
||
var panelRect = panel.getBoundingClientRect();
|
||
var requestedLeft = buttonRect.left - panelRect.left;
|
||
var maximumLeft = Math.max(0, panel.clientWidth - menu.offsetWidth);
|
||
var left = Math.max(0, Math.min(requestedLeft, maximumLeft));
|
||
|
||
menu.style.right = 'auto';
|
||
menu.style.left = Math.round(left) + 'px';
|
||
menu.style.top = '0px';
|
||
}
|
||
|
||
function positionUserFilterPanel(instance) {
|
||
var panel = instance.root.querySelector(
|
||
'.ucbc-user-filter-panel'
|
||
);
|
||
var button = instance.elements.userFiltersButton;
|
||
var root = instance.root;
|
||
|
||
if (!panel || !button || !root) {
|
||
return;
|
||
}
|
||
|
||
if (window.innerWidth <= 720) {
|
||
panel.style.removeProperty('top');
|
||
panel.style.removeProperty('right');
|
||
panel.style.removeProperty('left');
|
||
return;
|
||
}
|
||
|
||
var rootRect = root.getBoundingClientRect();
|
||
var buttonRect = button.getBoundingClientRect();
|
||
var requestedLeft = buttonRect.left - rootRect.left;
|
||
var maximumLeft = Math.max(
|
||
0,
|
||
root.clientWidth - panel.offsetWidth
|
||
);
|
||
var left = Math.max(
|
||
0,
|
||
Math.min(requestedLeft, maximumLeft)
|
||
);
|
||
var top = buttonRect.bottom - rootRect.top + 5;
|
||
|
||
panel.style.right = 'auto';
|
||
panel.style.left = Math.round(left) + 'px';
|
||
panel.style.top = Math.round(top) + 'px';
|
||
}
|
||
|
||
function renderColumnMenu(instance) {
|
||
var menu = instance.elements.columnMenu;
|
||
clearChildren(menu);
|
||
|
||
var list = createElement('div', 'ucbc-column-options');
|
||
var selectedColumn = getSelectedColumn(instance);
|
||
|
||
function appendOption(value, text) {
|
||
var button = createElement('button', 'ucbc-column-option');
|
||
button.type = 'button';
|
||
button.textContent = text;
|
||
button.setAttribute('data-column', value);
|
||
|
||
if (normalizeText(value).toLowerCase() === selectedColumn.toLowerCase()) {
|
||
button.classList.add('ucbc-column-option-selected');
|
||
button.setAttribute('aria-pressed', 'true');
|
||
} else {
|
||
button.setAttribute('aria-pressed', 'false');
|
||
}
|
||
|
||
button.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
instance.elements.selectedColumn.value = value;
|
||
updateSelectedColumnPresentation(instance);
|
||
renderColumnMenu(instance);
|
||
setVisible(menu, false);
|
||
|
||
if (instance.elements.searchInput.value.trim().length >= instance.config.minimumCharacters) {
|
||
executeSearch(instance, 1);
|
||
}
|
||
});
|
||
|
||
list.appendChild(button);
|
||
}
|
||
|
||
appendOption(instance.config.allColumnsValue, 'Todos los campos');
|
||
|
||
toArray(instance.config.columns)
|
||
.filter(isSearchColumn)
|
||
.forEach(function (column) {
|
||
appendOption(getColumnName(column), getColumnTitle(column));
|
||
});
|
||
|
||
menu.appendChild(list);
|
||
}
|
||
|
||
function getTotalPages(instance) {
|
||
return instance.totalRecords > 0
|
||
? Math.ceil(instance.totalRecords / instance.config.pageSize)
|
||
: 0;
|
||
}
|
||
|
||
function setLoading(instance, isLoading) {
|
||
instance.loading = isLoading;
|
||
instance.root.classList.toggle('ucbc-loading', isLoading);
|
||
instance.elements.searchInput.setAttribute('aria-busy', isLoading ? 'true' : 'false');
|
||
instance.elements.searchButton.disabled = !instance.enabled || isLoading;
|
||
instance.elements.columnsButton.disabled = !instance.enabled || isLoading;
|
||
var totalPages = getTotalPages(instance);
|
||
instance.elements.firstButton.disabled = isLoading || instance.page <= 1;
|
||
instance.elements.previousButton.disabled = isLoading || instance.page <= 1;
|
||
instance.elements.nextButton.disabled = isLoading || !instance.hasMore;
|
||
instance.elements.lastButton.disabled = isLoading || totalPages <= 1 || instance.page >= totalPages;
|
||
|
||
if (isLoading) {
|
||
setStatus(instance, 'Buscando...', 'loading');
|
||
} else if (instance.pageTurnIntent) {
|
||
instance.pageTurnIntent.changingPage = false;
|
||
}
|
||
|
||
refreshSortHeaders(instance);
|
||
}
|
||
|
||
function resetResults(instance) {
|
||
cancelPageTurnIntent(instance);
|
||
instance.items = [];
|
||
instance.page = 1;
|
||
instance.totalRecords = 0;
|
||
instance.hasMore = false;
|
||
instance.restoreScroll = null;
|
||
clearChildren(instance.elements.results);
|
||
setVisible(instance.elements.footer, false);
|
||
}
|
||
|
||
function updatePager(instance) {
|
||
var totalPages = getTotalPages(instance);
|
||
|
||
var showFooter = instance.page > 1 || instance.hasMore || instance.totalRecords > 0;
|
||
setVisible(instance.elements.footer, showFooter);
|
||
|
||
instance.elements.firstButton.disabled = instance.loading || instance.page <= 1;
|
||
instance.elements.previousButton.disabled = instance.loading || instance.page <= 1;
|
||
instance.elements.nextButton.disabled = instance.loading || !instance.hasMore;
|
||
instance.elements.lastButton.disabled = instance.loading || totalPages <= 1 || instance.page >= totalPages;
|
||
|
||
if (totalPages > 0) {
|
||
instance.elements.pageLabel.textContent =
|
||
'Página ' + instance.page + ' de ' + totalPages +
|
||
' · ' + instance.totalRecords + ' registro(s)';
|
||
} else {
|
||
instance.elements.pageLabel.textContent = '';
|
||
}
|
||
}
|
||
|
||
function createCell(value) {
|
||
var cell = document.createElement('td');
|
||
cell.textContent = normalizeText(value);
|
||
return cell;
|
||
}
|
||
|
||
function selectItem(instance, item) {
|
||
var selectedValue = normalizeText(getProperty(item, '__SelectedValue'));
|
||
var displayText = normalizeText(getProperty(item, '__DisplayText'));
|
||
|
||
instance.elements.selectedValue.value = selectedValue;
|
||
instance.elements.selectedJson.value = JSON.stringify(item || {});
|
||
instance.elements.selectedText.value = displayText || selectedValue;
|
||
|
||
updateSelectedState(instance);
|
||
hidePanel(instance);
|
||
resetResults(instance);
|
||
setStatus(instance, '', null);
|
||
|
||
if (typeof instance.postBack === 'function') {
|
||
instance.postBack('select');
|
||
}
|
||
}
|
||
|
||
|
||
function getVisibleResultColumns(instance) {
|
||
var resultColumns = toArray(instance.config.resultColumns);
|
||
var displayColumns = toArray(instance.config.displayColumns);
|
||
|
||
if (!displayColumns.length) {
|
||
return resultColumns;
|
||
}
|
||
|
||
return displayColumns
|
||
.map(function (displayColumn) {
|
||
if (typeof displayColumn !== 'string') {
|
||
return displayColumn;
|
||
}
|
||
|
||
var requestedName = normalizeText(displayColumn).toLowerCase();
|
||
|
||
for (var index = 0; index < resultColumns.length; index += 1) {
|
||
if (getColumnName(resultColumns[index]).toLowerCase() === requestedName) {
|
||
return resultColumns[index];
|
||
}
|
||
}
|
||
|
||
return {
|
||
ColumnName: displayColumn,
|
||
DisplayName: displayColumn
|
||
};
|
||
})
|
||
.filter(function (column) {
|
||
return Boolean(getColumnName(column));
|
||
});
|
||
}
|
||
|
||
function renderResults(instance) {
|
||
var container = instance.elements.results;
|
||
clearChildren(container);
|
||
|
||
if (!instance.items.length) {
|
||
setStatus(
|
||
instance,
|
||
'No se encontraron resultados.',
|
||
'empty'
|
||
);
|
||
|
||
updatePager(instance);
|
||
return;
|
||
}
|
||
|
||
setStatus(instance, '', null);
|
||
|
||
var visibleColumns =
|
||
getVisibleResultColumns(instance);
|
||
|
||
var table =
|
||
createElement(
|
||
'table',
|
||
'ucbc-results-table'
|
||
);
|
||
|
||
table.setAttribute('role', 'grid');
|
||
|
||
var thead =
|
||
document.createElement('thead');
|
||
|
||
var headerRow =
|
||
document.createElement('tr');
|
||
|
||
visibleColumns.forEach(function (column) {
|
||
headerRow.appendChild(
|
||
createSortHeader(
|
||
instance,
|
||
column
|
||
)
|
||
);
|
||
});
|
||
|
||
thead.appendChild(headerRow);
|
||
table.appendChild(thead);
|
||
|
||
var tbody =
|
||
document.createElement('tbody');
|
||
|
||
instance.items.forEach(
|
||
function (item, itemIndex) {
|
||
var row =
|
||
document.createElement('tr');
|
||
|
||
row.className =
|
||
'ucbc-result-row';
|
||
|
||
row.tabIndex = 0;
|
||
|
||
row.setAttribute(
|
||
'data-index',
|
||
String(itemIndex)
|
||
);
|
||
|
||
visibleColumns.forEach(
|
||
function (column) {
|
||
row.appendChild(
|
||
createCell(
|
||
getProperty(
|
||
item,
|
||
getColumnName(column)
|
||
)
|
||
)
|
||
);
|
||
}
|
||
);
|
||
|
||
row.addEventListener(
|
||
'click',
|
||
function () {
|
||
selectItem(
|
||
instance,
|
||
item
|
||
);
|
||
}
|
||
);
|
||
|
||
row.addEventListener(
|
||
'keydown',
|
||
function (event) {
|
||
if (
|
||
event.key === 'Enter' ||
|
||
event.key === ' '
|
||
) {
|
||
event.preventDefault();
|
||
|
||
selectItem(
|
||
instance,
|
||
item
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
if (
|
||
event.key !== 'ArrowDown' &&
|
||
event.key !== 'ArrowUp'
|
||
) {
|
||
return;
|
||
}
|
||
|
||
var rows =
|
||
container.querySelectorAll(
|
||
'.ucbc-result-row'
|
||
);
|
||
|
||
var currentIndex =
|
||
Number(
|
||
row.getAttribute(
|
||
'data-index'
|
||
)
|
||
);
|
||
|
||
var nextIndex =
|
||
event.key === 'ArrowDown'
|
||
? currentIndex + 1
|
||
: currentIndex - 1;
|
||
|
||
if (
|
||
nextIndex >= 0 &&
|
||
nextIndex < rows.length
|
||
) {
|
||
event.preventDefault();
|
||
rows[nextIndex].focus();
|
||
}
|
||
}
|
||
);
|
||
|
||
tbody.appendChild(row);
|
||
}
|
||
);
|
||
|
||
table.appendChild(tbody);
|
||
container.appendChild(table);
|
||
|
||
refreshSortHeaders(instance);
|
||
updatePager(instance);
|
||
|
||
if (instance.restoreScroll === 'bottom') {
|
||
container.scrollTop =
|
||
container.scrollHeight;
|
||
} else {
|
||
container.scrollTop = 0;
|
||
}
|
||
|
||
instance.restoreScroll = null;
|
||
}
|
||
|
||
function clearSearchTimeout(instance) {
|
||
if (!instance.requestTimeoutTimer) {
|
||
return;
|
||
}
|
||
|
||
window.clearTimeout(
|
||
instance.requestTimeoutTimer
|
||
);
|
||
|
||
instance.requestTimeoutTimer = null;
|
||
}
|
||
|
||
function startSearchTimeout(
|
||
instance,
|
||
requestId
|
||
) {
|
||
clearSearchTimeout(instance);
|
||
|
||
instance.requestTimeoutTimer =
|
||
window.setTimeout(
|
||
function () {
|
||
if (
|
||
requestId !==
|
||
instance.requestId
|
||
) {
|
||
return;
|
||
}
|
||
|
||
instance.requestTimeoutTimer = null;
|
||
|
||
// Invalidate the request so a late server
|
||
// response cannot replace the timeout message.
|
||
instance.requestId += 1;
|
||
|
||
setLoading(instance, false);
|
||
resetResults(instance);
|
||
showPanel(instance);
|
||
setStatus(
|
||
instance,
|
||
'La búsqueda tardó más de ' +
|
||
Math.round(
|
||
instance.config
|
||
.searchTimeoutMilliseconds /
|
||
1000
|
||
) +
|
||
' segundos. Intente nuevamente.',
|
||
'error'
|
||
);
|
||
},
|
||
instance.config
|
||
.searchTimeoutMilliseconds
|
||
);
|
||
}
|
||
|
||
function executeSearch(instance, page, restoreScroll) {
|
||
if (!instance.enabled || instance.loading || typeof instance.callback !== 'function') {
|
||
return;
|
||
}
|
||
|
||
if (
|
||
instance.pageTurnIntent &&
|
||
!instance.pageTurnIntent.changingPage
|
||
) {
|
||
cancelPageTurnIntent(instance);
|
||
}
|
||
|
||
var text = instance.elements.searchInput.value.trim();
|
||
|
||
if (text.length < instance.config.minimumCharacters) {
|
||
resetResults(instance);
|
||
showPanel(instance);
|
||
setStatus(
|
||
instance,
|
||
'Escriba al menos ' + instance.config.minimumCharacters + ' carácter(es) para buscar.',
|
||
'info'
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (instance.timer) {
|
||
window.clearTimeout(instance.timer);
|
||
instance.timer = null;
|
||
}
|
||
|
||
instance.requestId += 1;
|
||
|
||
var currentRequestId =
|
||
instance.requestId;
|
||
|
||
var requestedPage = Math.max(1, Number(page) || 1);
|
||
var totalPages = getTotalPages(instance);
|
||
|
||
if (totalPages > 0) {
|
||
requestedPage = Math.min(requestedPage, totalPages);
|
||
}
|
||
|
||
instance.page = requestedPage;
|
||
instance.restoreScroll = restoreScroll || 'top';
|
||
|
||
var request = {
|
||
Texto: text,
|
||
Columna: getSelectedColumn(instance),
|
||
Pagina: instance.page,
|
||
Ordenes: instance.sortOrders.map(
|
||
function (order) {
|
||
return {
|
||
Columna: order.Columna,
|
||
Descendente:
|
||
order.Descendente
|
||
};
|
||
}
|
||
)
|
||
};
|
||
|
||
showPanel(instance);
|
||
setVisible(instance.elements.columnMenu, false);
|
||
setLoading(instance, true);
|
||
startSearchTimeout(
|
||
instance,
|
||
currentRequestId
|
||
);
|
||
|
||
try {
|
||
instance.callback(
|
||
JSON.stringify(request),
|
||
{
|
||
clientId: instance.config.clientId,
|
||
requestId: currentRequestId
|
||
}
|
||
);
|
||
} catch (error) {
|
||
clearSearchTimeout(instance);
|
||
setLoading(instance, false);
|
||
setStatus(
|
||
instance,
|
||
error && error.message
|
||
? error.message
|
||
: 'No fue posible iniciar la búsqueda.',
|
||
'error'
|
||
);
|
||
}
|
||
}
|
||
|
||
function scheduleSearch(instance) {
|
||
if (!instance.enabled) {
|
||
return;
|
||
}
|
||
|
||
if (instance.timer) {
|
||
window.clearTimeout(instance.timer);
|
||
}
|
||
|
||
instance.timer = window.setTimeout(function () {
|
||
executeSearch(instance, 1);
|
||
}, instance.config.delayMilliseconds);
|
||
}
|
||
|
||
function clearSelection(instance) {
|
||
instance.elements.selectedValue.value = '';
|
||
instance.elements.selectedJson.value = '';
|
||
instance.elements.selectedText.value = '';
|
||
updateSelectedState(instance);
|
||
hidePanel(instance);
|
||
|
||
if (typeof instance.postBack === 'function') {
|
||
instance.postBack('clear');
|
||
}
|
||
}
|
||
|
||
function findUserFilterActionElement(root, target) {
|
||
var current = target;
|
||
|
||
while (current && current !== root) {
|
||
if (current.getAttribute &&
|
||
current.getAttribute('data-ucbc-filter-action')) {
|
||
return current;
|
||
}
|
||
|
||
current = current.parentNode;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function applyUserFilterEditor(instance) {
|
||
var editor = instance.root.querySelector(
|
||
'[data-ucbc-filter-editor-key]'
|
||
);
|
||
|
||
if (!editor || typeof instance.postBack !== 'function') {
|
||
return;
|
||
}
|
||
|
||
var operatorControl = editor.querySelector(
|
||
'[data-ucbc-filter-editor-operator]'
|
||
);
|
||
var valueControl = editor.querySelector(
|
||
'[data-ucbc-filter-editor-value]'
|
||
);
|
||
|
||
if (!valueControl) {
|
||
return;
|
||
}
|
||
|
||
var filterKey = normalizeText(
|
||
editor.getAttribute('data-ucbc-filter-editor-key')
|
||
);
|
||
var operatorValue = operatorControl
|
||
? normalizeText(operatorControl.value)
|
||
: 'Igual';
|
||
var value = normalizeText(valueControl.value);
|
||
var text = value;
|
||
|
||
if (valueControl.tagName &&
|
||
valueControl.tagName.toLowerCase() === 'select') {
|
||
var selectedOption = valueControl.options[
|
||
valueControl.selectedIndex
|
||
];
|
||
|
||
text = selectedOption
|
||
? normalizeText(selectedOption.text)
|
||
: value;
|
||
}
|
||
|
||
instance.elements.userFilterEditorKey.value = filterKey;
|
||
instance.elements.userFilterEditorOperator.value = operatorValue;
|
||
instance.elements.userFilterEditorValue.value = value;
|
||
instance.elements.userFilterEditorText.value = text;
|
||
|
||
instance.postBack('filters:apply');
|
||
}
|
||
|
||
function applyUserFilterListItem(instance, actionElement) {
|
||
if (!actionElement || typeof instance.postBack !== 'function') {
|
||
return;
|
||
}
|
||
|
||
var filterKey = normalizeText(
|
||
actionElement.getAttribute('data-ucbc-filter-key')
|
||
);
|
||
var value = normalizeText(
|
||
actionElement.getAttribute('data-ucbc-filter-value')
|
||
);
|
||
var text = normalizeText(
|
||
actionElement.getAttribute('data-ucbc-filter-text')
|
||
);
|
||
|
||
instance.elements.userFilterEditorKey.value = filterKey;
|
||
instance.elements.userFilterEditorOperator.value = 'Igual';
|
||
instance.elements.userFilterEditorValue.value = value;
|
||
instance.elements.userFilterEditorText.value = text;
|
||
|
||
instance.postBack('filters:apply');
|
||
}
|
||
|
||
function normalizeUserFilterSearchText(value) {
|
||
var normalized = normalizeText(value).toLocaleLowerCase();
|
||
|
||
if (typeof normalized.normalize === 'function') {
|
||
normalized = normalized
|
||
.normalize('NFD')
|
||
.replace(/[\u0300-\u036f]/g, '');
|
||
}
|
||
|
||
return normalized;
|
||
}
|
||
|
||
function filterUserFilterMenu(searchInput) {
|
||
if (!searchInput) {
|
||
return;
|
||
}
|
||
|
||
var editor = searchInput.closest(
|
||
'[data-ucbc-filter-editor-key]'
|
||
);
|
||
|
||
if (!editor) {
|
||
return;
|
||
}
|
||
|
||
var searchValue = normalizeUserFilterSearchText(
|
||
searchInput.value
|
||
);
|
||
var items = editor.querySelectorAll(
|
||
'[data-ucbc-filter-item]'
|
||
);
|
||
var visibleCount = 0;
|
||
|
||
Array.prototype.forEach.call(items, function (item) {
|
||
var itemText = normalizeUserFilterSearchText(
|
||
item.getAttribute('data-ucbc-filter-search-text')
|
||
);
|
||
var visible =
|
||
!searchValue || itemText.indexOf(searchValue) >= 0;
|
||
|
||
item.hidden = !visible;
|
||
|
||
if (visible) {
|
||
visibleCount += 1;
|
||
}
|
||
});
|
||
|
||
var noMatches = editor.querySelector(
|
||
'[data-ucbc-filter-no-matches]'
|
||
);
|
||
|
||
if (noMatches) {
|
||
noMatches.hidden = visibleCount > 0;
|
||
}
|
||
}
|
||
|
||
function handleUserFilterAction(instance, actionElement) {
|
||
var action = normalizeText(
|
||
actionElement.getAttribute('data-ucbc-filter-action')
|
||
).toLowerCase();
|
||
var filterKey = normalizeText(
|
||
actionElement.getAttribute('data-ucbc-filter-key')
|
||
);
|
||
|
||
if (typeof instance.postBack !== 'function') {
|
||
return;
|
||
}
|
||
|
||
switch (action) {
|
||
case 'edit':
|
||
instance.postBack(
|
||
'filters:edit:' + encodeURIComponent(filterKey)
|
||
);
|
||
break;
|
||
|
||
case 'remove':
|
||
instance.postBack(
|
||
'filters:remove:' + encodeURIComponent(filterKey)
|
||
);
|
||
break;
|
||
|
||
case 'close':
|
||
instance.postBack('filters:close');
|
||
break;
|
||
|
||
case 'back':
|
||
instance.postBack('filters:back');
|
||
break;
|
||
|
||
case 'apply':
|
||
applyUserFilterEditor(instance);
|
||
break;
|
||
|
||
case 'select-list-item':
|
||
applyUserFilterListItem(instance, actionElement);
|
||
break;
|
||
}
|
||
}
|
||
|
||
function bindEvents(instance) {
|
||
if (instance.root.__ucbcEventsBound) {
|
||
return;
|
||
}
|
||
|
||
instance.root.__ucbcEventsBound = true;
|
||
|
||
instance.elements.searchInput.addEventListener('input', function () {
|
||
scheduleSearch(instance);
|
||
});
|
||
|
||
instance.elements.searchInput.addEventListener('keydown', function (event) {
|
||
if (event.key === 'Enter') {
|
||
event.preventDefault();
|
||
executeSearch(instance, 1);
|
||
} else if (event.key === 'Escape') {
|
||
hidePanel(instance);
|
||
}
|
||
});
|
||
|
||
instance.elements.searchButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
executeSearch(instance, 1);
|
||
});
|
||
|
||
instance.elements.columnsButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
|
||
var shouldShow = instance.elements.columnMenu.hidden;
|
||
|
||
renderColumnMenu(instance);
|
||
showPanel(instance);
|
||
setVisible(instance.elements.columnMenu, shouldShow);
|
||
|
||
if (shouldShow) {
|
||
positionColumnMenu(instance);
|
||
}
|
||
});
|
||
|
||
if (instance.elements.userFiltersButton) {
|
||
instance.elements.userFiltersButton.addEventListener(
|
||
'click',
|
||
function (event) {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
|
||
if (typeof instance.postBack === 'function') {
|
||
instance.postBack('filters:open');
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
instance.root.addEventListener('click', function (event) {
|
||
var actionElement = findUserFilterActionElement(
|
||
instance.root,
|
||
event.target
|
||
);
|
||
|
||
if (!actionElement) {
|
||
return;
|
||
}
|
||
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
handleUserFilterAction(instance, actionElement);
|
||
});
|
||
|
||
instance.root.addEventListener('input', function (event) {
|
||
var target = event.target;
|
||
|
||
if (!target || !target.getAttribute ||
|
||
!target.getAttribute('data-ucbc-filter-search')) {
|
||
return;
|
||
}
|
||
|
||
filterUserFilterMenu(target);
|
||
});
|
||
|
||
window.addEventListener('resize', function () {
|
||
if (!instance.elements.columnMenu.hidden) {
|
||
positionColumnMenu(instance);
|
||
}
|
||
|
||
positionUserFilterPanel(instance);
|
||
});
|
||
|
||
instance.elements.clearButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
clearSelection(instance);
|
||
});
|
||
|
||
instance.elements.firstButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
|
||
if (instance.page > 1) {
|
||
executeSearch(instance, 1, 'top');
|
||
}
|
||
});
|
||
|
||
instance.elements.previousButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
|
||
if (instance.page > 1) {
|
||
executeSearch(instance, instance.page - 1, 'bottom');
|
||
}
|
||
});
|
||
|
||
instance.elements.nextButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
|
||
if (instance.hasMore) {
|
||
executeSearch(instance, instance.page + 1, 'top');
|
||
}
|
||
});
|
||
|
||
instance.elements.lastButton.addEventListener('click', function (event) {
|
||
event.preventDefault();
|
||
|
||
var totalPages = getTotalPages(instance);
|
||
if (totalPages > 0 && instance.page < totalPages) {
|
||
executeSearch(instance, totalPages, 'top');
|
||
}
|
||
});
|
||
|
||
instance.elements.results.addEventListener(
|
||
'wheel',
|
||
function (event) {
|
||
handlePageTurnWheel(
|
||
instance,
|
||
event
|
||
);
|
||
},
|
||
{
|
||
passive: false
|
||
}
|
||
);
|
||
|
||
instance.elements.results.addEventListener(
|
||
'scroll',
|
||
function () {
|
||
var state =
|
||
instance.pageTurnIntent;
|
||
|
||
if (
|
||
!state ||
|
||
state.direction === 0 ||
|
||
state.changingPage
|
||
) {
|
||
return;
|
||
}
|
||
|
||
var results =
|
||
instance.elements.results;
|
||
|
||
var edgeTolerance = 2;
|
||
|
||
var remainsAtRequestedEdge =
|
||
state.direction === 1
|
||
? results.scrollTop +
|
||
results.clientHeight >=
|
||
results.scrollHeight -
|
||
edgeTolerance
|
||
: results.scrollTop <=
|
||
edgeTolerance;
|
||
|
||
if (!remainsAtRequestedEdge) {
|
||
cancelPageTurnIntent(instance);
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
function bindDocumentClick() {
|
||
if (documentClickBound) {
|
||
return;
|
||
}
|
||
|
||
documentClickBound = true;
|
||
|
||
document.addEventListener('click', function (event) {
|
||
Object.keys(instances).forEach(function (key) {
|
||
var instance = instances[key];
|
||
|
||
if (instance && instance.root && !instance.root.contains(event.target)) {
|
||
hidePanel(instance);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function normalizeConfiguration(configuration) {
|
||
var config = configuration || {};
|
||
|
||
config.clientId = normalizeText(config.clientId || config.rootId);
|
||
config.rootId = normalizeText(config.rootId || config.clientId);
|
||
config.minimumCharacters = Math.max(0, Number(config.minimumCharacters) || 0);
|
||
config.delayMilliseconds = Math.max(0, Number(config.delayMilliseconds) || 0);
|
||
config.searchTimeoutMilliseconds = Math.max(
|
||
1000,
|
||
Number(config.searchTimeoutMilliseconds) ||
|
||
15000
|
||
);
|
||
config.pageSize = Math.max(1, Number(config.pageSize) || 50);
|
||
config.pageTurnSteps = Math.max(
|
||
1,
|
||
Number(config.pageTurnSteps) || 3
|
||
);
|
||
config.pageTurnResetMilliseconds = Math.max(
|
||
200,
|
||
Number(config.pageTurnResetMilliseconds) || 900
|
||
);
|
||
config.pageTurnDeltaThreshold = Math.max(
|
||
1,
|
||
Number(config.pageTurnDeltaThreshold) || 40
|
||
);
|
||
config.pageTurnStepDelay = Math.max(
|
||
0,
|
||
Number(config.pageTurnStepDelay) || 90
|
||
);
|
||
config.allColumnsValue = normalizeText(config.allColumnsValue || '__ALL__');
|
||
config.columns = toArray(config.columns);
|
||
config.resultColumns = toArray(config.resultColumns);
|
||
config.displayColumns = toArray(config.displayColumns);
|
||
config.enabled = config.enabled === undefined ? true : asBoolean(config.enabled);
|
||
config.hasUserFilters = asBoolean(config.hasUserFilters);
|
||
config.refreshAfterUserFilterChange =
|
||
asBoolean(config.refreshAfterUserFilterChange);
|
||
|
||
return config;
|
||
}
|
||
|
||
function init(configuration, callback, postBack) {
|
||
var config = normalizeConfiguration(configuration);
|
||
var root = getElement(config.rootId);
|
||
|
||
if (!root) {
|
||
return;
|
||
}
|
||
|
||
var existing = instances[config.clientId];
|
||
|
||
if (existing && existing.root === root) {
|
||
existing.config = config;
|
||
existing.callback = callback;
|
||
existing.postBack = postBack;
|
||
existing.enabled = config.enabled;
|
||
existing.elements.sortOrders =
|
||
getElement(
|
||
config.sortOrdersId
|
||
);
|
||
existing.elements.userFiltersButton =
|
||
getElement(config.userFiltersButtonId);
|
||
existing.elements.userFiltersJson =
|
||
getElement(config.userFiltersJsonId);
|
||
existing.elements.userFilterEditorKey =
|
||
getElement(config.userFilterEditorKeyId);
|
||
existing.elements.userFilterEditorOperator =
|
||
getElement(config.userFilterEditorOperatorId);
|
||
existing.elements.userFilterEditorValue =
|
||
getElement(config.userFilterEditorValueId);
|
||
existing.elements.userFilterEditorText =
|
||
getElement(config.userFilterEditorTextId);
|
||
|
||
existing.sortOrders =
|
||
normalizeSortOrders(
|
||
config,
|
||
existing.sortOrders
|
||
);
|
||
|
||
saveSortOrders(existing);
|
||
updateSelectedState(existing);
|
||
updateSelectedColumnPresentation(existing);
|
||
refreshSortHeaders(existing);
|
||
|
||
window.setTimeout(function () {
|
||
positionUserFilterPanel(existing);
|
||
}, 0);
|
||
|
||
if (config.refreshAfterUserFilterChange) {
|
||
window.setTimeout(function () {
|
||
executeSearch(existing, 1);
|
||
}, 0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
var instance = {
|
||
config: config,
|
||
root: root,
|
||
callback: callback,
|
||
postBack: postBack,
|
||
enabled: config.enabled,
|
||
elements: {
|
||
searchInput: getElement(config.searchInputId),
|
||
searchButton: getElement(config.searchButtonId),
|
||
columnsButton: getElement(config.columnsButtonId),
|
||
selectedText: getElement(config.selectedTextId),
|
||
selectedValue: getElement(config.selectedValueId),
|
||
selectedJson: getElement(config.selectedJsonId),
|
||
selectedColumn: getElement(config.selectedColumnId),
|
||
sortOrders: getElement(config.sortOrdersId),
|
||
userFiltersButton: getElement(config.userFiltersButtonId),
|
||
userFiltersJson: getElement(config.userFiltersJsonId),
|
||
userFilterEditorKey: getElement(config.userFilterEditorKeyId),
|
||
userFilterEditorOperator: getElement(config.userFilterEditorOperatorId),
|
||
userFilterEditorValue: getElement(config.userFilterEditorValueId),
|
||
userFilterEditorText: getElement(config.userFilterEditorTextId)
|
||
},
|
||
sortOrders: [],
|
||
items: [],
|
||
page: 1,
|
||
totalRecords: 0,
|
||
hasMore: false,
|
||
loading: false,
|
||
requestId: 0,
|
||
timer: null,
|
||
requestTimeoutTimer: null,
|
||
restoreScroll: null,
|
||
pageTurnIntent: {
|
||
direction: 0,
|
||
steps: 0,
|
||
accumulatedDelta: 0,
|
||
lastStepAt: 0,
|
||
resetTimer: null,
|
||
changingPage: false
|
||
}
|
||
};
|
||
|
||
if (!instance.elements.searchInput ||
|
||
!instance.elements.searchButton ||
|
||
!instance.elements.columnsButton ||
|
||
!instance.elements.selectedText ||
|
||
!instance.elements.selectedValue ||
|
||
!instance.elements.selectedJson ||
|
||
!instance.elements.selectedColumn ||
|
||
!instance.elements.sortOrders ||
|
||
!instance.elements.userFiltersJson ||
|
||
!instance.elements.userFilterEditorKey ||
|
||
!instance.elements.userFilterEditorOperator ||
|
||
!instance.elements.userFilterEditorValue ||
|
||
!instance.elements.userFilterEditorText ||
|
||
(config.hasUserFilters && !instance.elements.userFiltersButton)) {
|
||
return;
|
||
}
|
||
|
||
instance.sortOrders =
|
||
normalizeSortOrders(
|
||
config,
|
||
instance.elements.sortOrders.value
|
||
);
|
||
|
||
saveSortOrders(instance);
|
||
|
||
root.classList.add('ucbc');
|
||
ensureClientElements(instance);
|
||
bindEvents(instance);
|
||
bindDocumentClick();
|
||
updateSelectedState(instance);
|
||
updateSelectedColumnPresentation(instance);
|
||
|
||
instance.elements.searchInput.disabled = !instance.enabled;
|
||
instance.elements.searchButton.disabled = !instance.enabled;
|
||
instance.elements.columnsButton.disabled = !instance.enabled;
|
||
|
||
if (instance.elements.userFiltersButton) {
|
||
instance.elements.userFiltersButton.disabled = !instance.enabled;
|
||
}
|
||
|
||
instances[config.clientId] = instance;
|
||
|
||
window.setTimeout(function () {
|
||
positionUserFilterPanel(instance);
|
||
}, 0);
|
||
|
||
if (config.refreshAfterUserFilterChange) {
|
||
window.setTimeout(function () {
|
||
executeSearch(instance, 1);
|
||
}, 0);
|
||
}
|
||
}
|
||
|
||
function callbackSuccess(rawResponse, context) {
|
||
var clientId = context && context.clientId
|
||
? context.clientId
|
||
: '';
|
||
var instance = instances[clientId];
|
||
|
||
if (!instance) {
|
||
return;
|
||
}
|
||
|
||
if (context.requestId !== instance.requestId) {
|
||
return;
|
||
}
|
||
|
||
clearSearchTimeout(instance);
|
||
|
||
var response;
|
||
|
||
try {
|
||
response = typeof rawResponse === 'string'
|
||
? JSON.parse(rawResponse)
|
||
: rawResponse;
|
||
} catch (error) {
|
||
setLoading(instance, false);
|
||
setStatus(instance, 'La respuesta del servidor no contiene JSON válido.', 'error');
|
||
return;
|
||
}
|
||
|
||
setLoading(instance, false);
|
||
|
||
if (!response || !asBoolean(getProperty(response, 'Ok'))) {
|
||
resetResults(instance);
|
||
showPanel(instance);
|
||
setStatus(
|
||
instance,
|
||
normalizeText(getProperty(response, 'Mensaje')) || 'Ocurrió un error al buscar.',
|
||
'error'
|
||
);
|
||
return;
|
||
}
|
||
|
||
instance.items = toArray(getProperty(response, 'Items'));
|
||
instance.page = Math.max(1, Number(getProperty(response, 'Pagina')) || 1);
|
||
instance.totalRecords = Math.max(0, Number(getProperty(response, 'TotalRegistros')) || 0);
|
||
instance.hasMore = asBoolean(getProperty(response, 'TieneMas'));
|
||
|
||
showPanel(instance);
|
||
renderResults(instance);
|
||
}
|
||
|
||
function callbackError(errorMessage, context) {
|
||
var clientId = context && context.clientId
|
||
? context.clientId
|
||
: '';
|
||
var instance = instances[clientId];
|
||
|
||
if (!instance) {
|
||
return;
|
||
}
|
||
|
||
if (context.requestId !== instance.requestId) {
|
||
return;
|
||
}
|
||
|
||
clearSearchTimeout(instance);
|
||
setLoading(instance, false);
|
||
resetResults(instance);
|
||
showPanel(instance);
|
||
setStatus(
|
||
instance,
|
||
normalizeText(errorMessage) || 'No fue posible completar la búsqueda.',
|
||
'error'
|
||
);
|
||
}
|
||
|
||
window.UcBuscadorCatalogo = {
|
||
init: init,
|
||
callbackSuccess: callbackSuccess,
|
||
callbackError: callbackError
|
||
};
|
||
|
||
}(window, document));
|