(function (window, $) {
'use strict';
if (!$) {
console.error('FiltroSig requiere jQuery.');
return;
}
var menuFlotante = null;
function cerrarMenuFlotante() {
if (!menuFlotante) {
return;
}
var actual = menuFlotante;
menuFlotante = null;
actual.control.removeClass('menu-open');
actual.flecha.attr('aria-expanded', 'false');
actual.menu.removeClass('filtrosig-menu-flotante').removeAttr('style');
if ($.contains(document, actual.control[0])) {
actual.menu.detach().appendTo(actual.control);
} else {
actual.menu.remove();
}
}
function posicionarMenuFlotante() {
if (!menuFlotante) {
return;
}
var actual = menuFlotante;
if (!$.contains(document, actual.control[0])) {
cerrarMenuFlotante();
return;
}
var borde = actual.flecha[0].getBoundingClientRect();
var ancho = window.innerWidth;
var alto = window.innerHeight;
actual.menu.css({
width: Math.min(240, ancho - 12),
minWidth: Math.min(210, ancho - 12),
maxHeight: Math.max(50, alto - 12),
left: 0,
top: 0,
right: 'auto',
bottom: 'auto'
});
var altura = actual.menu.outerHeight();
var arriba = borde.bottom + 4;
if (arriba + altura > alto - 6) {
arriba = Math.max(6, borde.top - altura - 4);
}
actual.menu.css({
left: Math.max(6, Math.min(borde.right - actual.menu.outerWidth(), ancho - actual.menu.outerWidth() - 6)),
top: Math.min(arriba, Math.max(6, alto - altura - 6))
});
}
function alternarMenuFlotante(control, menu, flecha) {
var cerrar = menuFlotante && menuFlotante.control[0] === control[0];
cerrarMenuFlotante();
if (cerrar) {
return;
}
menuFlotante = { control: control, menu: menu, flecha: flecha };
control.addClass('menu-open');
flecha.attr('aria-expanded', 'true');
menu.detach().appendTo(control.closest('form')).addClass('filtrosig-menu-flotante');
posicionarMenuFlotante();
}
window.addEventListener('resize', posicionarMenuFlotante);
document.addEventListener('scroll', function (evento) {
if (menuFlotante && !menuFlotante.menu[0].contains(evento.target)) {
posicionarMenuFlotante();
}
}, true);
$(document).on('keydown.sigFiltroMenu', function (evento) {
if (evento.key === 'Escape') {
cerrarMenuFlotante();
}
});
var FILTRO_RENDERED = 'filtrosigrendered';
var FILTRO_HIDDEN = 'filtrosig-hidden';
var FILTRO_IGNORE = 'filtrosig-ignore';
/**
* Inicializa todos los GridView marcados con:
*
* class="filtrosig"
*
* que todavía no hayan sido renderizados.
*/
window.RenderizarFiltrosSig = function () {
$('table.filtrosig')
.not('.' + FILTRO_RENDERED)
.each(function () {
var $grid = $(this);
prepararFilasEspeciales($grid);
var campos = obtenerCampos($grid);
crearControl($grid, campos);
$grid.addClass(FILTRO_RENDERED).attr('data-sig-filtro-inicializado', '1');
});
};
/**
* Método público fijo para filtrar un GridView.
*
* grid:
* DOM table, jQuery table o id.
*
* texto:
* Texto a buscar.
*
* tipo:
* all
* column
* data
*
* campo:
* índice de columna o nombre del data.
*/
window.FiltrarGrid = function (grid, texto, tipo, campo) {
var $grid = obtenerGrid(grid);
if (!$grid.length) {
return;
}
texto = normalizarTexto(texto);
var $filas = obtenerFilasFiltrables($grid);
$filas.each(function () {
var $fila = $(this);
var coincide = false;
if (texto === '') {
coincide = true;
}
else if (tipo === 'column') {
coincide = filtrarPorColumna(
$fila,
campo,
texto
);
}
else if (tipo === 'data') {
coincide = filtrarPorData(
$fila,
campo,
texto
);
}
else {
coincide = filtrarTodo(
$fila,
texto
);
}
if (coincide) {
/*
* IMPORTANTE:
*
* Solo quitamos nuestra propia clase.
*
* NO modificamos:
*
* style="display:none"
* clases externas
* ocultamientos realizados por otras funciones.
*/
$fila.removeClass(FILTRO_HIDDEN);
}
else {
/*
* Esta es nuestra única marca para ocultar.
*/
$fila.addClass(FILTRO_HIDDEN);
}
});
actualizarContador($grid);
};
/**
* Obtiene el GridView.
*/
function obtenerGrid(grid) {
if (grid instanceof jQuery) {
return grid;
}
if (grid instanceof HTMLElement) {
return $(grid);
}
if (typeof grid === 'string') {
if (grid.charAt(0) === '#') {
return $(grid);
}
return $('#' + grid);
}
return $();
}
/**
* Marca las filas que FiltroSig NO debe ocultar.
*/
function prepararFilasEspeciales($grid) {
$grid.find('tr').each(function () {
var $tr = $(this);
/*
* Si contiene TH es header.
*/
if ($tr.children('th').length > 0) {
$tr.addClass(FILTRO_IGNORE);
}
/*
* Compatibilidad con las filas ADtr
* existentes en SIG.
*/
if ($tr.hasClass('ADtr')) {
$tr.addClass(FILTRO_IGNORE);
}
});
/*
* THEAD y TFOOT siempre se ignoran.
*/
$grid
.find('thead tr, tfoot tr')
.addClass(FILTRO_IGNORE);
}
/**
* Obtiene:
*
* - Todos
* - columnas visibles del GridView
* - campos data adicionales
*/
function obtenerCampos($grid) {
var campos = [];
/*
* TODOS
*/
campos.push({
tipo: 'all',
campo: '',
titulo: 'Todos'
});
/*
* COLUMNAS DEL GRIDVIEW
*/
var $headers = obtenerHeaders($grid);
$headers.each(function (index) {
var $th = $(this);
/*
* Permite excluir una columna:
*
* data-filtrosig-ignore="true"
*/
if (
String(
$th.attr('data-filtrosig-ignore')
).toLowerCase() === 'true'
) {
return;
}
var titulo = $.trim(
$th.text()
);
/*
* Si no tiene título normalmente es
* una columna de botones.
*/
if (!titulo) {
return;
}
campos.push({
tipo: 'column',
campo: index,
titulo: titulo
});
});
/*
* DATAS ADICIONALES
*
* Ejemplo:
*
* data-filtrosig-datas=
* "cliente:Cliente,etapa:Etapa,cvecliente:Clave cliente"
*/
var configuracionDatas =
$grid.attr('data-filtrosig-datas');
if (configuracionDatas) {
configuracionDatas
.split(',')
.forEach(function (item) {
item = $.trim(item);
if (!item) {
return;
}
var partes =
item.split(':');
var campo =
$.trim(partes[0]);
var titulo =
partes.length > 1
? $.trim(
partes.slice(1).join(':')
)
: campo;
campos.push({
tipo: 'data',
campo: campo,
titulo: titulo
});
});
}
return campos;
}
/**
* Obtiene los headers.
*/
function obtenerHeaders($grid) {
var $headers =
$grid.find('thead tr:first th');
if ($headers.length) {
return $headers;
}
/*
* Fallback para GridView sin
* UseAccessibleHeader.
*/
return $grid.find('tr:first th');
}
/**
* Genera el control visual de búsqueda.
*/
function crearControl($grid, campos) {
var gridId =
$grid.attr('id');
/*
* Si por alguna razón el GridView
* no tiene ID, generamos uno.
*/
if (!gridId) {
gridId =
'filtrosig_grid_' +
Math.random()
.toString(36)
.substring(2, 10);
$grid.attr(
'id',
gridId
);
}
/*
* CONTENEDOR
*/
var $contenedor = $('
', {
'class': 'filtrosig-container',
'data-filtrosig-grid': gridId
});
/*
* CONTROL
*/
var $control = $('
', {
'class': 'filtrosig-control'
});
/*
* INPUT
*
* autocomplete se coloca mediante attr()
* para evitar conflicto con jQuery UI autocomplete.
*/
var $input = $('
', {
type: 'text',
'class': 'filtrosig-input',
placeholder: 'Buscar...'
});
$input.attr(
'autocomplete',
'off'
);
/*
* CONTENEDOR AZUL
*/
var $acciones = $('
', {
'class': 'filtrosig-actions'
});
/*
* BOTÓN BUSCAR
*
* Usa FontAwesome.
*/
var $buscar = $('