1282 lines
26 KiB
JavaScript
1282 lines
26 KiB
JavaScript
(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 = $('<div>', {
|
|
'class': 'filtrosig-container',
|
|
'data-filtrosig-grid': gridId
|
|
});
|
|
|
|
|
|
/*
|
|
* CONTROL
|
|
*/
|
|
var $control = $('<div>', {
|
|
'class': 'filtrosig-control'
|
|
});
|
|
|
|
|
|
/*
|
|
* INPUT
|
|
*
|
|
* autocomplete se coloca mediante attr()
|
|
* para evitar conflicto con jQuery UI autocomplete.
|
|
*/
|
|
var $input = $('<input>', {
|
|
type: 'text',
|
|
'class': 'filtrosig-input',
|
|
placeholder: 'Buscar...'
|
|
});
|
|
|
|
$input.attr(
|
|
'autocomplete',
|
|
'off'
|
|
);
|
|
|
|
|
|
/*
|
|
* CONTENEDOR AZUL
|
|
*/
|
|
var $acciones = $('<div>', {
|
|
'class': 'filtrosig-actions'
|
|
});
|
|
|
|
|
|
/*
|
|
* BOTÓN BUSCAR
|
|
*
|
|
* Usa FontAwesome.
|
|
*/
|
|
var $buscar = $('<button>', {
|
|
type: 'button',
|
|
'class': 'filtrosig-search',
|
|
title: 'Buscar'
|
|
}).html(
|
|
'<span class="fa fa-search"></span>'
|
|
);
|
|
|
|
|
|
/*
|
|
* NOMBRE DEL CAMPO SELECCIONADO
|
|
*/
|
|
var $campoActual = $('<span>', {
|
|
'class': 'filtrosig-selected-field'
|
|
});
|
|
|
|
|
|
/*
|
|
* BOTÓN FLECHA
|
|
*/
|
|
var $flecha = $('<button>', {
|
|
type: 'button',
|
|
'class': 'filtrosig-arrow',
|
|
title: 'Seleccionar campo'
|
|
}).html(
|
|
'<span class="filtrosig-chevron"></span>'
|
|
);
|
|
|
|
|
|
/*
|
|
* MENÚ
|
|
*/
|
|
var $menu = $('<div>', {
|
|
'class': 'filtrosig-menu'
|
|
});
|
|
|
|
|
|
/*
|
|
* GENERAR OPCIONES
|
|
*/
|
|
campos.forEach(function (item) {
|
|
|
|
var $opcion = $('<button>', {
|
|
type: 'button',
|
|
'class': 'filtrosig-option',
|
|
text: item.titulo
|
|
});
|
|
|
|
|
|
$opcion.attr(
|
|
'data-tipo',
|
|
item.tipo
|
|
);
|
|
|
|
$opcion.attr(
|
|
'data-campo',
|
|
item.campo
|
|
);
|
|
|
|
$opcion.attr(
|
|
'data-titulo',
|
|
item.titulo
|
|
);
|
|
|
|
|
|
if (item.tipo === 'all') {
|
|
|
|
$opcion.addClass(
|
|
'active'
|
|
);
|
|
}
|
|
|
|
|
|
$menu.append(
|
|
$opcion
|
|
);
|
|
});
|
|
|
|
|
|
/*
|
|
* SELECCIÓN INICIAL
|
|
*/
|
|
$control.data(
|
|
'tipo',
|
|
'all'
|
|
);
|
|
|
|
$control.data(
|
|
'campo',
|
|
''
|
|
);
|
|
|
|
$control.data(
|
|
'titulo',
|
|
'Todos'
|
|
);
|
|
|
|
|
|
/*
|
|
* ARMAR PARTE AZUL
|
|
*/
|
|
$acciones
|
|
.append($buscar)
|
|
.append($campoActual)
|
|
.append($flecha);
|
|
|
|
|
|
/*
|
|
* ARMAR CONTROL
|
|
*/
|
|
$control
|
|
.append($input)
|
|
.append($acciones)
|
|
.append($menu);
|
|
|
|
|
|
$contenedor.append(
|
|
$control
|
|
);
|
|
|
|
|
|
/*
|
|
* Colocamos el control inmediatamente
|
|
* antes del GridView.
|
|
*/
|
|
$grid.before(
|
|
$contenedor
|
|
);
|
|
|
|
|
|
/*
|
|
* =====================================================
|
|
* TEMPORIZADOR PARA FILTRADO AUTOMÁTICO
|
|
* =====================================================
|
|
*
|
|
* Si el usuario escribe:
|
|
*
|
|
* A
|
|
*
|
|
* esperamos 1 segundo.
|
|
*
|
|
* Si antes escribe:
|
|
*
|
|
* AB
|
|
*
|
|
* cancelamos el anterior y volvemos
|
|
* a esperar 1 segundo.
|
|
*/
|
|
var timeoutFiltro = null;
|
|
|
|
|
|
/*
|
|
* =====================================================
|
|
* ABRIR / CERRAR MENÚ
|
|
* =====================================================
|
|
*/
|
|
$flecha.on('click', function (e) {
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
|
|
alternarMenuFlotante($control, $menu, $flecha);
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
* =====================================================
|
|
* SELECCIONAR CAMPO
|
|
* =====================================================
|
|
*/
|
|
$menu.on(
|
|
'click',
|
|
'.filtrosig-option',
|
|
function () {
|
|
|
|
var $opcion =
|
|
$(this);
|
|
|
|
|
|
var tipo =
|
|
$opcion.attr(
|
|
'data-tipo'
|
|
);
|
|
|
|
|
|
var campo =
|
|
$opcion.attr(
|
|
'data-campo'
|
|
);
|
|
|
|
|
|
var titulo =
|
|
$opcion.attr(
|
|
'data-titulo'
|
|
);
|
|
|
|
|
|
/*
|
|
* Guardamos selección.
|
|
*/
|
|
$control.data(
|
|
'tipo',
|
|
tipo
|
|
);
|
|
|
|
$control.data(
|
|
'campo',
|
|
campo
|
|
);
|
|
|
|
$control.data(
|
|
'titulo',
|
|
titulo
|
|
);
|
|
|
|
|
|
/*
|
|
* Cambiar opción activa.
|
|
*/
|
|
$menu
|
|
.find('.filtrosig-option')
|
|
.removeClass('active');
|
|
|
|
|
|
$opcion.addClass(
|
|
'active'
|
|
);
|
|
|
|
|
|
/*
|
|
* TODOS:
|
|
*
|
|
* No mostramos título.
|
|
*
|
|
* COLUMNA / DATA:
|
|
*
|
|
* mostramos título entre
|
|
* lupa y flecha.
|
|
*/
|
|
if (tipo === 'all') {
|
|
|
|
$campoActual.text('');
|
|
|
|
$control.removeClass(
|
|
'campo-seleccionado'
|
|
);
|
|
|
|
}
|
|
else {
|
|
|
|
$campoActual.text(
|
|
titulo
|
|
);
|
|
|
|
$control.addClass(
|
|
'campo-seleccionado'
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Cerrar menú.
|
|
*/
|
|
cerrarMenuFlotante();
|
|
|
|
|
|
/*
|
|
* Si había un filtro automático
|
|
* esperando, lo cancelamos.
|
|
*/
|
|
if (timeoutFiltro !== null) {
|
|
|
|
clearTimeout(
|
|
timeoutFiltro
|
|
);
|
|
|
|
timeoutFiltro = null;
|
|
}
|
|
|
|
|
|
/*
|
|
* Aplicar inmediatamente el filtro
|
|
* usando el nuevo campo.
|
|
*/
|
|
ejecutarFiltro(
|
|
$grid,
|
|
$control,
|
|
$input
|
|
);
|
|
}
|
|
);
|
|
|
|
|
|
/*
|
|
* =====================================================
|
|
* CLICK EN LA LUPA
|
|
* =====================================================
|
|
*
|
|
* Ejecuta inmediatamente.
|
|
*/
|
|
$buscar.on('click', function () {
|
|
|
|
/*
|
|
* Cancelar filtro automático pendiente.
|
|
*/
|
|
if (timeoutFiltro !== null) {
|
|
|
|
clearTimeout(
|
|
timeoutFiltro
|
|
);
|
|
|
|
timeoutFiltro = null;
|
|
}
|
|
|
|
|
|
ejecutarFiltro(
|
|
$grid,
|
|
$control,
|
|
$input
|
|
);
|
|
});
|
|
|
|
|
|
/*
|
|
* =====================================================
|
|
* ENTER
|
|
* =====================================================
|
|
*
|
|
* Ejecuta inmediatamente.
|
|
*/
|
|
$input.on('keydown', function (e) {
|
|
|
|
if (
|
|
e.key === 'Enter' ||
|
|
e.keyCode === 13
|
|
) {
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
/*
|
|
* Cancelar filtro automático pendiente.
|
|
*/
|
|
if (timeoutFiltro !== null) {
|
|
|
|
clearTimeout(
|
|
timeoutFiltro
|
|
);
|
|
|
|
timeoutFiltro = null;
|
|
}
|
|
|
|
|
|
ejecutarFiltro(
|
|
$grid,
|
|
$control,
|
|
$input
|
|
);
|
|
}
|
|
});
|
|
|
|
|
|
/*
|
|
* =====================================================
|
|
* FILTRADO AUTOMÁTICO AL ESCRIBIR
|
|
* =====================================================
|
|
*
|
|
* DEBOUNCE DE 1 SEGUNDO.
|
|
*
|
|
* Cada vez que escribe:
|
|
*
|
|
* 1. Cancela el timeout anterior.
|
|
* 2. Espera nuevamente 1 segundo.
|
|
* 3. Si no escribió nada más,
|
|
* ejecuta FiltrarGrid().
|
|
*
|
|
* Si borra todo:
|
|
*
|
|
* se limpia el filtro inmediatamente.
|
|
*/
|
|
$input.on('input', function () {
|
|
|
|
/*
|
|
* Cancelar ejecución anterior.
|
|
*/
|
|
if (timeoutFiltro !== null) {
|
|
|
|
clearTimeout(
|
|
timeoutFiltro
|
|
);
|
|
|
|
timeoutFiltro = null;
|
|
}
|
|
|
|
|
|
/*
|
|
* Si quedó vacío, no esperamos.
|
|
*
|
|
* Quitamos nuestro filtro inmediatamente.
|
|
*/
|
|
if (
|
|
$.trim(
|
|
$(this).val()
|
|
) === ''
|
|
) {
|
|
|
|
ejecutarFiltro(
|
|
$grid,
|
|
$control,
|
|
$input
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Esperar 1 segundo desde
|
|
* la última escritura.
|
|
*/
|
|
timeoutFiltro =
|
|
setTimeout(function () {
|
|
|
|
ejecutarFiltro(
|
|
$grid,
|
|
$control,
|
|
$input
|
|
);
|
|
|
|
|
|
timeoutFiltro = null;
|
|
|
|
}, 1000);
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Ejecuta el método público FiltrarGrid.
|
|
*/
|
|
function ejecutarFiltro(
|
|
$grid,
|
|
$control,
|
|
$input
|
|
) {
|
|
|
|
FiltrarGrid(
|
|
$grid,
|
|
$input.val(),
|
|
$control.data('tipo'),
|
|
$control.data('campo')
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Filtra utilizando:
|
|
*
|
|
* - todo el texto de la fila
|
|
* - todos los data-* existentes en la fila
|
|
*/
|
|
function filtrarTodo(
|
|
$fila,
|
|
texto
|
|
) {
|
|
|
|
/*
|
|
* Texto visible de toda la fila.
|
|
*/
|
|
var contenido =
|
|
normalizarTexto(
|
|
$fila.text()
|
|
);
|
|
|
|
|
|
/*
|
|
* Además agregamos TODOS los data-*
|
|
* de la fila.
|
|
*/
|
|
$.each(
|
|
$fila[0].attributes,
|
|
function () {
|
|
|
|
if (
|
|
this.name &&
|
|
this.name.indexOf('data-') === 0
|
|
) {
|
|
|
|
contenido +=
|
|
' ' +
|
|
normalizarTexto(
|
|
this.value
|
|
);
|
|
}
|
|
}
|
|
);
|
|
|
|
|
|
return contenido.indexOf(
|
|
texto
|
|
) !== -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Filtra exclusivamente por una columna.
|
|
*/
|
|
function filtrarPorColumna(
|
|
$fila,
|
|
indice,
|
|
texto
|
|
) {
|
|
|
|
indice =
|
|
parseInt(
|
|
indice,
|
|
10
|
|
);
|
|
|
|
|
|
if (isNaN(indice)) {
|
|
return false;
|
|
}
|
|
|
|
|
|
var $celda =
|
|
$fila
|
|
.children('td,th')
|
|
.eq(indice);
|
|
|
|
|
|
if (!$celda.length) {
|
|
return false;
|
|
}
|
|
|
|
|
|
var contenido =
|
|
normalizarTexto(
|
|
$celda.text()
|
|
);
|
|
|
|
|
|
return contenido.indexOf(
|
|
texto
|
|
) !== -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Filtra exclusivamente por un data-*.
|
|
*
|
|
* Ejemplo:
|
|
*
|
|
* data-etapa="Etapa 3"
|
|
*
|
|
* campo:
|
|
*
|
|
* etapa
|
|
*/
|
|
function filtrarPorData(
|
|
$fila,
|
|
campo,
|
|
texto
|
|
) {
|
|
|
|
var valor =
|
|
$fila.attr(
|
|
'data-' + campo
|
|
);
|
|
|
|
|
|
if (valor === undefined) {
|
|
|
|
valor = '';
|
|
}
|
|
|
|
|
|
valor =
|
|
normalizarTexto(
|
|
valor
|
|
);
|
|
|
|
|
|
return valor.indexOf(
|
|
texto
|
|
) !== -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Obtiene solamente las filas que
|
|
* FiltroSig tiene permitido filtrar.
|
|
*/
|
|
function obtenerFilasFiltrables($grid) {
|
|
|
|
return $grid
|
|
.find('tbody > tr')
|
|
.not('.ADtr')
|
|
.not('.' + FILTRO_IGNORE);
|
|
}
|
|
|
|
|
|
/**
|
|
* Actualiza contador opcional.
|
|
*
|
|
* Grid:
|
|
*
|
|
* data-filtrosig-contador="IdContador"
|
|
*/
|
|
function actualizarContador($grid) {
|
|
|
|
var idContador =
|
|
$grid.attr(
|
|
'data-filtrosig-contador'
|
|
);
|
|
|
|
|
|
if (!idContador) {
|
|
return;
|
|
}
|
|
|
|
|
|
var $contador =
|
|
$('#' + idContador);
|
|
|
|
|
|
if (!$contador.length) {
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* :visible respeta:
|
|
*
|
|
* - filtrosig-hidden
|
|
* - display:none externo
|
|
* - otras clases que oculten filas
|
|
*/
|
|
var cantidad =
|
|
obtenerFilasFiltrables($grid)
|
|
.filter(':visible')
|
|
.length;
|
|
|
|
|
|
$contador.text(
|
|
cantidad
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Normaliza el texto para la búsqueda.
|
|
*
|
|
* - minúsculas
|
|
* - trim
|
|
* - elimina diferencias por acentos
|
|
*
|
|
* Ejemplo:
|
|
*
|
|
* Mexico
|
|
*
|
|
* encuentra:
|
|
*
|
|
* México
|
|
*/
|
|
function normalizarTexto(texto) {
|
|
|
|
if (
|
|
texto === null ||
|
|
texto === undefined
|
|
) {
|
|
|
|
return '';
|
|
}
|
|
|
|
|
|
texto =
|
|
String(texto)
|
|
.toLowerCase()
|
|
.trim();
|
|
|
|
|
|
/*
|
|
* Búsqueda tolerante a acentos.
|
|
*/
|
|
if (texto.normalize) {
|
|
|
|
texto =
|
|
texto
|
|
.normalize('NFD')
|
|
.replace(
|
|
/[\u0300-\u036f]/g,
|
|
''
|
|
);
|
|
}
|
|
|
|
|
|
return texto;
|
|
}
|
|
|
|
|
|
/*
|
|
* =========================================================
|
|
* CERRAR MENÚ AL HACER CLICK AFUERA
|
|
* =========================================================
|
|
*/
|
|
$(document).on(
|
|
'click.filtrosig',
|
|
function () {
|
|
|
|
cerrarMenuFlotante();
|
|
}
|
|
);
|
|
|
|
|
|
/*
|
|
* Evita que un click dentro del control
|
|
* cierre inmediatamente el menú.
|
|
*/
|
|
$(document).on(
|
|
'click.filtrosig',
|
|
'.filtrosig-control',
|
|
function (e) {
|
|
|
|
e.stopPropagation();
|
|
}
|
|
);
|
|
|
|
|
|
/*
|
|
* =========================================================
|
|
* PRIMERA CARGA
|
|
* =========================================================
|
|
*/
|
|
$(function () {
|
|
|
|
RenderizarFiltrosSig();
|
|
});
|
|
|
|
|
|
/*
|
|
* =========================================================
|
|
* ASP.NET WEBFORMS / UPDATEPANEL
|
|
* =========================================================
|
|
*
|
|
* Después de cualquier postback parcial
|
|
* volvemos a buscar GridViews .filtrosig.
|
|
*
|
|
* Si el GridView fue reemplazado:
|
|
*
|
|
* ya no tendrá filtrosigrendered
|
|
*
|
|
* y se generará nuevamente.
|
|
*
|
|
* Si sobrevivió al postback:
|
|
*
|
|
* conserva filtrosigrendered
|
|
*
|
|
* y NO se duplica.
|
|
*/
|
|
if (
|
|
typeof Sys !== 'undefined' &&
|
|
Sys.WebForms &&
|
|
Sys.WebForms.PageRequestManager
|
|
) {
|
|
|
|
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(cerrarMenuFlotante);
|
|
|
|
Sys.WebForms.PageRequestManager
|
|
.getInstance()
|
|
.add_endRequest(function () {
|
|
|
|
RenderizarFiltrosSig();
|
|
});
|
|
}
|
|
|
|
|
|
})(window, window.jQuery);
|