/* * Ex Table Filter 0.5 - jQuery Plugin * written by cyokodog * * Copyright (c) 2014 cyokodog * http://www.cyokodog.net/ * http://d.hatena.ne.jp/cyokodog/) * http://cyokodog.tumblr.com/ * MIT LICENCE * * Built for jQuery library * http://jquery.com * */ ;(function($){ var f = $.regexp = function(option){ if(!(this instanceof f)) return new f(option); var o = this,c = o.config = $.extend({},f.defaults,option); }; $.extend(f,$.extend(f.prototype,{ _getInstance : function(target){ return target instanceof f ? target : f() }, escapeSource : function(source){ var o = f._getInstance(this),c = o.config; $.each(c.esc_str.split(','),function(){ var esc_s = '\\' + this; source = source.replace(new RegExp(esc_s,'g'),esc_s); }); return source; }, wildcardMatchEscapeSource : function(source){ var o = f._getInstance(this), c = o.config; return o.escapeSource(source).replace(/\\\*/g,'.*'); } })); f.defaults = { esc_str : '\\,^,$,*,+,?,.,(,),|,{,},[,]' }; })(jQuery); ;(function($){ // Namespace $.ex = $.ex || {}; // Constructor var plugin = $.ex.tableFilter = function(target, option){ var o = this, c = o.config = $.extend(true,{}, $.ex.tableFilter.defaults, option, o.getDataParam()); plugin.status.applyCnt ++; c.target = target.eq(0); c._filters = {}; o.setFilters(c.filters,{autoFilter:false}); !c.autoFilter || o.filtering(); c.callback.apply(o,[o]); } // API $.extend($.ex.tableFilter.prototype, { // プラグイン適用要素の独自データ属性(data-ex-table-filter)を取得する getDataParam : function(){ try{eval('return ' + this.config.target.attr('data-' + plugin.id));}catch(e){return {};} }, // プラグイン適用要素を取得する getTarget : function(){ return this.config.target; }, // フィルタリング中のフィルタを取得する getCurrentFilter : function(){ return this.config._currentFilter; }, // フィルタリング中のフィルタの値を取得する getCurrentFilterVal : function(){ var o = this, c = o.config; var el = o.getCurrentFilter().element; if(!el) return undefined; if(/^radio|checkbox$/.test(el.prop('type'))){ var el = el.filter(':checked'); if(el.prop('type') == 'checkbox'){ var ret = []; el.each(function(){ ret.push($(this).val()); }); return ret; } } return el.val(); }, // フィルタリング中のフィルタの値を数値変換して取得する getCurrentFilterNum : function(){ var o = this, c = o.config; return o.getCurrentFilterVal.apply(o,arguments) - 0; }, // フィルタリング中の TR 要素を取得する getCurrentRow : function(){ return this.config._row; }, // フィルタリング中の TH/TD 要素を取得する getCurrentCell : function(index){ var o = this, c = o.config; if(!arguments.length) return c._col; return o.getCurrentRow().find('> *').eq(index); }, // フィルタリング中の TH/TD 要素の値を取得する getCurrentCellVal : function(index){ var o = this, c = o.config; return o.getCurrentCell.apply(o,arguments).text(); }, // フィルタリング中の TH/TD 要素の値を数値変換して取得する getCurrentCellNum : function(index){ var o = this, c = o.config; return o.getCurrentCellVal.apply(o,arguments) - 0; }, // フィルタリング中の行の表示状態を取得する isShowCurrentRow : function(){ return this.config._show; }, // 各カラムのフィルタ条件を配列又は JSON 形式でまとめて設定する setFilters : function(filters, config){ var o = this, c = $.extend({},o.config,config); var appends = null; $.each(filters, function(index){ var filter = c._filters[index] = filters[index]; }); o._generateFilter(); $.each(c._filters, function(index){ o.setFilter(index, c._filters[index], config); }); return o; }, // 特定のカラムのフィルタ条件を設定する setFilter : function(index, filter, config){ var o = this, c = $.extend({},o.config,config); if(filter instanceof RegExp){ } else if(filter instanceof Function){ } else{ var element; var getDefaultParam = function(element){ return /^radio|checkbox$/.test(element.prop('type')) || element.prop('tagName') == 'SELECT' ? c.selectElementFilter : c.elementFilter; } if(!(filter instanceof jQuery) && typeof filter == 'object'){ if(filter.element) { element = $(filter.element); filter = $.extend({},getDefaultParam(element),filter); } } else{ element = $(filter); filter = $.extend({},getDefaultParam(element)); } if(element) { filter.element = element; if(c.autoBindFilter){ filter.element.on(c.elementAutoBindTrigger,function(){ if(c._triggerTimer) clearTimeout(c._triggerTimer); c._triggerTimer = setTimeout(function(){ o.filtering(); },c.elementAutoBindFilterDelay); }); } } } c._filters[index] = filter; if(c.autoFilter) o.filtering(); return o; }, // フィルタリングを実行する filtering : function(){ var o = this, c = o.config; c._rows = c.target.find('> tbody > tr'); c.onFilteringStart.apply(o,[o]); c._rows.each(function(rowno){ if(rowno >= c.startDataRowNo){ $.each(c._filters, function(index){ o._setFilterStatus(c._filters[index], '_show', false); }); c._row = c._rows.eq(rowno).show(); c._show = true; c._cols = c._row.find('> *'); c._cols.each(function(colno){ c._col = c._cols.eq(colno); var filter = c._currentFilter = c._filters[colno]; if(filter != undefined){ o._setFilterStatus(filter, '_show', o._getFilterStatus(filter, '_show') || !!o._filtering(filter)); } }); $.each(c._filters, function(index){ if(!o._getFilterStatus(c._filters[index], '_show')) c._show = false; }); var ret = c.onFiltering.apply(o,[o]); if(ret != undefined){ c._show = !!ret; } if(!c._show){ c._row.hide(); } } }); c.onFilteringEnd.apply(o,[o]); return o; }, // フィルタリングのメイン処理 _filtering : function(filter){ var o = this, c = o.config; var result = true; if(typeof filter == 'boolean') { result = filter; } else if(filter instanceof Function){ var ret = filter.apply(o,[o]); if(ret != undefined) { result = o._filtering(ret); } } else if(filter instanceof RegExp){ if(!filter.test(o.getCurrentCellVal())){ result = false; } } else if(filter.queryStringMatch && filter.queryStringName){ var getQSvalue = function(loc){ var loc = loc || location; var q = loc.search.replace('?','').split('&'); var ret = ''; for(var i in q){ var p = q[i].split('='); if(p[0] == filter.queryStringName) ret = p[1]; } return ret; } var qs = getQSvalue(); if(filter.element){ $(filter.element).each(function(){ if(getQSvalue(this) == qs) $(this).addClass('active') }); } result = (!qs.length || o.getCurrentCellVal() == qs); } else if(filter.element && filter.element instanceof jQuery){ var ret = filter.onFiltering.apply(o,[o]); if(ret != undefined) { result = o._filtering(ret); } else{ var v; if(filter.element.prop('tagName') == 'SELECT'){ v = filter.element.find('option:selected')[filter.selectValueMatch ? 'val' : 'text'](); } else if(filter.element.prop('type') == 'radio'){ v = filter.element.filter(':checked').val(); } else if(filter.element.prop('type') == 'checkbox'){ v = []; filter.element.filter(':checked').each(function(){ v.push($(this).val()); }); if(!v.length) v = ''; } else{ v = filter.element.val(); } if(v){ if(v instanceof Array){ for(var i = 0;i < v.length; i++){ v[i] = o._makeFilterSrc(filter,v[i]); } v = v.join('|'); } else{ v = o._makeFilterSrc(filter,v); } var reg = filter.matchSwitch ? new RegExp(v,filter.matchSwitch) : new RegExp(v); result = reg.test(o.getCurrentCellVal()); } } } else{ result = !!filter; } return result; }, // パラメータに従ったフィルタ条件を正規表現形式で生成 _makeFilterSrc : function(filter,src){ src = filter.wildcardMatch ? $.regexp.wildcardMatchEscapeSource(src) : $.regexp.escapeSource(src); if(filter.firstMatch || filter.wildcardMatch || filter.fullMatch) src = '^' + src; if(filter.lastMatch || filter.wildcardMatch || filter.fullMatch) src = src + '$'; return src; }, // フィルターにステータスを設定 _setFilterStatus : function(filter, name, val){ var element = filter.element; if(element && element.length){ element.data(name, val); } filter[name] = val; }, // フィルターのステータスを取得 _getFilterStatus : function(filter, name){ var element = filter.element; if(element && element.length){ return element.data(name); } return filter[name]; }, // フィルタ入力フィールドを自動生成する _generateFilter : function(){ var o = this, c = o.config; var appends = null; $.each(c._filters, function(index){ var filter = c._filters[index]; if(!(filter instanceof jQuery) && typeof filter == 'object'){ var append = filter.append; if(append && append.to && append.type){ appends = appends || {}; appends[index] = append; } } }); if(!appends) return o; c.target.find('> tbody > tr').each(function(rowno){ var tr = $(this); if(rowno >= c.startDataRowNo){ $.each(appends, function(i){ var v = tr.find('> *').eq(i).text(); if(v.length){ var append = appends[i]; append.values = append.values || {}; append.values[v] = v; if(!isNaN(v)) append.numCnt = (append.numCnt || 0) + 1; append.valCnt = (append.valCnt || 0) + 1; } }); } }); $.each(appends, function(i){ var append = appends[i]; var appendFilter = c.appendFilter[append.type]; append = $.extend(true, {}, appendFilter, append); append.to = $(append.to); append.isNumValues = (append.numCnt == append.valCnt); if(append.to.length && append.values){ var arr = []; $.each(append.values, function(v){ arr.push(v); }); !append.isNumValues ? arr.sort() : arr.sort(function(a, b){ return (parseInt(a) > parseInt(b)) ? 1 : -1; }); if(/^(checkbox|radio)$/.test(append.type)){ var element = []; var add = function(label, value){ var wrap = $(append.template.replace(/{label}/ig, label)).appendTo(append.to); var el = wrap.prop('type') == append.type ? wrap : wrap.find('input:' + append.type); if(append.type == 'radio') el.prop('name', 'radio-filter-' + plugin.status.applyCnt); element.push(el.val(value)[0]); } $.each(arr, function(j){ var v = arr[j]; if(j == 0 && append.addBlank) add(append.blankLabel, append.blankValue) add(v, v); }); if(element.length){ c._filters[i].element = $(element); } } else if(append.type == 'select'){ var element = $(append.template).appendTo(append.to); var add = function(label, value) { $('