HTML:
<li>
<label>检查时间</label>
<ul class="inspect_time">
<li class="retrieval_color">今天</li>
<li>昨天</li>
<li>最近3天</li>
<li>最近7天</li>
<li style="width:200px"><span class="date_title" id="date1" style="display:block;border-radius: 3px;"></span></li>//日期选择插件
</ul>
</li>
<script>
//date
var dateRange1 = new pickerDateRange(\'date1\', {
stopToday : false,
isTodayValid : true,
startDate: Today,
endDate: Today,
needCompare : false,
// defaultText : \' 离开 \',
autoSubmit : false,
inputTrigger : \'input_trigger1\',
theme : \'ta\'
});
</script>
CSS:
/*========== reset ==========*/
html, body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td, iframe,hr{margin:0;padding:0;}
body{font:12px/1.6 Tahoma,microsoft yahei,"微软雅黑","宋体";*font-family:"微软雅黑","宋体";}
fieldset, img { border:0; }
address, caption, cite, dfn, em, th, var{font-style:normal;font-weight:normal;}
ol, ul { list-style:none; }
caption, th { text-align:left; }
h1, h2, h3, h4, h5, h6 { font-size:100%; }
table {border-collapse:collapse;border-spacing:0;}
select,input,label,button,textarea{margin:0;padding:0;font:normal normal normal "微软雅黑",arial,Simsun,Arial Unicode MS,Mingliu,Arial;overflow:visible;}
input{padding:2px 0 1px;*padding:4px 0 0;_padding:4px 0 0;_height:21px;}
/**
* GRI主题
*/
.gri_contrast {
float: left;
margin: 4px 8px 0 8px;
line-height: 20px;
color: #666;
cursor: pointer;
font: 12px/1.5 Tahoma, Helvetica, \'SimSun\', sans-serif;
}
.gri_date {
/* margin: 4px 4px;*/
padding: 0 26px 0 6px;
width: 195px;
height: 20px;
line-height: 20px;
border: 1px solid #D6D6D6;
background: #FFF url(\'./images/icon_date.png\') no-repeat 100% 50%;
cursor: pointer;
color: #666;
}
.gri_date_month {
width: 180px
}
.gri_dateRangeCalendar {
position: absolute;
display: none;
background: #FFF;
border: 1px solid #6FB1DF;
padding: 10px;
-moz-box-shadow: 0px 1px 3px #6FB1DF;
filter: progid:DXImageTransform.Microsoft.Shadow(Strength = 5, Direction = 135, Color = "#CCCCCC");
font: 12px/1.5 Tahoma, Helvetica, \'SimSun\', sans-serif;
}
.gri_dateRangeCalendar a {
color: #369;
}
.gri_dateRangePicker {
float: left;
border: 0;
margin: 0;
padding: 0;
}
.gri_dateRangeOptions {
float: left;
}
.gri_dateRangeOptions input.gri_dateRangeInput {
width: 80px;
text-align: center;
border: 1px solid #DDD;
}
.gri_dateRangeOptions div.gri_dateRangeInput {
margin-bottom: 5px;
}
.gri_dateRangePreMonth {
float: left;
width: 15px;
height: 17px;
background: url(\'./images/page.png\') no-repeat 0 0;
overflow: hidden;
}
.gri_dateRangeNextMonth {
float: right;
width: 15px;
height: 17px;
background: url(\'./images/page.png\') no-repeat -15px 0;
overflow: hidden;
}
.gri_dateRangePreMonth span, .gri_dateRangeNextMonth span {
display: none;
}
.gri_dateRangeDateTable {
margin: 0 10px 0 0px;
padding: 0px;
float: left;
empty-cells: show;
border-collapse: collapse;
display: inline;
font-size: 12px;
}
.gri_dateRangeDateTable td {
border: 1px solid #EEE;
text-align: right;
cursor: pointer;
padding: 1px 2px;
}
.gri_dateRangeDateTable th {
border-top: 1px solid #DEE6F6;
border-left: 1px solid #DEE6F6;
background: #E0E8F7;
font-weight: 400;
border-left: 1px solid #DDD;
}
.gri_dateRangeDateTable td.gri_dateRangeGray {
color: #BBB;
cursor: default;
}
.gri_dateRangeDateTable td.gri_dateRangeToday {
color: #F90;
font-weight: bold;
}
.gri_dateRangeSelected {
background-color: #007CD9;
color: #FFF;
}
.gri_dateRangeCompare {
background-color: #B9E078;
color: #FFF;
}
.gri_dateRangeCoincide {
background-color: #FFFFC4;
}
.gri_pn {
background: url("../img/pn.png") repeat-x scroll 0 -48px #E5E5E5;
color: #fff;
}
.gri_pnc {
background: url("../img/pn.png") repeat-x scroll 0 0 #E5E5E5;
}
.gri_co {
border: 1px solid #999999;
box-shadow: 0 1px 0 #E5E5E5;
cursor: pointer;
font-family: Tahoma, \'Microsoft Yahei\', \'Simsun\';
font-size: 12px;
height: 21px;
overflow: hidden;
vertical-align: middle
}
/**
* =================================================
* TA主题
* =================================================
*/
.ta_date{
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background-color: #fefefe;
background-image: -ms-linear-gradient(top, #fafafa, #f5f5f5);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fafafa), to(#f5f5f5));
background-image: -moz-linear-gradient(top, #fafafa, #f5f5f5);
background-image: -o-linear-gradient(top, #fafafa, #f5f5f5);
background-image: linear-gradient(top, #fafafa, #f5f5f5);
background-repeat: repeat-x;
float:left;
}
.ta_date .date_title {
font-family:Arial;
font-size:14px;
color:#666666;
padding:6px 10px;
*padding:0px 10px;
border-right:1px solid #d8d8d8;
vertical-align:middle;
cursor:pointer;
*zoom:1;
}
.ta_date .date_title:before{content: " "}
.ta_date:hover {
/* background-image:none;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);*/
background: #9DC970;
}
.ta_date:hover .date_title{
color: #fff;
}
.ta_date .to{ padding:0 5px;}
.ta_date .opt_sel{/*====*/
width:30px;
height:28px;
line-height:28px;
display:inline-block;
text-align:center;
vertical-align:middle;
margin-left:-4px;
}
.ta_date a.opt_sel:link, .ta_date a.opt_sel:visited {
}
.ta_date a.opt_sel:active, .ta_date a.opt_sel:hover {
}
.ta_date .i_orderd{
display: inline-block;
width: 0;
height: 0;
vertical-align:middle;
border-top: 5px solid #727272;
border-right: 5px dashed transparent;
border-left: 5px dashed transparent;
font-size:0;
content: "";
overflow:hidden;
*margin-top:10px;
}
.ta_calendar2{*width:536px;}
.ta_calendar1{*width:268px;}
.ta_calendar{background-color: #ffffff;
font-size:12px;
text-align:left;
z-index:100;
position: absolute;
right: 0;
}
.i_pre,.i_next,.ta_calendar td.ta_dateRangeSelected,.ta_calendar td.first,.ta_calendar td.last,.ta_calendar td.today{
/*background:url(http://imgcache.qq.com/bossweb/mta/images/calendar_all.png) no-repeat;*/
background:url(../img/calendar_all.png) no-repeat;
cursor:pointer;
}
.i_pre,.i_next{ width:23px; height:23px;display:inline-block; }
.i_pre{ background-position:0 0;}
.i_pre:hover{ background-position:-46px 0px;}
.i_next{ background-position:-23px 0;}
.i_next:hover{ background-position:-69px 0px;}
.ta_calendar td.ta_dateRangeSelected{
background:#cbe6f5;
}
.ta_calendar td.ta_dateRangeGray{
color: #BBB;
cursor: default;
}
.ta_calendar td.first,.ta_calendar td.today{
background:#4eb5f7;
}
.ta_calendar td.first:after,.ta_calendar td.today:after{content: "";display: block; font-size: 10px;color:#fff;}
.ta_calendar td.last{
background:#4eb5f7;
}
.ta_calendar td.last:after{content: "";display: block; font-size: 10px;color:#fff;}
.ta_calendar .dis{
color:#9e9e9e;
}
.ta_calendar table {
font-size: 12px;
_display:inline;
border-spacing:0 7px;
border-collapse:collapse;
width: 100%;
}
.ta_calendar table caption{ text-align:center; height:40px; line-height:40px; font-size:14px; box-shadow:0px 1px 1px rgba(0,0,0,0.1);}
.ta_calendar table thead tr {
background:#fff;
}
.ta_calendar table thead th {
cursor: pointer;
text-align:center;
height: 40px;
}
.ta_calendar table.calendar-month {
font-size: 12px;
float:left;
margin:0 8px;
_display:inline;
border-spacing:7px;
border-collapse:separate;
margin-bottom:10px;
}
.calendar-month caption{
border-bottom:1px solid #E1E1E1;
*padding-bottom:0px;
}
.calendar-month tbody td {
line-height: 30px;
padding: 4px 11px;
text-align:center;
white-space:nowrap;
font-family:"���ź�";
cursor:pointer;
}
.calendar-month td.hover,.calendar-month td:hover,.calendar-month caption span:hover{
background:#;
color:#6590c1;
border:1px solid #6590c1;
padding: 3px 10px;
border-radius:2px;
cursor:pointer;
}
.calendar .dis:hover{
color:#9e9e9e;
border:1px solid #d3d5d6;
padding: 3px 10px;
}
.calendar-month td.current{
background:#6590c1;
color:#fff;
border-radius:2px;
}
.ta_calendar table thead th.sun{color: #999;}
.ta_calendar table thead th.sat{color: #999;}
.ta_calendar table td:first-child{height: 0px;}
.ta_calendar table tbody td {
text-align:center;
white-space:nowrap;
font-family:"Tahoma";
background: #edf8fe;
height: 40px;
width: 14%;
border: 1px solid #fff;
}
.ta_calendar_cont{position:relative;}
.ta_calendar_cont .i_pre,.ta_calendar_cont .i_next{position:absolute; top:7px;}
.ta_calendar_cont .i_pre{left:10px;}
.ta_calendar_cont .i_next{right:10px;}
.ta_calendar_footer{
border-top:1px solid #e5e5e5;
background:#fafafa;
padding-top:6px;
height:34px;
}
.ta_calendar_footer .frm_btn{
float:right;
}
.ta_calendar_footer .frm_msg{
float:left;
vertical-align:middle;
}
.ta_calendar_footer .ipt_text_s{
padding:4px 4px;
}
.ta_ipt_text, .ta_ipt_textarea, .ta_ipt_text_s {
border: 1px solid #CCCCCC;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
color: #555555;
font-size: 12px;
height: 16px;
line-height: 16px;
padding: 6px 4px;
position: relative;
transition: border 0.2s linear 0s, box-shadow 0.2s linear 0s;
vertical-align: middle;
width: 180px;
z-index: 2;
}
.ta_ipt_text_s {
width: 80px;
}
.ta_btn {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #F5F5F5;
background-image: -moz-linear-gradient(center top , #FEFEFE, #F5F5F5);
background-repeat: repeat-x;
border-color: #CACACA #CACACA #B3B3B3;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
color: #333333;
cursor: pointer;
display: inline-block;
font-family: "���ź�","����";
font-size: 12px;
line-height: 20px;
margin-bottom: 0;
outline: 0 none;
padding: 3px 12px;
text-align: center;
}
.ta_btn:hover, .ta_btn:active, .ta_btn.active, .ta_btn.disabled, .ta_btn[disabled] {
color: #333333;
}
.ta_btn:hover {
background-color: #FEFEFE;
background-image: none;
color: #333333;
text-decoration: none;
transition: background-position 0.1s linear 0s;
}
.ta_btn:focus {
outline: thin dotted #333333;
outline-offset: -2px;
}
.ta_btn.active, .ta_btn:active {
background-color: #E6E6E6;
background-image: none;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) inset, 0 1px 2px rgba(0, 0, 0, 0.05);
outline: 0 none;
}
.ta_btn.disabled, .ta_btn[disabled] {
background-color: #E6E6E6;
background-image: none;
box-shadow: none;
cursor: default;
opacity: 0.65;
}
.ta_btn {
margin: 0px 5px 0 0;
vertical-align: top;
}
.ta_btn:hover{
background-position: 0 -16px;
}
.ta_btn_primary {
background-color: #B4D66F;
background-image: -moz-linear-gradient(center top , #C7E184, #A2CC59);
border: 1px solid #88AB4A;
color: #56740F;
}
.ta_btn_primary:hover{
background-color: #5C96DB;
background-image: -moz-linear-gradient(center top , #74A5ED, #4789CD);
border: 1px solid #286AB1;
color: #FFFFFF;
}
.cf:after {
clear: both;
}
.cf:before, .cf:after {
content: "";
display: table;
}
.cf:before, .cf:after {
content: "";
display: table;
}
JS:
/**
*=======================================================================
*日期选择器js组件。
*@author :johnnyzheng(johnnyzheng@tencent.com) 郑灿双
*@version : 2012-07-11
*@modification list:2012-08-16 规范样式名称
* 2013-01-04 增加主题设置接口
* 2013-01-31 增加自定义灰掉周末 周几的选项,增加自动初始化自动提交的功能
* 2013-03-15 支持一个页面多个日期选择器,快捷日期选择
* 2013-03-26 增加确认、取消按钮的隐藏,而直接自动提交
* 2013-08-01 扩展接口,增加最近90天,增加自定义可选时间
* 2013-08-12 日期选择器框体宽度超出视窗大小的时候制动鼓靠右对齐
* 2014-02-25 增加业务接口:获取当前日期对象的的选中日期
* 2014-10-13 扩展参数,支持日期下拉选择自定义年和月份,配合theme:ta来使用。
*=======================================================================
*/
/**
* @description 整个日期选择器对象的构造函数入口,支持丰富的接口参数传递,大多数提供默认配置,可传入覆盖
* @param {String} inputId 日期选择器ID
* @param {object} options 配置数组
*/
function pickerDateRange(inputId, options) {
/**
* 默认配置参数数据,每个参数涵义在后解释
*/
var defaults = {
aToday : \'aToday\', //今天
aYesterday : \'aYesterday\', //昨天
aRecent7Days : \'aRecent7Days\', //最近7天
aRecent14Days : \'aRecent14Days\',//最近14天
aRecent30Days : \'aRecent30Days\', //最近30天
aRecent90Days : \'aRecent90Days\', //最近90天
startDate : \'\', // 开始日期
endDate : \'\', // 结束日期
startCompareDate : \'\', // 对比开始日期
endCompareDate : \'\', // 对比结束日期
minValidDate : \'315507600\', //最小可用时间,控制日期选择器的可选力度
maxValidDate : \'\', // 最大可用时间,与stopToday 配置互斥
success : function(obj) {return true;}, //回调函数,选择日期之后执行何种操作
startDateId : \'startDate\', // 开始日期输入框ID
startCompareDateId : \'startCompareDate\', // 对比开始日期输入框ID
endDateId : \'endDate\', // 结束日期输入框ID
endCompareDateId : \'endCompareDate\', // 对比结束日期输入框ID
target : \'\', // 日期选择框的目标,一般为 <form> 的ID值
needCompare : false, // 是否需要进行日期对比
suffix : \'\', //相应控件的后缀
inputTrigger : \'input_trigger\',
compareTrigger : \'compare_trigger\',
compareCheckboxId : \'needCompare\', // 比较选择框
calendars : 1, // 展示的月份数,最大是2
dayRangeMax : 0, // 日期最大范围(以天计算)
monthRangeMax : 12, // 日期最大范围(以月计算)
dateTable : \'dateRangeDateTable\', // 日期表格的CSS类
selectCss : \'dateRangeSelected\', // 时间选择的样式
compareCss : \'dateRangeCompare\', // 比较时间选择的样式
coincideCss : \'dateRangeCoincide\', // 重合部分的样式
firstCss : \'first\', //起始样式
lastCss : \'last\', //结束样式
clickCss : \'today\', //点击样式
disableGray : \'dateRangeGray\', // 非当前月的日期样式
isToday : \'dateRangeToday\', // 今天日期的样式
joinLineId : \'joinLine\',
isSingleDay : false,
defaultText : \'至\',
singleCompare : false,
stopToday : true,
isTodayValid : false,
weekendDis : false, //灰掉周末不可选。
disCertainDay : [], //不可用的周日期设置数组,如:[1,3]是要周一, 周三 两天不可选,每个周的周一,周三都不可选择。
disCertainDate : [],//不可用的日期设置数组,如:[1,3]是要1号,3号 两天不可选,特别的,[true,1,3]则反之,只有1,3可选,其余不可选。
shortOpr : false, //结合单天日期选择的短操作,不需要确定和取消的操作按钮。
noCalendar : false, //日期输入框是否展示
theme : \'gri\', //日期选择器的主题,目前支持 \'gri\' / \'ta\'
magicSelect : false, //用户自定义选择年、月,与{theme:ta}配合使用。
autoCommit : false, //加载后立马自动提交
autoSubmit : false, //没有确定,取消按钮,直接提交
replaceBtn : \'btn_compare\'
};
//将对象赋给__method变量
var __method = this;
this.inputId = inputId;
this.inputCompareId = inputId + \'Compare\';
this.compareInputDiv = \'div_compare_\'+inputId;
// 配置参数
this.mOpts = $.extend({}, defaults, options);
//默认日历参数最大是3
this.mOpts.calendars = Math.min(this.mOpts.calendars, 3);
//根据不同主题需要初始化的变量
this.mOpts.compareCss = this.mOpts.theme == \'ta\' ? this.mOpts.selectCss :this.mOpts.compareCss
//昨天,今天,最近7天,最近14天,最近30天
this.periodObj = {};
this.periodObj[__method.mOpts.aToday] = 0;
this.periodObj[__method.mOpts.aYesterday] = 1;
this.periodObj[__method.mOpts.aRecent7Days] = 6;
this.periodObj[__method.mOpts.aRecent14Days] = 13;
this.periodObj[__method.mOpts.aRecent30Days] = 29;
this.periodObj[__method.mOpts.aRecent90Days] = 89;
// 记录初始默认时间
this.startDefDate = \'\';
// 随机ID后缀
var suffix = \'\' == this.mOpts.suffix ? (new Date()).getTime() : this.mOpts.suffix;
// 日期选择框DIV的ID
this.calendarId = \'calendar_\' + suffix;
// 日期列表DIV的ID
this.dateListId = \'dateRangePicker_\' + suffix;
// 日期比较层
this.dateRangeCompareDiv = \'dateRangeCompareDiv_\' + suffix;
//日期选择层
this.dateRangeDiv = \'dateRangeDiv_\' + suffix;
// 日期对比选择控制的checkbox
this.compareCheckBoxDiv = \'dateRangeCompareCheckBoxDiv_\' + suffix;
// 时间选择的确认按钮
this.submitBtn = \'submit_\' + suffix;
// 日期选择框关闭按钮
this.closeBtn = \'closeBtn_\' + suffix;
// 上一个月的按钮
this.preMonth = \'dateRangePreMonth_\' + suffix;
// 下一个月的按钮
this.nextMonth = \'dateRangeNextMonth_\' + suffix;
// 表单中开始、结束、开始对比、结束对比时间
this.startDateId = this.mOpts.startDateId + \'_\' + suffix;
this.endDateId = this.mOpts.endDateId + \'_\' + suffix;
this.compareCheckboxId = this.mOpts.compareCheckboxId + \'_\' + suffix;
this.startCompareDateId = this.mOpts.startCompareDateId + \'_\' + suffix;
this.endCompareDateId = this.mOpts.endCompareDateId + \'_\' + suffix;
// 初始化日期选择器面板的HTML代码串
var wrapper = {
gri :[
\'<div id="\' + this.calendarId + \'" class="gri_dateRangeCalendar">\',
\'<table class="gri_dateRangePicker"><tr id="\' + this.dateListId + \'"></tr></table>\',
\'<div class="gri_dateRangeOptions" \'+ (this.mOpts.autoSubmit ? \' style="display:none" \' : \'\') +\'>\',
\'<div class="gri_dateRangeInput" id="\' + this.dateRangeDiv + \'" >\',
\'<input type="text" class="gri_dateRangeInput" name="\' + this.startDateId + \'" id="\' + this.startDateId + \'" value="\' + this.mOpts.startDate + \'" readonly />\',
\'<span id="\' + this.mOpts.joinLineId + \'"> - </span>\',
\'<input type="text" class="gri_dateRangeInput" name="\' + this.endDateId + \'" id="\' + this.endDateId + \'" value="\' + this.mOpts.endDate + \'" readonly /><br />\',
\'</div>\',
\'<div class="gri_dateRangeInput" id="\' + this.dateRangeCompareDiv + \'">\',
\'<input type="text" class="gri_dateRangeInput" name="\' + this.startCompareDateId + \'" id="\' + this.startCompareDateId + \'" value="\' + this.mOpts.startCompareDate + \'" readonly />\',
\'<span class="\' + this.mOpts.joinLineId + \'"> - </span>\',
\'<input type="text" class="gri_dateRangeInput" name="\' + this.endCompareDateId + \'" id="\' + this.endCompareDateId + \'" value="\' + this.mOpts.endCompareDate + \'" readonly />\',
\'</div>\',
\'<div>\',
\'<input type="button" name="\' + this.submitBtn + \'" id="\' + this.submitBtn + \'" value="确定" />\',
\' <a id="\' + this.closeBtn + \'" href="javascript:;">关闭</a>\',
\'</div>\',
\'</div>\',
\'</div>\'
],
ta:[
\'<div id="\' + this.calendarId + \'" class="ta_calendar ta_calendar2 cf">\',
\'<div class="ta_calendar_cont cf" id="\'+ this.dateListId +\'">\',
//\'<table class="dateRangePicker"><tr id="\' + this.dateListId + \'"></tr></table>\',
\'</div>\',
\'<div class="ta_calendar_footer cf" \'+ (this.mOpts.autoSubmit ? \' style="display:none" \' : \'\') +\'>\',
\'<div class="frm_msg">\',
\'<div id="\' + this.dateRangeDiv + \'">\',
\'<input type="text" class="ta_ipt_text_s" name="\' + this.startDateId + \'" id="\' + this.startDateId + \'" value="\' + this.mOpts.startDate + \'" readonly />\',
\'<span class="\' + this.mOpts.joinLineId + \'"> - </span>\',
\'<input type="text" class="ta_ipt_text_s" name="\' + this.endDateId + \'" id="\' + this.endDateId + \'" value="\' + this.mOpts.endDate + \'" readonly /><br />\',
\'</div>\',
\'<div id="\' + this.dateRangeCompareDiv + \'">\',
\'<input type="text" class="ta_ipt_text_s" name="\' + this.startCompareDateId + \'" id="\' + this.startCompareDateId + \'" value="\' + this.mOpts.startCompareDate + \'" readonly />\',
\'<span class="\' + this.mOpts.joinLineId + \'"> - </span>\',
\'<input type="text" class="ta_ipt_text_s" name="\' + this.endCompareDateId + \'" id="\' + this.endCompareDateId + \'" value="\' + this.mOpts.endCompareDate + \'" readonly />\',
\'</div>\',
\'</div>\',
\'<div class="frm_btn">\',
\'<input class="ta_btn ta_btn_primary" type="button" name="\' + this.submitBtn + \'" id="\' + this.submitBtn + \'" value="确定" />\',
\'<input class="ta_btn" type="button" id="\' + this.closeBtn + \'" value="取消"/>\',
\'</div>\',
\'</div>\',
\'</div>\'
]
};
//对比日期框体的html串
var checkBoxWrapper = {
gri:[
\'<label class="gri_contrast" for ="\' + this.compareCheckboxId + \'">\',
\'<input type="checkbox" class="gri_pc" name="\' + this.compareCheckboxId + \'" id="\' + this.compareCheckboxId + \'" value="1"/>对比\',
\'</label>\',
\'<input type="text" name="\'+this.inputCompareId+\'" id="\'+this.inputCompareId+\'" value="" class="gri_date"/>\'
],
ta:[
\'<label class="contrast" for ="\' + this.compareCheckboxId + \'">\',
\'<input type="checkbox" class="pc" name="\' + this.compareCheckboxId + \'" id="\' + this.compareCheckboxId + \'" value="1"/>对比\',
\'</label>\',
\'<div class="ta_date" id="\'+this.compareInputDiv+\'">\',
\'<span name="dateCompare" id="\'+this.inputCompareId+\'" class="date_title"></span>\',
\'<a class="opt_sel" id="\'+ this.mOpts.compareTrigger +\'" href="#">\',
\'<i class="i_orderd"></i>\',
\'</a>\',
\'</div>\'
]
};
//把checkbox放到页面的相应位置,放置到inputid后面 added by johnnyzheng
if(this.mOpts.theme == \'ta\'){
$(checkBoxWrapper[this.mOpts.theme].join(\'\')).insertAfter($(\'#div_\' + this.inputId));
}else{
$(checkBoxWrapper[this.mOpts.theme].join(\'\')).insertAfter($(\'#\' + this.inputId));
}
//根据传入参数决定是否展示日期输入框
if(this.mOpts.noCalendar){
$(\'#\' + this.inputId).css(\'display\', \'none\');
$(\'#\' + this.compareCheckboxId).parent().css(\'display\',\'none\');
}
// 把时间选择框放到页面中
$(0 < $(\'#appendParent\').length ? \'#appendParent\' : document.body).append(wrapper[this.mOpts.theme].join(\'\'));
$(\'#\' + this.calendarId).css(\'z-index\', 9999);
// 初始化目标地址的元素
if(1 > $(\'#\' + this.mOpts.startDateId).length) {
$(\'\'!=this.mOpts.target?\'#\'+this.mOpts.target:\'body\').append(\'<input type="hidden" id="\' + this.mOpts.startDateId + \'" name="\' + this.mOpts.startDateId + \'" value="\' + this.mOpts.startDate + \'" />\');
} else {
$(\'#\' + this.mOpts.startDateId).val(this.mOpts.startDate);
}
if(1 > $(\'#\' + this.mOpts.endDateId).length) {
$(\'\'!=this.mOpts.target?\'#\'+this.mOpts.target:\'body\').append(\'<input type="hidden" id="\' + this.mOpts.endDateId + \'" name="\' + this.mOpts.endDateId + \'" value="\' + this.mOpts.endDate + \'" />\');
} else {
$(\'#\' + this.mOpts.endDateId).val(this.mOpts.endDate);
}
if(1 > $(\'#\' + this.mOpts.compareCheckboxId).length) {
$(\'\'!=this.mOpts.target?\'#\'+this.mOpts.target:\'body\').append(\'<input type="checkbox" id="\' + this.mOpts.compareCheckboxId + \'" name="\' + this.mOpts.compareCheckboxId + \'" value="0" style="display:none;" />\');
}
// 如果不需要比较日期,则需要隐藏比较部分的内容
if(false == this.mOpts.needCompare) {
$(\'#\' + this.compareInputDiv).css(\'display\', \'none\');
$(\'#\' + this.compareCheckBoxDiv).css(\'display\', \'none\');
$(\'#\' + this.dateRangeCompareDiv).css(\'display\', \'none\');
$(\'#\' + this.compareCheckboxId).attr(\'disabled\', true);
$(\'#\' + this.startCompareDateId).attr(\'disabled\', true);
$(\'#\' + this.endCompareDateId).attr(\'disabled\', true);
//隐藏对比的checkbox
$(\'#\' + this.compareCheckboxId).parent().css(\'display\',\'none\');
$(\'#\'+ this.mOpts.replaceBtn).length > 0 && $(\'#\'+ this.mOpts.replaceBtn).hide();
} else {
if(1 > $(\'#\' + this.mOpts.startCompareDateId).length) {
$(\'\'!=this.mOpts.target?\'#\'+this.mOpts.target:\'body\').append(\'<input type="hidden" id="\' + this.mOpts.startCompareDateId + \'" name="\' + this.mOpts.startCompareDateId + \'" value="\' + this.mOpts.startCompareDate + \'" />\');
} else {
$(\'#\' + this.mOpts.startCompareDateId).val(this.mOpts.startCompareDate);
}
if(1 > $(\'#\' + this.mOpts.endCompareDateId).length) {
$(\'\'!=this.mOpts.target?\'#\'+this.mOpts.target:\'body\').append(\'<input type="hidden" id="\' + this.mOpts.endCompareDateId + \'" name="\' + this.mOpts.endCompareDateId + \'" value="\' + this.mOpts.endCompareDate + \'" />\');
} else {
$(\'#\' + this.mOpts.endCompareDateId).val(this.mOpts.endCompareDate);
}
if(\'\' == this.mOpts.startCompareDate || \'\' == this.mOpts.endCompareDate) {
$(\'#\' + this.compareCheckboxId).attr(\'checked\', false);
$(\'#\' + this.mOpts.compareCheckboxId).attr(\'checked\', false);
} else {
$(\'#\' + this.compareCheckboxId).attr(\'checked\', true);
$(\'#\' + this.mOpts.compareCheckboxId).attr(\'checked\', true);
}
}
// 输入框焦点定在第一个输入框
this.dateInput = this.startDateId;
// 为新的输入框加背景色
this.changeInput(this.dateInput);
// 开始时间 input 的 click 事件
$(\'#\' + this.startDateId).bind(\'click\', function() {
// 如果用户在选择基准结束时间时,换到对比时间了,则
if(__method.endCompareDateId == __method.dateInput) {
$(\'#\' + __method.startCompareDateId).val(__method.startDefDate);
}
__method.startDefDate = \'\';
__method.removeCSS(1);
//__method.addCSS(1);
__method.changeInput(__method.startDateId);
return false;
});
$(\'#\' + this.calendarId).bind(\'click\', function(event) {
//event.preventDefault();
// 防止冒泡
event.stopPropagation();
});
// 开始比较时间 input 的 click 事件
$(\'#\' + this.startCompareDateId).bind(\'click\', function() {
// 如果用户在选择基准结束时间时,换到对比时间了,则
if(__method.endDateId == __method.dateInput) {
$(\'#\' + __method.startDateId).val(__method.startDefDate);
}
__method.startDefDate = \'\';
__method.removeCSS(0);
//__method.addCSS(0);
__method.changeInput(__method.startCompareDateId);
return false;
});
/**
* 设置回调句柄,点击成功后,返回一个时间对象,包含开始结束时间
* 和对比开始结束时间
*/
var dateall = [];
$(\'#\' + this.submitBtn).bind(\'click\', function() {
__method.close(1);
__method.mOpts.success({\'startDate\': $(\'#\' + __method.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + __method.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + __method.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + __method.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + __method.mOpts.endCompareDateId).val()
});
// __method.close();
$(\'.date_title\').css({
\'background\':\'#9DC970\',
\'color\':\'#fff\'
})
$(\'.inspect_time li\').removeClass(\'retrieval_color\');
var selectdate = $(\'.date_title\').text();//所选日期
var selectdate1 = selectdate.replace(\'至\',\',\');
timer1 = selectdate1.substr(0, 10);//重新赋值
timer2 = selectdate1.substr(11);//重新赋值
$.ajax({
type:"POST",
url:_ajaxUrl,
datatype:"json",
data:{
name: $("input[name=\'name\']").val(),
IMGCARD: $("input[name=\'imgcard\']").val(),
CHECKCARD: $("input[name=\'CHECKCARD\']").val(),
PHECARD: $("input[name=\'PHECARD\']").val(),
RADIOLOGDIAGNOSIS: $("input[name=\'RADIOLOGDIAGNOSIS\']").val(),
AUDITDOC: $("input[name=\'AUDITDOC\']").val(),
checkitem: $("input[name=\'checkitem\']").val(),
strDate:timer1,
endDate:timer2,
stutype:type1,
DISYY:type2,
DIASTA:state
},
success:function(data){
data = JSON.parse(data);
totalPage = Math.ceil(data.rows/5)//总页数
initPageLinks();
var sHtml = \'\';
if(data.code == 0){
arry = data.person;
for(var i = 0;i<arry.length;i++){
//隔行变色
var trColor;
if (i % 2 == 0) {trColor = "even";}else {trColor = "odd";}
//性别
var msex = \'\';
if (arry[i].sex == 2) { msex = \'女\';}else{msex = \'男\';}
//医疗状态
var mdiasta = \'\';if (arry[i].diasta == 1) {mdiasta = \'待诊断\';}else if(arry[i].diasta == 2){mdiasta = \'诊断中\';}else{mdiasta = \'已诊断\';}
//序号
var xuhao = pageNum*(currentPage-1)+i+1;
sHtml += "<tr class=\'" + trColor + "\'>";
sHtml += "<td>"+xuhao+"</td>";
sHtml += "<td class=\"td_juid\" style=\"display:none\">"+arry[i].guid+"</td>";
sHtml += "<td>"+arry[i].filmdate+"</td>"
sHtml += "<td>"+arry[i].name+"</td>"
sHtml += "<td class=\"sextype\">"+msex+"</td>"
sHtml += "<td>"+arry[i].age+"</td>"
sHtml += "<td>"+mdiasta+"</td>"
sHtml += "<td>"+arry[i].phecard+"</td>"
sHtml += "<td>"+arry[i].imgcard+"</td>"
sHtml += "<td>"+arry[i].checkcard+"</td>"
sHtml += "<td>"+arry[i].stutype+"</td>"
sHtml += "<td>"+arry[i].ckparts+"</td>"
sHtml += "<td><i>"+arry[i].checkitem+"</i></td>"
sHtml += "<td>"+arry[i].reportdate+"</td>"
sHtml += "<td>"+arry[i].auditdoc+"</td>"
sHtml += "<td>"+arry[i].ckdate+"</td>"
sHtml += "<td>"+arry[i].disyy+"</td>"
sHtml += "<td class=\"_operation\"><b title=\"影像报告\" class=\"img_presentation\"><img src=\"img/img.png\"></b><b></b><b></b><b></b></td>"
sHtml += "</tr>";
$("#bbsTab").html(sHtml);
}
}else if(data.code == 1){
sHtml += "<tr>"
sHtml += "<td colspan=\"17\">没有可显示的数据!</td>"
sHtml += "</tr>"
$("#bbsTab").html(sHtml);
}else{
alert(\'查询出错!\');
}
},
error:function(jqXHR){
alert(\'发生错误:\'+jqXHR.status)
}
})
return false;
});
// 日期选择关闭按钮的 click 事件
$(\'#\' + this.closeBtn).bind(\'click\', function() {
__method.close();
return false;
});
// 为输入框添加click事件
$(\'#\' + this.inputId).bind(\'click\', function() {
__method.init();
__method.show(false, __method);
return false;
});
$(\'#\' + this.mOpts.inputTrigger).bind(\'click\', function() {
__method.init();
__method.show(false, __method);
return false;
});
$(\'#\' + this.mOpts.compareTrigger).bind(\'click\', function() {
__method.init(true);
__method.show(true, __method);
return false;
});
// 为输入框添加click事件
$(\'#\' + this.inputCompareId).bind(\'click\', function() {
__method.init(true);
__method.show(true, __method);
return false;
});
//判断是否是实时数据,如果是将时间默认填充进去 added by johnnyzheng 12-06
if(this.mOpts.singleCompare){
if(this.mOpts.theme === \'ta\'){
$(\'#\' + __method.startDateId).val(__method.mOpts.startDate);
$(\'#\' + __method.endDateId).val(__method.mOpts.startDate);
$(\'#\' + __method.startCompareDateId).val(__method.mOpts.startCompareDate);
$(\'#\' + __method.endCompareDateId).val(__method.mOpts.startCompareDate);
}
else{
$(\'#\' + __method.startDateId).val(__method.mOpts.startDate);
$(\'#\' + __method.endDateId).val(__method.mOpts.startDate);
$(\'#\' + __method.startCompareDateId).val(__method.mOpts.startCompareDate);
$(\'#\' + __method.endCompareDateId).val(__method.mOpts.startCompareDate);
$(\'#\' + this.compareCheckboxId).attr(\'checked\',true);
$(\'#\' + this.mOpts.compareCheckboxId).attr(\'checked\',true);
}
}
// 时间对比
$(\'#\' + this.dateRangeCompareDiv).css(\'display\', $(\'#\' + this.compareCheckboxId).attr(\'checked\') ? \'\' : \'none\');
$(\'#\' + this.compareInputDiv).css(\'display\', $(\'#\' + this.compareCheckboxId).attr(\'checked\') ? \'\' : \'none\');
$(\'#\' + this.compareCheckboxId).bind(\'click\', function() {
$(\'#\' + __method.inputCompareId).css(\'display\', this.checked ? \'\' : \'none\');
// 隐藏对比时间选择
$(\'#\' + __method.dateRangeCompareDiv).css(\'display\', this.checked ? \'\' : \'none\');
$(\'#\' + __method.compareInputDiv).css(\'display\', this.checked ? \'\' : \'none\');
// 把两个对比时间框置为不可用
$(\'#\' + __method.startCompareDateId).css(\'disabled\', this.checked ? false : true);
$(\'#\' + __method.endCompareDateId).css(\'disabled\', this.checked ? false : true);
// 修改表单的 checkbox 状态
$(\'#\' + __method.mOpts.compareCheckboxId).attr(\'checked\', $(\'#\' + __method.compareCheckboxId).attr(\'checked\'));
// 修改表单的值
$(\'#\' + __method.mOpts.compareCheckboxId).val($(\'#\' + __method.compareCheckboxId).attr(\'checked\')?1:0);
// 初始化选框背景
if($(\'#\' + __method.compareCheckboxId).attr(\'checked\')) {
sDate = __method.str2date($(\'#\' + __method.startDateId).val());
sTime = sDate.getTime();
eDate = __method.str2date($(\'#\' + __method.endDateId).val());
eTime = eDate.getTime();
scDate = $(\'#\' + __method.startCompareDateId).val();
ecDate = $(\'#\' + __method.endCompareDateId).val();
if(\'\' == scDate || \'\' == ecDate) {
ecDate = __method.str2date(__method.date2ymd(sDate).join(\'-\'));
ecDate.setDate(ecDate.getDate() - 1);
scDate = __method.str2date(__method.date2ymd(sDate).join(\'-\'));
scDate.setDate(scDate.getDate() - ((eTime - sTime) / 86400000) - 1);
//这里要和STATS_START_TIME的时间进行对比,如果默认填充的对比时间在这个时间之前 added by johnnyzheng
if(ecDate.getTime() < __method.mOpts.minValidDate * 1000){
scDate = sDate;
ecDate = eDate;
}
if(ecDate.getTime() >= __method.mOpts.minValidDate * 1000 && scDate.getTime() < __method.mOpts.minValidDate * 1000){
scDate.setTime(__method.mOpts.minValidDate * 1000)
scDate = __method.str2date(__method.date2ymd(scDate).join(\'-\'));
ecDate.setDate(scDate.getDate() + ((eTime - sTime) / 86400000) - 1);
}
$(\'#\' + __method.startCompareDateId).val(__method.formatDate(__method.date2ymd(scDate).join(\'-\')));
$(\'#\' + __method.endCompareDateId).val(__method.formatDate(__method.date2ymd(ecDate).join(\'-\')));
}
__method.addCSS(1);
// 输入框焦点切换到比较开始时间
__method.changeInput(__method.startCompareDateId);
} else {
__method.removeCSS(1);
// 输入框焦点切换到开始时间
__method.changeInput(__method.startDateId);
}
//用户点击默认自动提交 added by johnnyzheng 12-08
__method.close(1);
__method.mOpts.success({\'startDate\': $(\'#\' + __method.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + __method.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + __method.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + __method.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + __method.mOpts.endCompareDateId).val()
});
});
// 初始化开始
this.init();
// 关闭日期选择框,并把结果反显到输入框
this.close(1);
if(this.mOpts.replaceBtn && $(\'#\'+this.mOpts.replaceBtn).length > 0){
$(\'#\'+ __method.compareCheckboxId).hide();
$(\'.contrast\').hide();
$(\'#\'+this.mOpts.replaceBtn).bind(\'click\', function(){
var self = this;
$(\'#\'+ __method.compareCheckboxId).attr(\'checked\')
? $(\'#\'+ __method.compareCheckboxId).removeAttr(\'checked\')
: $(\'#\'+ __method.compareCheckboxId).attr(\'checked\', \'checked\');
$(\'#\'+ __method.compareCheckboxId).click();
$(\'#\'+ __method.compareCheckboxId).attr(\'checked\')
? function(){
$(\'#\'+ __method.compareCheckboxId).removeAttr(\'checked\');
$(\'.contrast\').hide();
$(self).text(\'按时间对比\');
}()
: function(){
$(\'#\'+ __method.compareCheckboxId).attr(\'checked\', \'checked\');
$(\'.contrast\').show();
$(self).text(\'取消对比\');
}();
});
}
if(this.mOpts.autoCommit){
this.mOpts.success({\'startDate\': $(\'#\' + __method.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + __method.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + __method.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + __method.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + __method.mOpts.endCompareDateId).val()
});
}
//让用户点击页面即可关闭弹窗
$(document).bind(\'click\', function () {
__method.close();
});
};
/**
* @description 日期选择器的初始化方法,对象原型扩展
* @param {Boolean} isCompare 标识当前初始化选择面板是否是对比日期
*/
pickerDateRange.prototype.init = function(isCompare) {
var __method = this;
var minDate, maxDate;
var isNeedCompare = typeof(isCompare) != \'undefined\'? isCompare && $("#" + __method.compareCheckboxId).attr(\'checked\') : $("#" + __method.compareCheckboxId).attr(\'checked\');
// 清空日期列表的内容
$("#" + this.dateListId).empty();
// 如果开始日期为空,则取当天的日期为开始日期
var endDate = \'\' == this.mOpts.endDate ? (new Date()) : this.str2date(this.mOpts.endDate);
// 日历结束时间
this.calendar_endDate = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0);
//如果是magicSelect 自定义年和月份,则自定义填充日期
if(this.mOpts.magicSelect && this.mOpts.theme == \'ta\'){
var i = 0;
do{
var td = null;
if(i==0){
td = this.fillDate(this.str2date($(\'#\'+this.endDateId).val()).getFullYear(), this.str2date($(\'#\'+this.endDateId).val()).getMonth(), i);
$("#" + this.dateListId).append(td);
}
else{
td = this.fillDate(this.str2date($(\'#\'+this.startDateId).val()).getFullYear(), this.str2date($(\'#\'+this.startDateId).val()).getMonth(), i);
var firstTd = (this.mOpts.theme == \'ta\' ? $("#" + this.dateListId).find(\'table\').get(0) : $("#" + this.dateListId).find(\'td\').get(0));
$(firstTd).before(td);
}
i++;
}while(i<2);
// 日历开始时间
this.calendar_startDate = new Date(this.str2date($(\'#\'+this.startDateId).val()).getFullYear(), this.str2date($(\'#\'+this.startDateId).val()).getMonth(), 1);
}else{
// 计算并显示以 endDate 为结尾的最近几个月的日期列表
for(var i = 0; i < this.mOpts.calendars; i ++) {
var td = null;
if(this.mOpts.theme == \'ta\'){
td = this.fillDate(endDate.getFullYear(), endDate.getMonth(), i);
}
else{
td = document.createElement(\'td\');
$(td).append(this.fillDate(endDate.getFullYear(), endDate.getMonth(), i));
$(td).css(\'vertical-align\', \'top\');
}
if(0 == i) {
$("#" + this.dateListId).append(td);
} else {
var firstTd = (this.mOpts.theme == \'ta\' ? $("#" + this.dateListId).find(\'table\').get(0) : $("#" + this.dateListId).find(\'td\').get(0));
$(firstTd).before(td);
}
endDate.setMonth(endDate.getMonth() - 1, 1);
}
// 日历开始时间
this.calendar_startDate = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 1);
}
// 上一个月
$(\'#\' + this.preMonth).bind(\'click\', function() {
__method.calendar_endDate.setMonth(__method.calendar_endDate.getMonth() - 1, 1);
__method.mOpts.endDate = __method.date2ymd(__method.calendar_endDate).join(\'-\');
__method.init(isCompare);
//如果是单月选择的时候,要控制input输入框 added by johnnyzheng 2011-12-19
if(1 == __method.mOpts.calendars){
if(\'\' == $(\'#\' + __method.startDateId).val()){
__method.changeInput(__method.startDateId);
}
else{
__method.changeInput(__method.endDateId);
}
}
return false;
});
// 下一个月
$(\'#\' + this.nextMonth).bind(\'click\', function() {
__method.calendar_endDate.setMonth(__method.calendar_endDate.getMonth() + 1, 1);
__method.mOpts.endDate = __method.date2ymd(__method.calendar_endDate).join(\'-\');
__method.init(isCompare);
//如果是单月选择的时候,要控制input输入框 added by johnnyzheng 2011-12-19
if(1 == __method.mOpts.calendars){
if(\'\' == $(\'#\' + __method.startDateId).val()){
__method.changeInput(__method.startDateId);
}
else{
__method.changeInput(__method.endDateId);
}
}
return false;
});
//如果有用户自定义选择月份,则为其绑定事件
if(this.mOpts.magicSelect) this.bindChangeForSelect();
// 初始化时间选区背景
if(this.endDateId != this.dateInput && this.endCompareDateId != this.dateInput) {
(isNeedCompare && typeof(isCompare) !=\'undefined\') ? this.addCSS(1) : this.addCSS(0);
}
if(isNeedCompare && typeof(isCompare) !=\'undefined\'){
__method.addCSS(1);
}
else{
__method.addCSS(0);
}
// 隐藏对比日期框
$(\'#\' + __method.inputCompareId).css(\'display\', isNeedCompare ? \'\' : \'none\');
$(\'#\' + this.compareInputDiv).css(\'display\', $(\'#\' + this.compareCheckboxId).attr(\'checked\') ? \'\' : \'none\');
//昨天,今天,最近7天,最近30天快捷的点击,样式要自己定义,id可以传递默认,也可覆盖
for(var property in __method.periodObj){
if($(\'#\'+ property).length > 0){
$(\'#\' + property).unbind(\'click\');
$(\'#\' + property).bind(\'click\' , function(){
//处理点击样式
var cla = __method.mOpts.theme == \'ta\' ? \'active\' : \'a\';
$(this).parent().nextAll().removeClass(cla);
$(this).parent().prevAll().removeClass(cla);
$(this).parent().addClass(cla);
//拼接提交时间串
var timeObj = __method.getSpecialPeriod(__method.periodObj[$(this).attr(\'id\')]);
$(\'#\' + __method.startDateId).val(__method.formatDate(timeObj.otherday));
$(\'#\' + __method.endDateId).val(__method.formatDate(timeObj.today));
$(\'#\' + __method.mOpts.startDateId).val($(\'#\' + __method.startDateId).val());
$(\'#\' + __method.mOpts.endDateId).val($(\'#\' + __method.endDateId).val());
__method.mOpts.theme == \'ta\' ? $(\'#\'+__method.compareInputDiv).hide() : $(\'#\' + __method.inputCompareId).css(\'display\',\'none\');
$(\'#\' + __method.compareCheckboxId).attr(\'checked\', false);
$(\'#\' + __method.mOpts.compareCheckboxId).attr(\'checked\', false);
$(\'#\' + this.compareInputDiv).css(\'display\', $(\'#\' + this.compareCheckboxId).attr(\'checked\') ? \'\' : \'none\');
__method.close(1);
//于此同时清空对比时间框的时间
$(\'#\' + __method.startCompareDateId).val(\'\');
$(\'#\' + __method.endCompareDateId).val(\'\');
$(\'#\' + __method.mOpts.startCompareDateId).val(\'\');
$(\'#\' + __method.mOpts.endCompareDateId).val(\'\');
$(\'#\' + __method.mOpts.compareCheckboxId).val(0);
if($(\'#\'+ __method.mOpts.replaceBtn).length > 0){
$(\'.contrast\').hide();
$(\'#\'+ __method.mOpts.replaceBtn).text(\'按时间对比\');
}
//点击提交
__method.mOpts.success({\'startDate\': $(\'#\' + __method.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + __method.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + __method.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + __method.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + __method.mOpts.endCompareDateId).val()
});
});
}
}
// 让用户手动关闭或提交日历,每次初始化的时候绑定,关闭的时候解绑 by zacharycai
$(document).bind(\'click\', function () {
__method.close();
});
//完全清空日期控件的值 by zacharycai
$(\'#\' + this.inputId).bind(\'change\', function(){
if ($(this).val() === \'\'){
$(\'#\' + __method.startDateId).val(\'\');
$(\'#\' + __method.endDateId).val(\'\');
$(\'#\' + __method.startCompareDateId).val(\'\');
$(\'#\' + __method.endCompareDateId).val(\'\');
}
})
};
pickerDateRange.prototype.bindChangeForSelect = function(){
var __method = this;
//气泡弹窗
var _popup = function(btn, ctn, wrap, css) {
css = css || \'open\';
var ITEMS_TIMEOUT = null, time_out = 500;
function hidePop() {
$(\'#\' + ctn).removeClass(css);
}
function showPop() {
$(\'#\' + ctn).addClass(css);
}
function isPopShow() {
return $(\'#\' + ctn).attr(\'class\') == css;
}
$("#" + btn).click(function() {
isPopShow() ? hidePop() : showPop();
}).mouseover(function() {
clearTimeout(ITEMS_TIMEOUT);
}).mouseout(function() {
ITEMS_TIMEOUT = setTimeout(hidePop, time_out);
});
$(\'#\' + wrap).mouseover(function() {
clearTimeout(ITEMS_TIMEOUT);
}).mouseout(function() {
ITEMS_TIMEOUT = setTimeout(hidePop, time_out);
});
};
//自定义选择的触发动作
try{
$("#" + this.dateListId).find(\'div[id*="selected"]\').each(function(){
//绑定pop
var _match = $(this).attr(\'id\').match(/(\w+)_(\d)/i);
if(_match){
var _name = _match[1];//名称
var _idx = _match[2];//下标
if(_name==\'yselected\'){
_popup(\'_ybtn_\'+_idx, $(this).attr(\'id\'), \'_yctn_\'+_idx);
}
else if(_name==\'mselected\'){
_popup(\'_mbtn_\'+_idx, $(this).attr(\'id\'), \'_mctn_\'+_idx);
}
$(this).find(\'li a\').each(function(){
$(this).click(function() {
var match = $(this).parents(\'.select_wrap\').attr(\'id\').match(/(\w+)_(\d)/i);
//if(match){
var name = match[1];//名称
var idx = match[2];//下标
var nt = null;
if(idx^1 == 0){
//开始
if(name == \'yselected\'){
__method.calendar_startDate.setYear($(this).text()*1 , 1);
//__method.calendar_startDate.setMonth(__method.str2date($(\'#\'+__method.startDateId).val()).getMonth(), 1);
}
else if(name=\'mselected\'){
//__method.calendar_startDate.setYear(__method.str2date($(\'#\'+__method.startDateId).val()).getFullYear(), 1);
__method.calendar_startDate.setMonth($(this).text()*1-1, 1);
}
__method.mOpts.startDate = __method.date2ymd(__method.calendar_startDate).join(\'-\');
nt = __method.fillDate(__method.calendar_startDate.getFullYear(), __method.calendar_startDate.getMonth(), idx);
}
else{
//结束
if(name == \'yselected\'){
__method.calendar_endDate.setYear($(this).text()*1 , 1);
//__method.calendar_endDate.setMonth(__method.str2date($(\'#\'+__method.endDateId).val()).getMonth(), 1);
}
else if(name=\'mselected\'){
//__method.calendar_endDate.setYear(__method.str2date($(\'#\'+__method.endDateId).val()).getFullYear(), 1);
__method.calendar_endDate.setMonth($(this).text()*1-1, 1);
}
__method.mOpts.endDate = __method.date2ymd(__method.calendar_endDate).join(\'-\');
nt = __method.fillDate(__method.calendar_endDate.getFullYear(), __method.calendar_endDate.getMonth(), idx);
}
var tb = $("#" + __method.dateListId).find(\'table\').get(idx^1);
$(tb).replaceWith(nt);
//}
__method.removeCSS(0);
__method.bindChangeForSelect();
});
});
}
});
}catch(e){
window.console && console.log(e);
}
}
/**
* @description 计算今天,昨天,最近7天,最近30天返回的时间范围
* @param {Num} period 快捷选择的时间段,今天、昨天、最近7天、最近30天
*/
pickerDateRange.prototype.getSpecialPeriod = function(period){
var __method = this;
var date = new Date();
//如果今天不可用,则从昨天向前推 added by johnnyzheng 12-07
(true == __method.mOpts.isTodayValid && (\'\' != __method.mOpts.isTodayValid) || 2 > period)? \'\' : date.setTime(date.getTime() - ( 1 * 24 * 60 * 60 * 1000));
var timeStamp = ((date.getTime()- ( period * 24 * 60 * 60 * 1000)) < (__method.mOpts.minValidDate * 1000)) ? (__method.mOpts.minValidDate * 1000) : (date.getTime()- ( period * 24 * 60 * 60 * 1000)) ;
var todayStr = date.getFullYear() + \'-\' + (date.getMonth()+ 1 ) + \'-\' + date.getDate();
date.setTime(timeStamp);
var otherdayStr = date.getFullYear() + \'-\' + (date.getMonth()+ 1 ) + \'-\' + date.getDate();
if(period == __method.periodObj.aYesterday){
todayStr = otherdayStr;
}
return {today: todayStr , otherday : otherdayStr};
}
pickerDateRange.prototype.getCurrentDate = function(){
return {
\'startDate\': $(\'#\' + this.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + this.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + this.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + this.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + this.mOpts.endCompareDateId).val()
};
};
/**
* @description 移除选择日期面板的样式
* @param {Boolean} isCompare 是否是对比日期面板
* @param {String} specialClass 特殊的样式,这里默认是常规和对比日期两种样式的重合样式
*/
pickerDateRange.prototype.removeCSS = function(isCompare, specialClass) {
// 初始化对比时间重合部分的样式类
if(\'undefined\' == typeof(specialClass)) {
specialClass = this.mOpts.theme + \'_\' + this.mOpts.coincideCss;
}
// 是否移除对比部分的样式:0 日期选择;1 对比日期选择
if(\'undefined\' == typeof(isCompare)) {
isCompare = 0;
}
// 整个日期列表的开始日期
var s_date = this.calendar_startDate;
var e_date = this.calendar_endDate;
//如果是用户自定义选择的话,需要充值样式边界日期
if(this.mOpts.magicSelect){
s_date = this.str2date($(\'#\'+this.startDateId).val());
e_date = this.str2date($(\'#\'+this.endDateId).val());
}
var bDate = new Date(s_date.getFullYear(), s_date.getMonth(), s_date.getDate());
var cla = \'\';
// 从开始日期循环到结束日期
for(var d = new Date(bDate); d.getTime() <= e_date.getTime(); d.setDate(d.getDate() + 1)) {
if(0 == isCompare) {
// 移除日期样式
cla = this.mOpts.theme + \'_\' + this.mOpts.selectCss;
} else {
// 移除对比日期样式
cla = this.mOpts.theme + \'_\' + this.mOpts.compareCss;
}
// 移除指定样式
$(\'#\'+ this.calendarId + \'_\' + this.date2ymd(d).join(\'-\')).removeClass(cla);
$(\'#\'+ this.calendarId + \'_\' + this.date2ymd(d).join(\'-\')).removeClass(this.mOpts.firstCss).removeClass(this.mOpts.lastCss).removeClass(this.mOpts.clickCss);
}
};
/**
* @description 为选中的日期加上样式:1=比较时间;0=时间范围
* @param {Boolean} isCompare 是否是对比日期面板
* @param {String} specialClass 特殊的样式,这里默认是常规和对比日期两种样式的重合样式
*/
pickerDateRange.prototype.addCSS = function(isCompare, specialClass) {
// 初始化对比时间重合部分的样式类
if(\'undefined\' == typeof(specialClass)) {
specialClass = this.mOpts.theme + \'_\' + this.mOpts.coincideCss;
}
// 是否移除对比部分的样式:0 日期选择;1 对比日期选择
if(\'undefined\' == typeof(isCompare)) {
isCompare = 0;
}
// 获取4个日期
var startDate = this.str2date($(\'#\' + this.startDateId).val());
var endDate = this.str2date($(\'#\' + this.endDateId).val());
var startCompareDate = this.str2date($(\'#\' + this.startCompareDateId).val());
var endCompareDate = this.str2date($(\'#\' + this.endCompareDateId).val());
// 循环开始日期
var sDate = 0 == isCompare ? startDate : startCompareDate;
// 循环结束日期
var eDate = 0 == isCompare ? endDate : endCompareDate;
var cla = \'\';
for(var d = new Date(sDate); d.getTime() <= eDate.getTime(); d.setDate(d.getDate() + 1)) {
if(0 == isCompare) {
// 添加日期样式
cla = this.mOpts.theme + \'_\' + this.mOpts.selectCss;
$(\'#\' + this.calendarId + \'_\' + this.date2ymd(d).join(\'-\')).removeClass(this.mOpts.firstCss).removeClass(this.mOpts.lastCss).removeClass(this.mOpts.clickCss);
$(\'#\' + this.calendarId + \'_\' + this.date2ymd(d).join(\'-\')).removeClass(cla);
} else {
// 添加对比日期样式
cla = this.mOpts.theme + \'_\' + this.mOpts.compareCss;
}
$(\'#\' + this.calendarId + \'_\' + this.date2ymd(d).join(\'-\')).attr(\'class\', cla);
}
if(this.mOpts.theme == \'ta\'){
//为开始结束添加特殊样式
$(\'#\' + this.calendarId + \'_\' + this.date2ymd(new Date(sDate)).join(\'-\')).removeClass().addClass(this.mOpts.firstCss);
$(\'#\' + this.calendarId + \'_\' + this.date2ymd(new Date(eDate)).join(\'-\')).removeClass().addClass(this.mOpts.lastCss);
//如果开始结束时间相同
sDate.getTime() == eDate.getTime() && $(\'#\'+ this.calendarId + \'_\' + this.date2ymd(new Date(eDate)).join(\'-\')).removeClass().addClass(this.mOpts.clickCss);
}
};
/**
* @description 判断开始、结束日期是否处在允许的范围内
* @param {String} startYmd 开始时间字符串
* @param {String} endYmd 结束时间字符串
*/
pickerDateRange.prototype.checkDateRange = function(startYmd, endYmd) {
var sDate = this.str2date(startYmd);
var eDate = this.str2date(endYmd);
var sTime = sDate.getTime();
var eTime = eDate.getTime();
var minEDate, maxEDate;
if(eTime >= sTime) {
// 判断是否超过最大日期外
maxEDate = this.str2date(startYmd);
maxEDate.setMonth(maxEDate.getMonth() + this.mOpts.monthRangeMax);
maxEDate.setDate(maxEDate.getDate() + this.mOpts.dayRangeMax - 1);
if(maxEDate.getTime() < eTime) {
alert(\'结束日期不能大于:\' + this.date2ymd(maxEDate).join(\'-\'));
return false;
}
} else {
// 判断是否超过最大日期外
//maxEDate = this.str2date(stPartYmd);
maxEDate = this.str2date(endYmd);
maxEDate.setMonth(maxEDate.getMonth() - this.mOpts.monthRangeMax);
maxEDate.setDate(maxEDate.getDate() - this.mOpts.dayRangeMax + 1);
if(maxEDate.getTime() > eTime) {
alert(\'开始日期不能小于:\' + this.date2ymd(maxEDate).join(\'-\'));
return false;
}
}
return true;
}
/**
* @description 选择日期
* @param {String} ymd 时间字符串
*/
pickerDateRange.prototype.selectDate = function(ymd) {
//点击日期点的时候添加对应输入框的样式,而不是之前的 聚焦到输入框时显示样式 by zacharycai
this.changeInput(this.dateInput);
// 格式化日期
var ymdFormat = this.formatDate(ymd);
// start <-> end 切换
if(this.startDateId == this.dateInput) {
// 移除样式
this.removeCSS(0);
this.removeCSS(1);
// 为当前点加样式
$(\'#\'+ this.calendarId + \'_\' + ymd).attr(\'class\', (this.mOpts.theme == \'ta\' ? this.mOpts.clickCss : this.mOpts.theme + \'_\' + this.mOpts.selectCss));
// 获取开始时间的初始值
this.startDefDate = $(\'#\' + this.dateInput).val();
// 更改对应输入框的值
$(\'#\' + this.dateInput).val(ymdFormat);
// 切换输入框焦点,如果是实时数据那么选择一天的数据
if (true == this.mOpts.singleCompare || true == this.mOpts.isSingleDay) {
this.dateInput = this.startDateId;
$(\'#\' + this.endDateId).val(ymdFormat);
(this.mOpts.shortOpr || this.mOpts.autoSubmit) && this.close(1);
this.mOpts.success({\'startDate\': $(\'#\' + this.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + this.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + this.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + this.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + this.mOpts.endCompareDateId).val()
});
} else {
this.dateInput = this.endDateId;
}
} else if(this.endDateId == this.dateInput) {
// 如果开始时间未选
if(\'\' == $(\'#\' + this.startDateId).val()) {
this.dateInput = this.startDateId;
this.selectDate(ymd);
return false;
}
// 判断用户选择的时间范围
if(false == this.checkDateRange($(\'#\' + this.startDateId).val(), ymd)) {
return false;
}
// 如果结束时间小于开始时间
if(-1 == this.compareStrDate(ymd, $(\'#\' + this.startDateId).val())) {
// 更改对应输入框的值(结束时间)
$(\'#\' + this.dateInput).val($(\'#\' + this.startDateId).val());
// 更改对应输入框的值(开始时间)
$(\'#\' + this.startDateId).val(ymdFormat);
ymdFormat = $(\'#\' + this.dateInput).val();
}
// 更改对应输入框的值
$(\'#\' + this.dateInput).val(ymdFormat);
// 切换输入框焦点
this.dateInput = this.startDateId;
this.removeCSS(0);
this.addCSS(0);
//this.addCSS(0, this.mOpts.coincideCss);
this.startDefDate = \'\';
if(this.mOpts.autoSubmit){
this.close(1);
this.mOpts.success({\'startDate\': $(\'#\' + this.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + this.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + this.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + this.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + this.mOpts.endCompareDateId).val()
});
}
} else if(this.startCompareDateId == this.dateInput) {
// 移除样式
this.removeCSS(1);
this.removeCSS(0);
// 为当前点加样式
$(\'#\'+ this.calendarId + \'_\' + ymd).attr(\'class\', (this.mOpts.theme == \'ta\' ? this.mOpts.clickCss : this.mOpts.theme + \'_\' + this.mOpts.compareCss));
// 获取开始时间的初始值
this.startDefDate = $(\'#\' + this.dateInput).val();
// 更改对应输入框的值
$(\'#\' + this.dateInput).val(ymdFormat);
// 切换输入框焦点
if (true == this.mOpts.singleCompare || true == this.mOpts.isSingleDay) {
this.dateInput = this.startCompareDateId;
$(\'#\' + this.endCompareDateId).val(ymdFormat);
(this.mOpts.shortOpr || this.mOpts.autoSubmit) && this.close(1);
this.mOpts.success({\'startDate\': $(\'#\' + this.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + this.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + this.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + this.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + this.mOpts.endCompareDateId).val()
});
}
else{
this.dateInput = this.endCompareDateId;
}
} else if(this.endCompareDateId == this.dateInput) {
// 如果开始时间未选
if(\'\' == $(\'#\' + this.startCompareDateId).val()) {
this.dateInput = this.startCompareDateId;
this.selectDate(ymd);
return false;
}
// 判断用户选择的时间范围
if(false == this.checkDateRange($(\'#\' + this.startCompareDateId).val(), ymd)) {
return false;
}
// 如果结束时间小于开始时间
if(-1 == this.compareStrDate(ymd, $(\'#\' + this.startCompareDateId).val())) {
// 更改对应输入框的值(结束时间)
$(\'#\' + this.dateInput).val($(\'#\' + this.startCompareDateId).val());
// 更改对应输入框的值(开始时间)
$(\'#\' + this.startCompareDateId).val(ymdFormat);
ymdFormat = $(\'#\' + this.dateInput).val();
}
// 更改对应输入框的值
$(\'#\' + this.dateInput).val(ymdFormat);
// 切换输入框焦点
this.dateInput = this.startCompareDateId;
//this.addCSS(1, this.mOpts.coincideCss);
this.removeCSS(1);
this.addCSS(1);
this.startDefDate = \'\';
if(this.mOpts.autoSubmit){
this.close(1);
this.mOpts.success({\'startDate\': $(\'#\' + this.mOpts.startDateId).val(),
\'endDate\': $(\'#\' + this.mOpts.endDateId).val(),
\'needCompare\' : $(\'#\' + this.mOpts.compareCheckboxId).val(),
\'startCompareDate\':$(\'#\' + this.mOpts.startCompareDateId).val(),
\'endCompareDate\':$(\'#\' + this.mOpts.endCompareDateId).val()
});
}
}
// 切换到下一个输入框
// this.changeInput(this.dateInput);
};
/**
* @description显示日期选择框
* @param {Boolean} isCompare 是否是对比日期选择框
* @param {Object} __method 时期选择器超级对象
*/
pickerDateRange.prototype.show = function(isCompare, __method) {
$(\'#\' + __method.dateRangeDiv).css(\'display\', isCompare ? \'none\' : \'\');
$(\'#\' + __method.dateRangeCompareDiv).css(\'display\', isCompare ? \'\' : \'none\');
var pos = isCompare ? $(\'#\' + this.inputCompareId).offset() : $(\'#\' + this.inputId).offset();
var offsetHeight = isCompare ? $(\'#\' + this.inputCompareId).height() : $(\'#\' + this.inputId).height();
var clientWidth = parseInt($(document.body)[0].clientWidth);
var left = pos.left;
$("#" + this.calendarId).css(\'display\', \'block\');
if (true == this.mOpts.singleCompare || true == this.mOpts.isSingleDay) {
$(\'#\' + this.endDateId).css(\'display\', \'none\');
$(\'#\' + this.endCompareDateId).css(\'display\',\'none\');
$(\'#\' + this.mOpts.joinLineId).css(\'display\', \'none\');
$(\'.\' + this.mOpts.joinLineId).css(\'display\', \'none\');
}
// 如果和输入框左对齐时超出了宽度范围,则右对齐
if(0 < clientWidth && $("#" + this.calendarId).width() + pos.left > clientWidth) {
left = pos.left + $(\'#\' + this.inputId).width() - $("#" + this.calendarId).width() + ((/msie/i.test(navigator.userAgent) && !(/opera/i.test(navigator.userAgent)))? 5 : 0) ;
__method.mOpts.theme==\'ta\' && (left += 50);
}
$("#" + this.calendarId).css(\'left\', left + \'px\');
//$("#" + this.calendarId).css(\'top\', pos.top + (offsetHeight ? offsetHeight- 1 : (__method.mOpts.theme==\'ta\'?35:22)) + \'px\');
$("#" + this.calendarId).css(\'top\', pos.top + (__method.mOpts.theme==\'ta\'?35:22) + \'px\');
//第一次显示的时候,一定要初始化输入框
isCompare ? this.changeInput(this.startCompareDateId) : this.changeInput(this.startDateId);
return false;
};
/**
* @description 关闭日期选择框
* @param {Boolean} btnSubmit 是否是点击确定按钮关闭的
*/
pickerDateRange.prototype.close = function(btnSubmit) {
var __method = this;
//by zacharycai 关闭后就解绑了
//$(document).unbind(\'click\');
// 把开始、结束时间显示到输入框 (PS:如果选择的今日,昨日,则只填入一个日期)
// 如果开始和结束同个时间也照样分段by zacharycai
//$(\'#\' + this.inputId).val($(\'#\' + this.startDateId).val() + ($(\'#\' + this.startDateId).val() == $(\'#\' + this.endDateId).val() ? \'\' : this.mOpts.defaultText + $(\'#\' + this.endDateId).val()));
if(btnSubmit){
//如果是单日快捷选择
if (this.mOpts.shortOpr === true){
$(\'#\' + this.inputId).val($(\'#\' + this.startDateId).val());
$(\'#\' + this.inputCompareId).val($(\'#\' + this.startCompareDateId).val());
}else{
$(\'#\' + this.inputId).val($(\'#\' + this.startDateId).val() + (\'\' == $(\'#\' + this.endDateId).val() ? \'\' : this.mOpts.defaultText + $(\'#\' + this.endDateId).val()));
}
//判断当前天是否可选,来决定从后往前推修改日期是从哪一点开始
var nDateTime = ((true == this.mOpts.isTodayValid && \'\' != this.mOpts.isTodayValid)) ? new Date().getTime() : new Date().getTime() - (1 * 24 * 60 * 60 * 1000);
var bDateTime = this.str2date($(\'#\' + this.startDateId).val()).getTime();
var eDateTime = this.str2date($(\'#\' + this.endDateId).val()).getTime();
//如果endDateTime小于bDateTime 相互交换
if(eDateTime < bDateTime){
var tmp = $(\'#\' + this.startDateId).val();
$(\'#\' + this.startDateId).val($(\'#\' + this.endDateId).val());
$(\'#\' + this.endDateId).val(tmp);
}
var _val = this.mOpts.shortOpr == true ? $(\'#\' + this.startDateId).val() : ($(\'#\' + this.startDateId).val() + (\'\' == $(\'#\' + this.endDateId).val() ? \'\' : this.mOpts.defaultText + $(\'#\' + this.endDateId).val()));
// 把开始、结束时间显示到输入框 (PS:如果选择的今日,昨日,则只填入一个日期)
var input = document.getElementById(this.inputId);
if(input && input.tagName == \'INPUT\'){
$(\'#\' + this.inputId).val(_val);
$(\'#\'+this.inputCompareId).is(\':visible\') && $(\'#\'+this.inputCompareId).val(_compareVal);
}else{
$(\'#\' + this.inputId).html(_val);
$(\'#\'+this.inputCompareId).is(\':visible\') && $(\'#\'+this.inputCompareId).html(_compareVal);
}
////在js侧就做好日期校准,以前面的日期选择的跨度为准,如果后面的跨度超过了当前可用时间,则以当前可用时间向前推 added by johnnyzheng 11-29
if(this.mOpts.theme != \'ta\'){
if(\'\' != $(\'#\' + this.startCompareDateId).val() && \'\' != $(\'#\' + this.endCompareDateId).val()){
var bcDateTime = this.str2date($(\'#\' + this.startCompareDateId).val()).getTime();
var ecDateTime = this.str2date($(\'#\' + this.endCompareDateId).val()).getTime();
var _ecDateTime = bcDateTime + eDateTime - bDateTime;
if(_ecDateTime > nDateTime){
//如果计算得到的时间超过了当前可用时间,那么就和服务器端保持一致,将当前可用的天数向前推日期选择器的跨度 added by johnnyzheng 11-29
_ecDateTime = nDateTime;
$(\'#\' + this.startCompareDateId).val(this.formatDate(this.date2ymd(new Date(_ecDateTime + bDateTime - eDateTime)).join(\'-\')));
}
$(\'#\' + this.endCompareDateId).val(this.formatDate(this.date2ymd(new Date(_ecDateTime)).join(\'-\')));
//把开始结束对比时间大小重新矫正一下
var bcDateTime = this.str2date($(\'#\' + this.startCompareDateId).val()).getTime();
var ecDateTime = this.str2date($(\'#\' + this.endCompareDateId).val()).getTime();
if(ecDateTime < bcDateTime){
var tmp = $(\'#\' + this.startCompareDateId).val();
$(\'#\' + this.startCompareDateId).val($(\'#\' + this.endCompareDateId).val());
$(\'#\' + this.endCompareDateId).val(tmp);
}
}
}
//把对比时间填入输入框 (PS:如果选择今日,昨日,则只填入一个日期)
//$(\'#\' + this.inputCompareId).val($(\'#\' + this.startCompareDateId).val() + this.mOpts.defaultText + $(\'#\' + this.endCompareDateId).val());
var _compareVal = this.mOpts.shortOpr == true ? $(\'#\' + this.startCompareDateId).val() : ($(\'#\' + this.startCompareDateId).val() + (\'\' == $(\'#\' + this.endCompareDateId).val() ? \'\' : this.mOpts.defaultText + $(\'#\' + this.endCompareDateId).val()));
if(input && input.tagName == \'INPUT\'){
$(\'#\' + this.inputCompareId).val(_compareVal);
}else{
$(\'#\' + this.inputCompareId).html(_compareVal);
}
// 计算相隔天数
var step = (bDateTime - eDateTime) / 86400000;
// 更改目标元素值
$(\'#\' + this.mOpts.startDateId).val($(\'#\' + this.startDateId).val());
$(\'#\' + this.mOpts.endDateId).val($(\'#\' + this.endDateId).val());
$(\'#\' + this.mOpts.startCompareDateId).val($(\'#\' + this.startCompareDateId).val());
$(\'#\' + this.mOpts.endCompareDateId).val($(\'#\' + this.endCompareDateId).val());
//点击确定按钮进行查询后将取消所有的今天 昨天 最近7天的快捷链接 added by johnnyzheng 11-29
for(var property in this.periodObj){
if($(\'#\' + this.mOpts[property])){
$(\'#\' + this.mOpts[property]).parent().removeClass(\'a\');
}
}
}
// 隐藏日期选择框 延迟200ms 关闭日期选择框
$("#" + __method.calendarId).css(\'display\', \'none\');
return false;
};
/**
* @description 日期填充函数
* @param {Num} year 年
* @param {Num} month 月
*/
pickerDateRange.prototype.fillDate = function(year, month, index) {
var __method = this;
var isTaTheme = this.mOpts.theme == \'ta\';
// 当月第一天
var firstDayOfMonth = new Date(year, month, 1);
var dateBegin = new Date(year, month, 1);
var w = dateBegin.getDay();
// 计算应该开始的日期
dateBegin.setDate(1 - w);
// 当月最后一天
var lastDayOfMonth = new Date(year, month + 1, 0);
var dateEnd = new Date(year, month + 1, 0);
w = dateEnd.getDay();
// 计算应该结束的日期
dateEnd.setDate(dateEnd.getDate() + 6 - w);
var today = new Date();
var dToday = today.getDate();
var mToday = today.getMonth();
var yToday = today.getFullYear();
var table = document.createElement(\'table\');
if(isTaTheme){
table.className = this.mOpts.dateTable;
cap = document.createElement(\'caption\');
//如果是magicSelect,用户自定义的选择年和月份
if(this.mOpts.magicSelect){
var yh = [\'<div class="select_wrap" id="yselected_\'+index+\'"><div class="select" id="_ybtn_\'+index+\'">\'+year+\'</div><div class="dropdown" id="_yctn_\'+index+\'"><ul class="list_menu">\']
var mh = [\'<div class="select_wrap" id="mselected_\'+index+\'"><div class="select" id="_mbtn_\'+index+\'">\'+(month+1)+\'</div><div class="dropdown" id="_mctn_\'+index+\'"><ul class="list_menu">\']
//var yh = [\'<select name="yselected_\'+index+\'" class="xxxs">\'];
//var mh = [\'<select name="mselected_\'+index+\'" class="xxxs">\'];
i=1;
yt = yToday;
do{
//yh.push(\'<option value="\'+yt+\'" \'+(yt == year? \'selected\' : \'\')+\'>\'+(yt--)+\'</option>\');
//mh.push(\'<option value="\'+i+\'" \'+(i == (month+1)? \'selected\' : \'\')+\'>\'+(i++)+\'</option>\');
yh.push(\'<li><a href="javascript:;">\'+(yt--)+\'</a></li>\');
mh.push(\'<li><a href="javascript:;">\'+(i++)+\'</a></li>\');
}while(i <= 12);
//yh.push(\'</select>\');
//mh.push(\'</select>\');
yh.push(\'</ul></div></div>\');
mh.push(\'</ul></div></div>\');
$(cap).append(yh.join(\'\') +\'<span class="joinLine"> 年 </span>\'+mh.join(\'\')+\'<span class="joinLine"> 月 </span>\');
}
else{
$(cap).append(year + \'年\' + (month + 1) + \'月\');
}
$(table).append(cap);
thead = document.createElement(\'thead\');
tr = document.createElement(\'tr\');
var days = [\'周日\', \'周一\', \'周二\', \'周三\', \'周四\', \'周五\', \'周六\'];
for(var i = 0; i < 7; i ++) {
th = document.createElement(\'th\');
$(th).append(days[i]);
$(tr).append(th);
}
$(thead).append(tr);
$(table).append(thead);
tr = document.createElement(\'tr\');
td = document.createElement(\'td\');
// 如果是最后一个月的日期,则加上下一个月的链接
if(!this.mOpts.magicSelect){
if(0 == index) {
$(td).append(\'<a href="javascript:void(0);" id="\' + this.nextMonth + \'"><i class="i_next"></i></a>\');
}
// 如果是第一个月的日期,则加上上一个月的链接
if(index + 1 == this.mOpts.calendars) {
$(td).append(\'<a href="javascript:void(0);" id="\' + this.preMonth + \'"><i class="i_pre"></i></a>\');
}
}
// $(td).append(\'<span style="font-size:16px">\' + year + \'年\' + (month + 1) + \'月\' + \'</span>\');
$(td).attr(\'colSpan\', 7);
$(td).css(\'text-align\', \'center\');
$(tr).append(td);
$(table).append(tr);
}
else{
table.className = this.mOpts.theme + \'_\' + this.mOpts.dateTable;
tr = document.createElement(\'tr\');
td = document.createElement(\'td\');
// 如果是最后一个月的日期,则加上下一个月的链接
if(0 == index) {
$(td).append(\'<a href="javascript:void(0);" id="\' + this.nextMonth + \'" class="gri_dateRangeNextMonth"><span>next</span></a>\');
}
// 如果是第一个月的日期,则加上上一个月的链接
if(index + 1 == this.mOpts.calendars) {
$(td).append(\'<a href="javascript:void(0);" id="\' + this.preMonth + \'" class="gri_dateRangePreMonth"><span>pre</span></a>\');
}
$(td).append(year + \'年\' + (month + 1) + \'月\');
$(td).attr(\'colSpan\', 7);
$(td).css(\'text-align\', \'center\');
$(td).css(\'background-color\', \'#F9F9F9\');
$(tr).append(td);
$(table).append(tr);
var days = [\'日\', \'一\', \'二\', \'三\', \'四\', \'五\', \'六\'];
tr = document.createElement(\'tr\');
for(var i = 0; i < 7; i ++) {
td = document.createElement(\'td\');
$(td).append(days[i]);
$(tr).append(td);
}
$(table).append(tr);
}
// 当前月的所有日期(包括空白位置填充的日期)
var tdClass = \'\', deviation = 0, ymd = \'\';
for(var d = dateBegin; d.getTime() <= dateEnd.getTime(); d.setDate(d.getDate() + 1)) {
if(d.getTime() < firstDayOfMonth.getTime()) { // 当前月之前的日期
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'-1\';
} else if(d.getTime() > lastDayOfMonth.getTime()) { // 当前月之后的日期
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'1\';
} else if((this.mOpts.stopToday == true && d.getTime() < today.getTime()) || d.getTime() < __method.mOpts.minValidDate * 1000 || (\'\' !== __method.mOpts.maxValidDate && d.getTime() > __method.mOpts.maxValidDate * 1000)) { // 当前时间之后的日期,或者开启统计之前的日期
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'2\';
} else { // 当前月日期
deviation = \'0\';
if(d.getDate() == dToday && d.getMonth() == mToday && d.getFullYear() == yToday) {
if (true == this.mOpts.isTodayValid) {
tdClass = this.mOpts.theme + \'_\' + this.mOpts.isToday;
} else {
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'2\';
}
}
else {
tdClass = \'\';
}
//让周末不可选不可选
if(this.mOpts.weekendDis && (d.getDay()==6 || d.getDay()==0)){
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'3\';
}
//让周几不可选
if(this.mOpts.disCertainDay && this.mOpts.disCertainDay.length > 0 ){
for(var p in this.mOpts.disCertainDay){
if(!isNaN(this.mOpts.disCertainDay[p]) && d.getDay() === this.mOpts.disCertainDay[p]){
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'4\';
}
}
}
//让几号不可选
if(this.mOpts.disCertainDate && this.mOpts.disCertainDate.length > 0 ){
var isDisabled = false;
for(var p in this.mOpts.disCertainDate){
if(!isNaN(this.mOpts.disCertainDate[p]) || isNaN(parseInt(this.mOpts.disCertainDate[p]))){
if ( this.mOpts.disCertainDate[0] === true ){
isDisabled = !!(d.getDate() !== this.mOpts.disCertainDate[p]);
if ( !isDisabled ){
break;
}
}else {
isDisabled = !!(d.getDate() === this.mOpts.disCertainDate[p]);
if ( isDisabled ){
break;
}
}
}
}
if ( isDisabled ){
tdClass = this.mOpts.theme + \'_\' + this.mOpts.disableGray;
deviation = \'4\';
}
}
}
// 如果是周日
if(0 == d.getDay()) {
tr = document.createElement(\'tr\');
}
td = document.createElement(\'td\');
td.innerHTML = d.getDate();
if(\'\' != tdClass) {
$(td).attr(\'class\', tdClass);
}
// 只有当前月可以点击
if(0 == deviation) {
ymd = d.getFullYear() + \'-\' + (d.getMonth() + 1) + \'-\' + d.getDate();
$(td).attr(\'id\', __method.calendarId + \'_\' + ymd);
$(td).css(\'cursor\',\'pointer\');
(function(ymd) {
$(td).bind("click", ymd, function() {
__method.selectDate(ymd);
return false;
});
})(ymd);
}
$(tr).append(td);
// 如果是周六
if(6 == d.getDay()) {
$(table).append(tr);
}
}
return table;
};
/**
* @description 把时间字串转成时间格式
* @param {String} str 时间字符串
*/
pickerDateRange.prototype.str2date = function(str) {
var ar = str.split(\'-\');
// 返回日期格式
return new Date(ar[0], ar[1] - 1, ar[2]);
};
/**
* @description 比较两个时间字串的大小:1 大于; 0 等于; -1 小于
* @param {String} b 待比较时间串1
* @param {String} e 待比较时间串2
*/
pickerDateRange.prototype.compareStrDate = function(b, e) {
var bDate = this.str2date(b);
var eDate = this.str2date(e);
// 1 大于; 0 等于; -1 小于
if(bDate.getTime() > eDate.getTime()) {
return 1;
} else if(bDate.getTime() == eDate.getTime()) {
return 0;
} else {
return -1;
}
};
/**
* @description 把时间格式转成对象
* @param {Date} d 时间
*/
pickerDateRange.prototype.date2ymd = function(d) {
return [d.getFullYear(), (d.getMonth() + 1), d.getDate()];
};
/**
* @description 切换焦点到当前输入框
* @param {String} 日期框体ID
*/
pickerDateRange.prototype.changeInput = function(ipt) {
// 强制修改为开始输入框
if (true == this.mOpts.isSingleDay) {
ipt = this.startDateId;
}
// 所有4个输入框
var allInputs = [this.startDateId, this.startCompareDateId, this.endDateId, this.endCompareDateId];
// 如果 ipt 是日期输入框,则为日期样式,否则为对比日期样式
var cla = \'\';
if(ipt == this.startDateId || ipt == this.endDateId) {
cla = this.mOpts.theme + \'_\' + this.mOpts.selectCss;
} else {
cla = this.mOpts.theme + \'_\' + this.mOpts.compareCss;
}
if(ipt == this.endDateId && this.mOpts.singleCompare) {
cla = this.mOpts.theme + \'_\' + this.mOpts.compareCss;
}
// 移除所有输入框的附加样式
for(var i in allInputs) {
$(\'#\' + allInputs[i]).removeClass(this.mOpts.theme + \'_\' + this.mOpts.selectCss);
$(\'#\' + allInputs[i]).removeClass(this.mOpts.theme + \'_\' + this.mOpts.compareCss);
}
// 为指定输入框添加样式
$(\'#\' + ipt).addClass(cla);
//背景图repeat
$(\'#\' + ipt).css(\'background-repeat\', \'repeat\');
// 把输入焦点移到指定输入框
this.dateInput = ipt;
};
/**
* @description 日期格式化,加前导零
*/
pickerDateRange.prototype.formatDate = function(ymd) {
return ymd.replace(/(\d{4})\-(\d{1,2})\-(\d{1,2})/g, function(ymdFormatDate, y, m, d){
if(m < 10){
m = \'0\' + m;
}
if(d < 10){
d = \'0\' + d;
}
return y + \'-\' + m + \'-\' + d;
});
};
/*! TableSorter (FORK) v2.28.13 *//** Client-side table sorting with ease!* @requires jQuery v1.2.6+** Copyright (c) 2007 Christian Bach* fork maintained by Rob Garrison** Examples and original docs at: http://tablesorter.com* Dual licensed under the MIT and GPL licenses:* http://www.opensource.org/licenses/mit-license.php* http://www.gnu.org/licenses/gpl.html** @type jQuery* @name tablesorter (FORK)* @cat Plugins/Tablesorter* @author Christian Bach - christian.bach@polyester.se* @contributor Rob Garrison - https://github.com/Mottie/tablesorter* @docs (fork) - https://mottie.github.io/tablesorter/docs/*//*jshint browser:true, jquery:true, unused:false, expr: true */;( function( $ ) {\'use strict\';var ts = $.tablesorter = {
version : \'2.28.13\',
parsers : [],widgets : [],defaults : {
// *** appearancetheme : \'default\', // adds tablesorter-{theme} to the table for stylingwidthFixed : false, // adds colgroup to fix widths of columnsshowProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered.
headerTemplate : \'{content}\',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> // class from cssIcononRenderTemplate : null, // function( index, template ){ return template; }, // template is a stringonRenderHeader : null, // function( index ){}, // nothing to return
// *** functionalitycancelSelection : true, // prevent text selection in the headertabIndex : true, // add tabindex to header for keyboard accessibilitydateFormat : \'mmddyyyy\', // other options: \'ddmmyyy\' or \'yyyymmdd\'sortMultiSortKey : \'shiftKey\', // key used to select additional columnssortResetKey : \'ctrlKey\', // key used to remove sorting on a columnusNumberFormat : true, // false for German \'1.234.567,89\' or French \'1 234 567,89\'delayInit : false, // if false, the parsed table contents will not update until the first sortserverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.resort : true, // default setting to trigger a resort after an \'update\', \'addRows\', \'updateCell\', etc has completed
// *** sort optionsheaders : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.ignoreCase : true, // ignore case while sortingsortForce : null, // column(s) first sorted; always appliedsortList : [], // Initial sort order; applied initially; updated when manually sortedsortAppend : null, // column(s) sorted last; always appliedsortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained
sortInitialOrder : \'asc\', // sort direction on first clicksortLocaleCompare: false, // replace equivalent character (accented characters)sortReset : false, // third click on the header will reset column to default - unsortedsortRestart : false, // restart sort to \'sortInitialOrder\' when clicking on previously unsorted columns
emptyTo : \'bottom\', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMinstringTo : \'max\', // sort strings in numerical column as max, min, top, bottom, zeroduplicateSpan : true, // colspan cells in the tbody will have duplicated content in the cache for each spanned columntextExtraction : \'basic\', // text extraction method/function - function( node, table, cellIndex ){}textAttribute : \'data-text\',// data-attribute that contains alternate cell text (used in default textExtraction function)textSorter : null, // choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]numberSorter : null, // choose overall numeric sorter function( a, b, direction, maxColumnValue )
// *** widget optionsinitWidgets : true, // apply widgets on tablesorter initializationwidgetClass : \'widget-{name}\', // table class name template to match to include a widgetwidgets : [], // method to add widgets, e.g. widgets: [\'zebra\']widgetOptions : {zebra : [ \'even\', \'odd\' ] // zebra widget alternating row class names},
// *** callbacksinitialized : null, // function( table ){},
// *** extra css class namestableClass : \'\',cssAsc : \'\',cssDesc : \'\',cssNone : \'\',cssHeader : \'\',cssHeaderRow : \'\',cssProcessing : \'\', // processing icon applied to header during sort/filter
cssChildRow : \'tablesorter-childRow\', // class name indiciating that a row is to be attached to its parentcssInfoBlock : \'tablesorter-infoOnly\', // don\'t sort tbody with this class name (only one class name allowed here!)cssNoSort : \'tablesorter-noSort\', // class name added to element inside header; clicking on it won\'t cause a sortcssIgnoreRow : \'tablesorter-ignoreRow\',// header row to ignore; cells within this row will not be added to c.$headers
cssIcon : \'tablesorter-icon\', // if this class does not exist, the {icon} will not be added from the headerTemplatecssIconNone : \'\', // class name added to the icon when there is no column sortcssIconAsc : \'\', // class name added to the icon when the column has an ascending sortcssIconDesc : \'\', // class name added to the icon when the column has a descending sortcssIconDisabled : \'\', // class name added to the icon when the column has a disabled sort
// *** eventspointerClick : \'click\',pointerDown : \'mousedown\',pointerUp : \'mouseup\',
// *** selectorsselectorHeaders : \'> thead th, > thead td\',selectorSort : \'th, td\', // jQuery selector of content within selectorHeaders that is clickable to trigger a sortselectorRemove : \'.remove-me\',
// *** advanceddebug : false,
// *** Internal variablesheaderList: [],empties: {},strings: {},parsers: [],
// *** parser options for validator; values must be falsy!globalize: 0,imgAttr: 0
// removed: widgetZebra: { css: [\'even\', \'odd\'] }
},
// internal css classes - these will ALWAYS be added to// the table and MUST only contain one class name - fixes #381css : {table : \'tablesorter\',cssHasChild: \'tablesorter-hasChildRow\',childRow : \'tablesorter-childRow\',colgroup : \'tablesorter-colgroup\',header : \'tablesorter-header\',headerRow : \'tablesorter-headerRow\',headerIn : \'tablesorter-header-inner\',icon : \'tablesorter-icon\',processing : \'tablesorter-processing\',sortAsc : \'tablesorter-headerAsc\',sortDesc : \'tablesorter-headerDesc\',sortNone : \'tablesorter-headerUnSorted\'},
// labels applied to sortable headers for accessibility (aria) supportlanguage : {sortAsc : \'Ascending sort applied, \',sortDesc : \'Descending sort applied, \',sortNone : \'No sort applied, \',sortDisabled : \'sorting is disabled\',nextAsc : \'activate to apply an ascending sort\',nextDesc : \'activate to apply a descending sort\',nextNone : \'activate to remove the sort\'},
regex : {templateContent : /\{content\}/g,templateIcon : /\{icon\}/g,templateName : /\{name\}/i,spaces : /\s+/g,nonWord : /\W/g,formElements : /(input|select|button|textarea)/i,
// *** sort functions ***// regex used in natural sort// chunk/tokenize numbers & letterschunk : /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,// replace chunks @ endschunks : /(^\\0|\\0$)/,hex : /^0x[0-9a-f]+$/i,
// *** formatFloat ***comma : /,/g,digitNonUS : /[\s|\.]/g,digitNegativeTest : /^\s*\([.\d]+\)/,digitNegativeReplace : /^\s*\(([.\d]+)\)/,
// *** isDigit ***digitTest : /^[\-+(]?\d+[)]?$/,digitReplace : /[,.\'"\s]/g
},
// digit sort, text locationstring : {max : 1,min : -1,emptymin : 1,emptymax : -1,zero : 0,none : 0,\'null\' : 0,top : true,bottom : false},
keyCodes : {enter : 13},
// placeholder date parser data (globalize)dates : {},
// These methods can be applied on table.config instanceinstanceMethods : {},
/*▄█████ ██████ ██████ ██ ██ █████▄▀█▄ ██▄▄ ██ ██ ██ ██▄▄██ ▀█▄ ██▀▀ ██ ██ ██ ██▀▀▀█████▀ ██████ ██ ▀████▀ ██*/
setup : function( table, c ) {// if no thead or tbody, or tablesorter is already present, quitif ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {if ( c.debug ) {if ( table.hasInitialized ) {console.warn( \'Stopping initialization. Tablesorter has already been initialized\' );} else {console.error( \'Stopping initialization! No table, thead or tbody\', table );}}return;}
var tmp = \'\',$table = $( table ),meta = $.metadata;// initialization flagtable.hasInitialized = false;// table is being processed flagtable.isProcessing = true;// make sure to store the config objecttable.config = c;// save the settings where they read$.data( table, \'tablesorter\', c );if ( c.debug ) {console[ console.group ? \'group\' : \'log\' ]( \'Initializing tablesorter v\' + ts.version );$.data( table, \'startoveralltimer\', new Date() );}
// removing this in version 3 (only supports jQuery 1.7+)c.supportsDataObject = ( function( version ) {version[ 0 ] = parseInt( version[ 0 ], 10 );return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );})( $.fn.jquery.split( \'.\' ) );// ensure case insensitivityc.emptyTo = c.emptyTo.toLowerCase();c.stringTo = c.stringTo.toLowerCase();c.last = { sortList : [], clickedIndex : -1 };// add table theme class only if there isn\'t already one thereif ( !/tablesorter\-/.test( $table.attr( \'class\' ) ) ) {tmp = ( c.theme !== \'\' ? \' tablesorter-\' + c.theme : \'\' );}
// give the table a unique id, which will be used in namespace bindingif ( !c.namespace ) {c.namespace = \'.tablesorter\' + Math.random().toString( 16 ).slice( 2 );} else {// make sure namespace starts with a period & doesn\'t have weird charactersc.namespace = \'.\' + c.namespace.replace( ts.regex.nonWord, \'\' );}
c.table = table;c.$table = $table// add namespace to table to allow bindings on extra elements to target// the parent table (e.g. parser-input-select).addClass( ts.css.table + \' \' + c.tableClass + tmp + \' \' + c.namespace.slice(1) ).attr( \'role\', \'grid\' );c.$headers = $table.find( c.selectorHeaders );
c.$table.children().children( \'tr\' ).attr( \'role\', \'row\' );c.$tbodies = $table.children( \'tbody:not(.\' + c.cssInfoBlock + \')\' ).attr({\'aria-live\' : \'polite\',\'aria-relevant\' : \'all\'});if ( c.$table.children( \'caption\' ).length ) {tmp = c.$table.children( \'caption\' )[ 0 ];if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + \'caption\'; }c.$table.attr( \'aria-labelledby\', tmp.id );}c.widgetInit = {}; // keep a list of initialized widgets// change textExtraction via data-attributec.textExtraction = c.$table.attr( \'data-text-extraction\' ) || c.textExtraction || \'basic\';// build headersts.buildHeaders( c );// fixate columns if the users supplies the fixedWidth option// do this after theme has been appliedts.fixColumnWidth( table );// add widgets from class namets.addWidgetFromClass( table );// add widget options before parsing (e.g. grouping widget has parser settings)ts.applyWidgetOptions( table );// try to auto detect column type, and store in tables configts.setupParsers( c );// start total row count at zeroc.totalRows = 0;ts.validateOptions( c );// build the cache for the tbody cells// delayInit will delay building the cache until the user starts a sortif ( !c.delayInit ) { ts.buildCache( c ); }// bind all header events and methodsts.bindEvents( table, c.$headers, true );ts.bindMethods( c );// get sort list from jQuery data or metadata// in jQuery < 1.4, an error occurs when calling $table.data()if ( c.supportsDataObject && typeof $table.data().sortlist !== \'undefined\' ) {c.sortList = $table.data().sortlist;} else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {c.sortList = $table.metadata().sortlist;}// apply widget init codets.applyWidget( table, true );// if user has supplied a sort list to constructorif ( c.sortList.length > 0 ) {ts.sortOn( c, c.sortList, {}, !c.initWidgets );} else {ts.setHeadersCss( c );if ( c.initWidgets ) {// apply widget formatts.applyWidget( table, false );}}
// show processesing iconif ( c.showProcessing ) {$table.unbind( \'sortBegin\' + c.namespace + \' sortEnd\' + c.namespace ).bind( \'sortBegin\' + c.namespace + \' sortEnd\' + c.namespace, function( e ) {clearTimeout( c.timerProcessing );ts.isProcessing( table );if ( e.type === \'sortBegin\' ) {c.timerProcessing = setTimeout( function() {ts.isProcessing( table, true );}, 500 );}});}
// initializedtable.hasInitialized = true;table.isProcessing = false;if ( c.debug ) {console.log( \'Overall initialization time:\' + ts.benchmark( $.data( table, \'startoveralltimer\' ) ) );if ( c.debug && console.groupEnd ) { console.groupEnd(); }}$table.triggerHandler( \'tablesorter-initialized\', table );if ( typeof c.initialized === \'function\' ) {c.initialized( table );}},
bindMethods : function( c ) {var $table = c.$table,namespace = c.namespace,events = ( \'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete \' +\'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup \' +\'mouseleave \' ).split( \' \' ).join( namespace + \' \' );// apply easy methods that trigger bound events$table.unbind( events.replace( ts.regex.spaces, \' \' ) ).bind( \'sortReset\' + namespace, function( e, callback ) {e.stopPropagation();// using this.config to ensure functions are getting a non-cached version of the configts.sortReset( this.config, function( table ) {if (table.isApplyingWidgets) {// multiple triggers in a row... filterReset, then sortReset - see #1361// wait to update widgetssetTimeout( function() {ts.applyWidget( table, \'\', callback );}, 100 );} else {ts.applyWidget( table, \'\', callback );}});}).bind( \'updateAll\' + namespace, function( e, resort, callback ) {e.stopPropagation();ts.updateAll( this.config, resort, callback );}).bind( \'update\' + namespace + \' updateRows\' + namespace, function( e, resort, callback ) {e.stopPropagation();ts.update( this.config, resort, callback );}).bind( \'updateHeaders\' + namespace, function( e, callback ) {e.stopPropagation();ts.updateHeaders( this.config, callback );}).bind( \'updateCell\' + namespace, function( e, cell, resort, callback ) {e.stopPropagation();ts.updateCell( this.config, cell, resort, callback );}).bind( \'addRows\' + namespace, function( e, $row, resort, callback ) {e.stopPropagation();ts.addRows( this.config, $row, resort, callback );}).bind( \'updateComplete\' + namespace, function() {this.isUpdating = false;}).bind( \'sorton\' + namespace, function( e, list, callback, init ) {e.stopPropagation();ts.sortOn( this.config, list, callback, init );}).bind( \'appendCache\' + namespace, function( e, callback, init ) {e.stopPropagation();ts.appendCache( this.config, init );if ( $.isFunction( callback ) ) {callback( this );}})// $tbodies variable is used by the tbody sorting widget.bind( \'updateCache\' + namespace, function( e, callback, $tbodies ) {e.stopPropagation();ts.updateCache( this.config, callback, $tbodies );}).bind( \'applyWidgetId\' + namespace, function( e, id ) {e.stopPropagation();ts.applyWidgetId( this, id );}).bind( \'applyWidgets\' + namespace, function( e, init ) {e.stopPropagation();// apply widgetsts.applyWidget( this, init );}).bind( \'refreshWidgets\' + namespace, function( e, all, dontapply ) {e.stopPropagation();ts.refreshWidgets( this, all, dontapply );}).bind( \'removeWidget\' + namespace, function( e, name, refreshing ) {e.stopPropagation();ts.removeWidget( this, name, refreshing );}).bind( \'destroy\' + namespace, function( e, removeClasses, callback ) {e.stopPropagation();ts.destroy( this, removeClasses, callback );}).bind( \'resetToLoadState\' + namespace, function( e ) {e.stopPropagation();// remove all widgetsts.removeWidget( this, true, false );var tmp = $.extend( true, {}, c.originalSettings );// restore original settings; this clears out current settings, but does not clear// values saved to storage.c = $.extend( true, {}, ts.defaults, tmp );c.originalSettings = tmp;this.hasInitialized = false;// setup the entire table againts.setup( this, c );});},
bindEvents : function( table, $headers, core ) {table = $( table )[ 0 ];var tmp,c = table.config,namespace = c.namespace,downTarget = null;if ( core !== true ) {$headers.addClass( namespace.slice( 1 ) + \'_extra_headers\' );tmp = $.fn.closest ? $headers.closest( \'table\' )[ 0 ] : $headers.parents( \'table\' )[ 0 ];if ( tmp && tmp.nodeName === \'TABLE\' && tmp !== table ) {$( tmp ).addClass( namespace.slice( 1 ) + \'_extra_table\' );}}tmp = ( c.pointerDown + \' \' + c.pointerUp + \' \' + c.pointerClick + \' sort keyup \' ).replace( ts.regex.spaces, \' \' ).split( \' \' ).join( namespace + \' \' );// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)$headers// http://stackoverflow.com/questions/5312849/jquery-find-self;.find( c.selectorSort ).add( $headers.filter( c.selectorSort ) ).unbind( tmp ).bind( tmp, function( e, external ) {var $cell, cell, temp,$target = $( e.target ),// wrap event type in spaces, so the match doesn\'t trigger on inner wordstype = \' \' + e.type + \' \';// only recognize left clicksif ( ( ( e.which || e.button ) !== 1 && !type.match( \' \' + c.pointerClick + \' | sort | keyup \' ) ) ||// allow pressing enter( type === \' keyup \' && e.which !== ts.keyCodes.enter ) ||// allow triggering a click event (e.which is undefined) & ignore physical clicks( type.match( \' \' + c.pointerClick + \' \' ) && typeof e.which !== \'undefined\' ) ) {return;}// ignore mouseup if mousedown wasn\'t on the same targetif ( type.match( \' \' + c.pointerUp + \' \' ) && downTarget !== e.target && external !== true ) {return;}// set target on mousedownif ( type.match( \' \' + c.pointerDown + \' \' ) ) {downTarget = e.target;// preventDefault needed or jQuery v1.3.2 and older throws an// "Uncaught TypeError: handler.apply is not a function" errortemp = $target.jquery.split( \'.\' );if ( temp[ 0 ] === \'1\' && temp[ 1 ] < 4 ) { e.preventDefault(); }return;}downTarget = null;// prevent sort being triggered on form elementsif ( ts.regex.formElements.test( e.target.nodeName ) ||// nosort class name, or elements within a nosort container$target.hasClass( c.cssNoSort ) || $target.parents( \'.\' + c.cssNoSort ).length > 0 ||// elements within a button$target.parents( \'button\' ).length > 0 ) {return !c.cancelSelection;}if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {ts.buildCache( c );}// jQuery v1.2.6 doesn\'t have closest()$cell = $.fn.closest ? $( this ).closest( \'th, td\' ) :/TH|TD/.test( this.nodeName ) ? $( this ) : $( this ).parents( \'th, td\' );// reference original table headers and find the same cell// don\'t use $headers or IE8 throws an error - see #987temp = $headers.index( $cell );c.last.clickedIndex = ( temp < 0 ) ? $cell.attr( \'data-column\' ) : temp;// use column index if $headers is undefinedcell = c.$headers[ c.last.clickedIndex ];if ( cell && !cell.sortDisabled ) {ts.initSort( c, cell, e );}});if ( c.cancelSelection ) {// cancel selection$headers.attr( \'unselectable\', \'on\' ).bind( \'selectstart\', false ).css({\'user-select\' : \'none\',\'MozUserSelect\' : \'none\' // not needed for jQuery 1.8+});}},
buildHeaders : function( c ) {var $temp, icon, timer, indx;c.headerList = [];c.headerContent = [];c.sortVars = [];if ( c.debug ) {timer = new Date();}// children tr in tfoot - see issue #196 & #547// don\'t pass table.config to computeColumnIndex here - widgets (math) pass it to "quickly" index tbody cellsc.columns = ts.computeColumnIndex( c.$table.children( \'thead, tfoot\' ).children( \'tr\' ) );// add icon if cssIcon option existsicon = c.cssIcon ?\'<i class="\' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + \' \' + ts.css.icon ) + \'"></i>\' :\'\';// redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) {var configHeaders, header, column, template, tmp,$elem = $( elem );// ignore cell (don\'t add it to c.$headers) if row has ignoreRow classif ( $elem.parent().hasClass( c.cssIgnoreRow ) ) { return; }// make sure to get header cell & not column indexed cellconfigHeaders = ts.getColumnData( c.table, c.headers, index, true );// save original header contentc.headerContent[ index ] = $elem.html();// if headerTemplate is empty, don\'t reformat the header cellif ( c.headerTemplate !== \'\' && !$elem.find( \'.\' + ts.css.headerIn ).length ) {// set up header templatetemplate = c.headerTemplate.replace( ts.regex.templateContent, $elem.html() ).replace( ts.regex.templateIcon, $elem.find( \'.\' + ts.css.icon ).length ? \'\' : icon );if ( c.onRenderTemplate ) {header = c.onRenderTemplate.apply( $elem, [ index, template ] );// only change t if something is returnedif ( header && typeof header === \'string\' ) {template = header;}}$elem.html( \'<div class="\' + ts.css.headerIn + \'">\' + template + \'</div>\' ); // faster than wrapInner}if ( c.onRenderHeader ) {c.onRenderHeader.apply( $elem, [ index, c, c.$table ] );}column = parseInt( $elem.attr( \'data-column\' ), 10 );elem.column = column;tmp = ts.getOrder( ts.getData( $elem, configHeaders, \'sortInitialOrder\' ) || c.sortInitialOrder );// this may get updated numerous times if there are multiple rowsc.sortVars[ column ] = {count : -1, // set to -1 because clicking on the header automatically adds oneorder: tmp ?( c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ] ) : // desc, asc, unsorted( c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ] ), // asc, desc, unsortedlockedOrder : false};tmp = ts.getData( $elem, configHeaders, \'lockedOrder\' ) || false;if ( typeof tmp !== \'undefined\' && tmp !== false ) {c.sortVars[ column ].lockedOrder = true;c.sortVars[ column ].order = ts.getOrder( tmp ) ? [ 1, 1 ] : [ 0, 0 ];}// add cell to headerListc.headerList[ index ] = elem;// add to parent in case there are multiple rows$elem.addClass( ts.css.header + \' \' + c.cssHeader ).parent().addClass( ts.css.headerRow + \' \' + c.cssHeaderRow ).attr( \'role\', \'row\' );// allow keyboard cursor to focus on elementif ( c.tabIndex ) {$elem.attr( \'tabindex\', 0 );}return elem;}) );// cache headers per columnc.$headerIndexed = [];for ( indx = 0; indx < c.columns; indx++ ) {// colspan in header making a column undefinedif ( ts.isEmptyObject( c.sortVars[ indx ] ) ) {c.sortVars[ indx ] = {};}$temp = c.$headers.filter( \'[data-column="\' + indx + \'"]\' );// target sortable column cells, unless there are none, then use non-sortable cells// .last() added in jQuery 1.4; use .filter(\':last\') to maintain compatibility with jQuery v1.2.6c.$headerIndexed[ indx ] = $temp.length ?$temp.not( \'.sorter-false\' ).length ?$temp.not( \'.sorter-false\' ).filter( \':last\' ) :$temp.filter( \':last\' ) :$();}c.$table.find( c.selectorHeaders ).attr({scope: \'col\',role : \'columnheader\'});// enable/disable sortingts.updateHeader( c );if ( c.debug ) {console.log( \'Built headers:\' + ts.benchmark( timer ) );console.log( c.$headers );}},
// Use it to add a set of methods to table.config which will be available for all tables.// This should be done before table initializationaddInstanceMethods : function( methods ) {$.extend( ts.instanceMethods, methods );},
/*█████▄ ▄████▄ █████▄ ▄█████ ██████ █████▄ ▄███████▄▄██ ██▄▄██ ██▄▄██ ▀█▄ ██▄▄ ██▄▄██ ▀█▄██▀▀▀ ██▀▀██ ██▀██ ▀█▄ ██▀▀ ██▀██ ▀█▄██ ██ ██ ██ ██ █████▀ ██████ ██ ██ █████▀*/setupParsers : function( c, $tbodies ) {var rows, list, span, max, colIndex, indx, header, configHeaders,noParser, parser, extractor, time, tbody, len,table = c.table,tbodyIndex = 0,debug = {};// update table bodies in case we start with an empty tablec.$tbodies = c.$table.children( \'tbody:not(.\' + c.cssInfoBlock + \')\' );tbody = typeof $tbodies === \'undefined\' ? c.$tbodies : $tbodies;len = tbody.length;if ( len === 0 ) {return c.debug ? console.warn( \'Warning: *Empty table!* Not building a parser cache\' ) : \'\';} else if ( c.debug ) {time = new Date();console[ console.group ? \'group\' : \'log\' ]( \'Detecting parsers for each column\' );}list = {extractors: [],parsers: []};while ( tbodyIndex < len ) {rows = tbody[ tbodyIndex ].rows;if ( rows.length ) {colIndex = 0;max = c.columns;for ( indx = 0; indx < max; indx++ ) {header = c.$headerIndexed[ colIndex ];if ( header && header.length ) {// get column indexed table cell; adding true parameter fixes #1362 but// it would break backwards compatibility...configHeaders = ts.getColumnData( table, c.headers, colIndex ); // , true );// get column parser/extractorextractor = ts.getParserById( ts.getData( header, configHeaders, \'extractor\' ) );parser = ts.getParserById( ts.getData( header, configHeaders, \'sorter\' ) );noParser = ts.getData( header, configHeaders, \'parser\' ) === \'false\';// empty cells behaviour - keeping emptyToBottom for backwards compatibilityc.empties[colIndex] = (ts.getData( header, configHeaders, \'empty\' ) ||c.emptyTo || ( c.emptyToBottom ? \'bottom\' : \'top\' ) ).toLowerCase();// text strings behaviour in numerical sortsc.strings[colIndex] = (ts.getData( header, configHeaders, \'string\' ) ||c.stringTo ||\'max\' ).toLowerCase();if ( noParser ) {parser = ts.getParserById( \'no-parser\' );}if ( !extractor ) {// For now, maybe detect somedayextractor = false;}if ( !parser ) {parser = ts.detectParserForColumn( c, rows, -1, colIndex );}if ( c.debug ) {debug[ \'(\' + colIndex + \') \' + header.text() ] = {parser : parser.id,extractor : extractor ? extractor.id : \'none\',string : c.strings[ colIndex ],empty : c.empties[ colIndex ]};}list.parsers[ colIndex ] = parser;list.extractors[ colIndex ] = extractor;span = header[ 0 ].colSpan - 1;if ( span > 0 ) {colIndex += span;max += span;while ( span + 1 > 0 ) {// set colspan columns to use the same parsers & extractorslist.parsers[ colIndex - span ] = parser;list.extractors[ colIndex - span ] = extractor;span--;}}}colIndex++;}}tbodyIndex += ( list.parsers.length ) ? len : 1;}if ( c.debug ) {if ( !ts.isEmptyObject( debug ) ) {console[ console.table ? \'table\' : \'log\' ]( debug );} else {console.warn( \' No parsers detected!\' );}console.log( \'Completed detecting parsers\' + ts.benchmark( time ) );if ( console.groupEnd ) { console.groupEnd(); }}c.parsers = list.parsers;c.extractors = list.extractors;},
addParser : function( parser ) {var indx,len = ts.parsers.length,add = true;for ( indx = 0; indx < len; indx++ ) {if ( ts.parsers[ indx ].id.toLowerCase() === parser.id.toLowerCase() ) {add = false;}}if ( add ) {ts.parsers[ ts.parsers.length ] = parser;}},
getParserById : function( name ) {/*jshint eqeqeq:false */if ( name == \'false\' ) { return false; }var indx,len = ts.parsers.length;for ( indx = 0; indx < len; indx++ ) {if ( ts.parsers[ indx ].id.toLowerCase() === ( name.toString() ).toLowerCase() ) {return ts.parsers[ indx ];}}return false;},
detectParserForColumn : function( c, rows, rowIndex, cellIndex ) {var cur, $node, row,indx = ts.parsers.length,node = false,nodeValue = \'\',keepLooking = true;while ( nodeValue === \'\' && keepLooking ) {rowIndex++;row = rows[ rowIndex ];// stop looking after 50 empty rowsif ( row && rowIndex < 50 ) {if ( row.className.indexOf( ts.cssIgnoreRow ) < 0 ) {node = rows[ rowIndex ].cells[ cellIndex ];nodeValue = ts.getElementText( c, node, cellIndex );$node = $( node );if ( c.debug ) {console.log( \'Checking if value was empty on row \' + rowIndex + \', column: \' +cellIndex + \': "\' + nodeValue + \'"\' );}}} else {keepLooking = false;}}while ( --indx >= 0 ) {cur = ts.parsers[ indx ];// ignore the default text parser because it will always be trueif ( cur && cur.id !== \'text\' && cur.is && cur.is( nodeValue, c.table, node, $node ) ) {return cur;}}// nothing found, return the generic parser (text)return ts.getParserById( \'text\' );},
getElementText : function( c, node, cellIndex ) {if ( !node ) { return \'\'; }var tmp,extract = c.textExtraction || \'\',// node could be a jquery object// http://jsperf.com/jquery-vs-instanceof-jquery/2$node = node.jquery ? node : $( node );if ( typeof extract === \'string\' ) {// check data-attribute first when set to \'basic\'; don\'t use node.innerText - it\'s really slow!// http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/if ( extract === \'basic\' && typeof ( tmp = $node.attr( c.textAttribute ) ) !== \'undefined\' ) {return $.trim( tmp );}return $.trim( node.textContent || $node.text() );} else {if ( typeof extract === \'function\' ) {return $.trim( extract( $node[ 0 ], c.table, cellIndex ) );} else if ( typeof ( tmp = ts.getColumnData( c.table, extract, cellIndex ) ) === \'function\' ) {return $.trim( tmp( $node[ 0 ], c.table, cellIndex ) );}}// fallbackreturn $.trim( $node[ 0 ].textContent || $node.text() );},
// centralized function to extract/parse cell contentsgetParsedText : function( c, cell, colIndex, txt ) {if ( typeof txt === \'undefined\' ) {txt = ts.getElementText( c, cell, colIndex );}// if no parser, make sure to return the txtvar val = \'\' + txt,parser = c.parsers[ colIndex ],extractor = c.extractors[ colIndex ];if ( parser ) {// do extract before parsing, if there is oneif ( extractor && typeof extractor.format === \'function\' ) {txt = extractor.format( txt, c.table, cell, colIndex );}// allow parsing if the string is empty, previously parsing would change it to zero,// in case the parser needs to extract data from the table cell attributesval = parser.id === \'no-parser\' ? \'\' :// make sure txt is a string (extractor may have converted it)parser.format( \'\' + txt, c.table, cell, colIndex );if ( c.ignoreCase && typeof val === \'string\' ) {val = val.toLowerCase();}}return val;},
/*▄████▄ ▄████▄ ▄████▄ ██ ██ ████████ ▀▀ ██▄▄██ ██ ▀▀ ██▄▄██ ██▄▄██ ▄▄ ██▀▀██ ██ ▄▄ ██▀▀██ ██▀▀▀████▀ ██ ██ ▀████▀ ██ ██ ██████*/buildCache : function( c, callback, $tbodies ) {var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,colMax, span, cacheIndex, hasParser, max, len, index,table = c.table,parsers = c.parsers;// update tbody variablec.$tbodies = c.$table.children( \'tbody:not(.\' + c.cssInfoBlock + \')\' );$tbody = typeof $tbodies === \'undefined\' ? c.$tbodies : $tbodies,c.cache = {};c.totalRows = 0;// if no parsers found, return - it\'s an empty table.if ( !parsers ) {return c.debug ? console.warn( \'Warning: *Empty table!* Not building a cache\' ) : \'\';}if ( c.debug ) {cacheTime = new Date();}// processing iconif ( c.showProcessing ) {ts.isProcessing( table, true );}for ( tbodyIndex = 0; tbodyIndex < $tbody.length; tbodyIndex++ ) {colMax = []; // column max value per tbodycache = c.cache[ tbodyIndex ] = {normalized: [] // array of normalized row data; last entry contains \'rowData\' above// colMax: # // added at the end};
totalRows = ( $tbody[ tbodyIndex ] && $tbody[ tbodyIndex ].rows.length ) || 0;for ( rowIndex = 0; rowIndex < totalRows; ++rowIndex ) {rowData = {// order: original row order #// $row : jQuery Object[]child: [], // child row text (filter widget)raw: [] // original row text};/** Add the table data to main data array */$row = $( $tbody[ tbodyIndex ].rows[ rowIndex ] );cols = [];// ignore "remove-me" rowsif ( $row.hasClass( c.selectorRemove.slice(1) ) ) {continue;}// if this is a child row, add it to the last row\'s children and continue to the next row// ignore child row class, if it is the first rowif ( $row.hasClass( c.cssChildRow ) && rowIndex !== 0 ) {len = cache.normalized.length - 1;prevRowData = cache.normalized[ len ][ c.columns ];prevRowData.$row = prevRowData.$row.add( $row );// add \'hasChild\' class name to parent rowif ( !$row.prev().hasClass( c.cssChildRow ) ) {$row.prev().addClass( ts.css.cssHasChild );}// save child row content (un-parsed!)$cells = $row.children( \'th, td\' );len = prevRowData.child.length;prevRowData.child[ len ] = [];// child row content does not account for colspans/rowspans; so indexing may be offcacheIndex = 0;max = c.columns;for ( colIndex = 0; colIndex < max; colIndex++ ) {cell = $cells[ colIndex ];if ( cell ) {prevRowData.child[ len ][ colIndex ] = ts.getParsedText( c, cell, colIndex );span = $cells[ colIndex ].colSpan - 1;if ( span > 0 ) {cacheIndex += span;max += span;}}cacheIndex++;}// go to the next for loopcontinue;}rowData.$row = $row;rowData.order = rowIndex; // add original row position to rowCachecacheIndex = 0;max = c.columns;for ( colIndex = 0; colIndex < max; ++colIndex ) {cell = $row[ 0 ].cells[ colIndex ];if ( cell && cacheIndex < c.columns ) {hasParser = typeof parsers[ cacheIndex ] !== \'undefined\';if ( !hasParser && c.debug ) {console.warn( \'No parser found for row: \' + rowIndex + \', column: \' + colIndex +\'; cell containing: "\' + $(cell).text() + \'"; does it have a header?\' );}val = ts.getElementText( c, cell, cacheIndex );rowData.raw[ cacheIndex ] = val; // save original row text// save raw column text even if there is no parser settxt = ts.getParsedText( c, cell, cacheIndex, val );cols[ cacheIndex ] = txt;if ( hasParser && ( parsers[ cacheIndex ].type || \'\' ).toLowerCase() === \'numeric\' ) {// determine column max value (ignore sign)colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );}// allow colSpan in tbodyspan = cell.colSpan - 1;if ( span > 0 ) {index = 0;while ( index <= span ) {// duplicate text (or not) to spanned columns// instead of setting duplicate span to empty string, use textExtraction to try to get a value// see http://stackoverflow.com/q/36449711/145346txt = c.duplicateSpan || index === 0 ?val :typeof c.textExtraction !== \'string\' ?ts.getElementText( c, cell, cacheIndex + index ) || \'\' :\'\';rowData.raw[ cacheIndex + index ] = txt;cols[ cacheIndex + index ] = txt;index++;}cacheIndex += span;max += span;}}cacheIndex++;}// ensure rowData is always in the same location (after the last column)cols[ c.columns ] = rowData;cache.normalized[ cache.normalized.length ] = cols;}cache.colMax = colMax;// total up rows, not including child rowsc.totalRows += cache.normalized.length;
}if ( c.showProcessing ) {ts.isProcessing( table ); // remove processing icon}if ( c.debug ) {len = Math.min( 5, c.cache[ 0 ].normalized.length );console[ console.group ? \'group\' : \'log\' ]( \'Building cache for \' + c.totalRows +\' rows (showing \' + len + \' rows in log) and \' + c.columns + \' columns\' +ts.benchmark( cacheTime ) );val = {};for ( colIndex = 0; colIndex < c.columns; colIndex++ ) {for ( cacheIndex = 0; cacheIndex < len; cacheIndex++ ) {if ( !val[ \'row: \' + cacheIndex ] ) {val[ \'row: \' + cacheIndex ] = {};}val[ \'row: \' + cacheIndex ][ c.$headerIndexed[ colIndex ].text() ] =c.cache[ 0 ].normalized[ cacheIndex ][ colIndex ];}}console[ console.table ? \'table\' : \'log\' ]( val );if ( console.groupEnd ) { console.groupEnd(); }}if ( $.isFunction( callback ) ) {callback( table );}},
getColumnText : function( table, column, callback, rowFilter ) {table = $( table )[0];var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result,hasCallback = typeof callback === \'function\',allColumns = column === \'all\',data = { raw : [], parsed: [], $cell: [] },c = table.config;if ( ts.isEmptyObject( c ) ) {if ( c.debug ) {console.warn( \'No cache found - aborting getColumnText function!\' );}} else {tbodyLen = c.$tbodies.length;for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) {cache = c.cache[ tbodyIndex ].normalized;rowLen = cache.length;for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) {row = cache[ rowIndex ];if ( rowFilter && !row[ c.columns ].$row.is( rowFilter ) ) {continue;}result = true;parsed = ( allColumns ) ? row.slice( 0, c.columns ) : row[ column ];row = row[ c.columns ];raw = ( allColumns ) ? row.raw : row.raw[ column ];$cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );if ( hasCallback ) {result = callback({tbodyIndex : tbodyIndex,rowIndex : rowIndex,parsed : parsed,raw : raw,$row : row.$row,$cell : $cell});}if ( result !== false ) {data.parsed[ data.parsed.length ] = parsed;data.raw[ data.raw.length ] = raw;data.$cell[ data.$cell.length ] = $cell;}}}// return everythingreturn data;}},
/*██ ██ █████▄ █████▄ ▄████▄ ██████ ████████ ██ ██▄▄██ ██ ██ ██▄▄██ ██ ██▄▄██ ██ ██▀▀▀ ██ ██ ██▀▀██ ██ ██▀▀▀████▀ ██ █████▀ ██ ██ ██ ██████*/setHeadersCss : function( c ) {var indx, column,list = c.sortList,len = list.length,none = ts.css.sortNone + \' \' + c.cssNone,css = [ ts.css.sortAsc + \' \' + c.cssAsc, ts.css.sortDesc + \' \' + c.cssDesc ],cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],aria = [ \'ascending\', \'descending\' ],// find the footer$extras = c.$table.find( \'tfoot tr\' ).children( \'td, th\' ).add( $( c.namespace + \'_extra_headers\' ) ).removeClass( css.join( \' \' ) ),// remove all header information$sorted = c.$headers.add( $( \'thead \' + c.namespace + \'_extra_headers\' ) ).removeClass( css.join( \' \' ) ).addClass( none ).attr( \'aria-sort\', \'none\' ).find( \'.\' + ts.css.icon ).removeClass( cssIcon.join( \' \' ) ).end();// add css none to all sortable headers$sorted.not( \'.sorter-false\' ).find( \'.\' + ts.css.icon ).addClass( cssIcon[ 2 ] );// add disabled css icon classif ( c.cssIconDisabled ) {$sorted.filter( \'.sorter-false\' ).find( \'.\' + ts.css.icon ).addClass( c.cssIconDisabled );}for ( indx = 0; indx < len; indx++ ) {// direction = 2 means reset!if ( list[ indx ][ 1 ] !== 2 ) {// multicolumn sorting updating - see #1005// .not(function(){}) needs jQuery 1.4// filter(function(i, el){}) <- el is undefined in jQuery v1.2.6$sorted = c.$headers.filter( function( i ) {// only include headers that are in the sortList (this includes colspans)var include = true,$el = c.$headers.eq( i ),col = parseInt( $el.attr( \'data-column\' ), 10 ),end = col + c.$headers[ i ].colSpan;for ( ; col < end; col++ ) {include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false;}return include;});
// choose the :last in case there are nested columns$sorted = $sorted.not( \'.sorter-false\' ).filter( \'[data-column="\' + list[ indx ][ 0 ] + \'"]\' + ( len === 1 ? \':last\' : \'\' ) );if ( $sorted.length ) {for ( column = 0; column < $sorted.length; column++ ) {if ( !$sorted[ column ].sortDisabled ) {$sorted.eq( column ).removeClass( none ).addClass( css[ list[ indx ][ 1 ] ] ).attr( \'aria-sort\', aria[ list[ indx ][ 1 ] ] ).find( \'.\' + ts.css.icon ).removeClass( cssIcon[ 2 ] ).addClass( cssIcon[ list[ indx ][ 1 ] ] );}}// add sorted class to footer & extra headers, if they existif ( $extras.length ) {$extras.filter( \'[data-column="\' + list[ indx ][ 0 ] + \'"]\' ).removeClass( none ).addClass( css[ list[ indx ][ 1 ] ] );}}}}// add verbose aria labelslen = c.$headers.length;for ( indx = 0; indx < len; indx++ ) {ts.setColumnAriaLabel( c, c.$headers.eq( indx ) );}},
// nextSort (optional), lets you disable next sort textsetColumnAriaLabel : function( c, $header, nextSort ) {if ( $header.length ) {var column = parseInt( $header.attr( \'data-column\' ), 10 ),vars = c.sortVars[ column ],tmp = $header.hasClass( ts.css.sortAsc ) ?\'sortAsc\' :$header.hasClass( ts.css.sortDesc ) ? \'sortDesc\' : \'sortNone\',txt = $.trim( $header.text() ) + \': \' + ts.language[ tmp ];if ( $header.hasClass( \'sorter-false\' ) || nextSort === false ) {txt += ts.language.sortDisabled;} else {tmp = ( vars.count + 1 ) % vars.order.length;nextSort = vars.order[ tmp ];// if nextSorttxt += ts.language[ nextSort === 0 ? \'nextAsc\' : nextSort === 1 ? \'nextDesc\' : \'nextNone\' ];}$header.attr( \'aria-label\', txt );}},
updateHeader : function( c ) {var index, isDisabled, $header, col,table = c.table,len = c.$headers.length;for ( index = 0; index < len; index++ ) {$header = c.$headers.eq( index );col = ts.getColumnData( table, c.headers, index, true );// add \'sorter-false\' class if \'parser-false\' is setisDisabled = ts.getData( $header, col, \'sorter\' ) === \'false\' || ts.getData( $header, col, \'parser\' ) === \'false\';ts.setColumnSort( c, $header, isDisabled );}},
setColumnSort : function( c, $header, isDisabled ) {var id = c.table.id;$header[ 0 ].sortDisabled = isDisabled;$header[ isDisabled ? \'addClass\' : \'removeClass\' ]( \'sorter-false\' ).attr( \'aria-disabled\', \'\' + isDisabled );// disable tab index on disabled cellsif ( c.tabIndex ) {if ( isDisabled ) {$header.removeAttr( \'tabindex\' );} else {$header.attr( \'tabindex\', \'0\' );}}// aria-controls - requires table IDif ( id ) {if ( isDisabled ) {$header.removeAttr( \'aria-controls\' );} else {$header.attr( \'aria-controls\', id );}}},
updateHeaderSortCount : function( c, list ) {var col, dir, group, indx, primary, temp, val, order,sortList = list || c.sortList,len = sortList.length;c.sortList = [];for ( indx = 0; indx < len; indx++ ) {val = sortList[ indx ];// ensure all sortList values are numeric - fixes #127col = parseInt( val[ 0 ], 10 );// prevents error if sorton array is wrongif ( col < c.columns ) {
// set order if not already defined - due to colspan header without associated header cell// adding this check prevents a javascript errorif ( !c.sortVars[ col ].order ) {if ( ts.getOrder( c.sortInitialOrder ) ) {order = c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ];} else {order = c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ];}c.sortVars[ col ].order = order;c.sortVars[ col ].count = 0;}
order = c.sortVars[ col ].order;dir = ( \'\' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );dir = dir ? dir[ 0 ] : \'\';// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)extswitch ( dir ) {case \'1\' : case \'d\' : // descendingdir = 1;break;case \'s\' : // same direction (as primary column)// if primary sort is set to \'s\', make it ascendingdir = primary || 0;break;case \'o\' :temp = order[ ( primary || 0 ) % order.length ];// opposite of primary column; but resets if primary resetsdir = temp === 0 ? 1 : temp === 1 ? 0 : 2;break;case \'n\' :dir = order[ ( ++c.sortVars[ col ].count ) % order.length ];break;default : // ascendingdir = 0;break;}primary = indx === 0 ? dir : primary;group = [ col, parseInt( dir, 10 ) || 0 ];c.sortList[ c.sortList.length ] = group;dir = $.inArray( group[ 1 ], order ); // fixes issue #167c.sortVars[ col ].count = dir >= 0 ? dir : group[ 1 ] % order.length;}}},
updateAll : function( c, resort, callback ) {var table = c.table;table.isUpdating = true;ts.refreshWidgets( table, true, true );ts.buildHeaders( c );ts.bindEvents( table, c.$headers, true );ts.bindMethods( c );ts.commonUpdate( c, resort, callback );},
update : function( c, resort, callback ) {var table = c.table;table.isUpdating = true;// update sorting (if enabled/disabled)ts.updateHeader( c );ts.commonUpdate( c, resort, callback );},
// simple header update - see #989updateHeaders : function( c, callback ) {c.table.isUpdating = true;ts.buildHeaders( c );ts.bindEvents( c.table, c.$headers, true );ts.resortComplete( c, callback );},
updateCell : function( c, cell, resort, callback ) {// updateCell for child rows is a mess - we\'ll ignore them for now// eventually I\'ll break out the "update" row cache code to make everything consistentif ( $( cell ).closest( \'tr\' ).hasClass( c.cssChildRow ) ) {console.warn(\'Tablesorter Warning! "updateCell" for child row content has been disabled, use "update" instead\');return;}if ( ts.isEmptyObject( c.cache ) ) {// empty table, do an update instead - fixes #1099ts.updateHeader( c );ts.commonUpdate( c, resort, callback );return;}c.table.isUpdating = true;c.$table.find( c.selectorRemove ).remove();// get position from the domvar tmp, indx, row, icell, cache, len,$tbodies = c.$tbodies,$cell = $( cell ),// update cache - format: function( s, table, cell, cellIndex )// no closest in jQuery v1.2.6tbodyIndex = $tbodies.index( $.fn.closest ? $cell.closest( \'tbody\' ) : $cell.parents( \'tbody\' ).filter( \':first\' ) ),tbcache = c.cache[ tbodyIndex ],$row = $.fn.closest ? $cell.closest( \'tr\' ) : $cell.parents( \'tr\' ).filter( \':first\' );cell = $cell[ 0 ]; // in case cell is a jQuery object// tbody may not exist if update is initialized while tbody is removed for processingif ( $tbodies.length && tbodyIndex >= 0 ) {row = $tbodies.eq( tbodyIndex ).find( \'tr\' ).not( \'.\' + c.cssChildRow ).index( $row );cache = tbcache.normalized[ row ];len = $row[ 0 ].cells.length;if ( len !== c.columns ) {// colspan in here somewhere!icell = 0;tmp = false;for ( indx = 0; indx < len; indx++ ) {if ( !tmp && $row[ 0 ].cells[ indx ] !== cell ) {icell += $row[ 0 ].cells[ indx ].colSpan;} else {tmp = true;}}} else {icell = $cell.index();}tmp = ts.getElementText( c, cell, icell ); // rawcache[ c.columns ].raw[ icell ] = tmp;tmp = ts.getParsedText( c, cell, icell, tmp );cache[ icell ] = tmp; // parsedif ( ( c.parsers[ icell ].type || \'\' ).toLowerCase() === \'numeric\' ) {// update column max value (ignore sign)tbcache.colMax[ icell ] = Math.max( Math.abs( tmp ) || 0, tbcache.colMax[ icell ] || 0 );}tmp = resort !== \'undefined\' ? resort : c.resort;if ( tmp !== false ) {// widgets will be reappliedts.checkResort( c, tmp, callback );} else {// don\'t reapply widgets is resort is false, just in case it causes// problems with element focusts.resortComplete( c, callback );}} else {if ( c.debug ) {console.error( \'updateCell aborted, tbody missing or not within the indicated table\' );}c.table.isUpdating = false;}},
addRows : function( c, $row, resort, callback ) {var txt, val, tbodyIndex, rowIndex, rows, cellIndex, len, order,cacheIndex, rowData, cells, cell, span,// allow passing a row string if only one non-info tbody exists in the tablevalid = typeof $row === \'string\' && c.$tbodies.length === 1 && /<tr/.test( $row || \'\' ),table = c.table;if ( valid ) {$row = $( $row );c.$tbodies.append( $row );} else if ( !$row ||// row is a jQuery object?!( $row instanceof jQuery ) ||// row contained in the table?( $.fn.closest ? $row.closest( \'table\' )[ 0 ] : $row.parents( \'table\' )[ 0 ] ) !== c.table ) {if ( c.debug ) {console.error( \'addRows method requires (1) a jQuery selector reference to rows that have already \' +\'been added to the table, or (2) row HTML string to be added to a table with only one tbody\' );}return false;}table.isUpdating = true;if ( ts.isEmptyObject( c.cache ) ) {// empty table, do an update instead - fixes #450ts.updateHeader( c );ts.commonUpdate( c, resort, callback );} else {rows = $row.filter( \'tr\' ).attr( \'role\', \'row\' ).length;tbodyIndex = c.$tbodies.index( $row.parents( \'tbody\' ).filter( \':first\' ) );// fixes adding rows to an empty table - see issue #179if ( !( c.parsers && c.parsers.length ) ) {ts.setupParsers( c );}// add each rowfor ( rowIndex = 0; rowIndex < rows; rowIndex++ ) {cacheIndex = 0;len = $row[ rowIndex ].cells.length;order = c.cache[ tbodyIndex ].normalized.length;cells = [];rowData = {child : [],raw : [],$row : $row.eq( rowIndex ),order : order};// add each cellfor ( cellIndex = 0; cellIndex < len; cellIndex++ ) {cell = $row[ rowIndex ].cells[ cellIndex ];txt = ts.getElementText( c, cell, cacheIndex );rowData.raw[ cacheIndex ] = txt;val = ts.getParsedText( c, cell, cacheIndex, txt );cells[ cacheIndex ] = val;if ( ( c.parsers[ cacheIndex ].type || \'\' ).toLowerCase() === \'numeric\' ) {// update column max value (ignore sign)c.cache[ tbodyIndex ].colMax[ cacheIndex ] =Math.max( Math.abs( val ) || 0, c.cache[ tbodyIndex ].colMax[ cacheIndex ] || 0 );}span = cell.colSpan - 1;if ( span > 0 ) {cacheIndex += span;}cacheIndex++;}// add the row data to the endcells[ c.columns ] = rowData;// update cachec.cache[ tbodyIndex ].normalized[ order ] = cells;}// resort using current settingsts.checkResort( c, resort, callback );}},
updateCache : function( c, callback, $tbodies ) {// rebuild parsersif ( !( c.parsers && c.parsers.length ) ) {ts.setupParsers( c, $tbodies );}// rebuild the cache mapts.buildCache( c, callback, $tbodies );},
// init flag (true) used by pager plugin to prevent widget application// renamed from appendToTableappendCache : function( c, init ) {var parsed, totalRows, $tbody, $curTbody, rowIndex, tbodyIndex, appendTime,table = c.table,wo = c.widgetOptions,$tbodies = c.$tbodies,rows = [],cache = c.cache;// empty table - fixes #206/#346if ( ts.isEmptyObject( cache ) ) {// run pager appender in case the table was just emptiedreturn c.appender ? c.appender( table, rows ) :table.isUpdating ? c.$table.triggerHandler( \'updateComplete\', table ) : \'\'; // Fixes #532}if ( c.debug ) {appendTime = new Date();}for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {$tbody = $tbodies.eq( tbodyIndex );if ( $tbody.length ) {// detach tbody for manipulation$curTbody = ts.processTbody( table, $tbody, true );parsed = cache[ tbodyIndex ].normalized;totalRows = parsed.length;for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {rows[rows.length] = parsed[ rowIndex ][ c.columns ].$row;// removeRows used by the pager plugin; don\'t render if using ajax - fixes #411if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {$curTbody.append( parsed[ rowIndex ][ c.columns ].$row );}}// restore tbodyts.processTbody( table, $curTbody, false );}}if ( c.appender ) {c.appender( table, rows );}if ( c.debug ) {console.log( \'Rebuilt table\' + ts.benchmark( appendTime ) );}// apply table widgets; but not before ajax completesif ( !init && !c.appender ) {ts.applyWidget( table );}if ( table.isUpdating ) {c.$table.triggerHandler( \'updateComplete\', table );}},
commonUpdate : function( c, resort, callback ) {// remove rows/elements before updatec.$table.find( c.selectorRemove ).remove();// rebuild parsersts.setupParsers( c );// rebuild the cache mapts.buildCache( c );ts.checkResort( c, resort, callback );},
/*▄█████ ▄████▄ █████▄ ██████ ██ █████▄ ▄████▄▀█▄ ██ ██ ██▄▄██ ██ ██ ██ ██ ██ ▄▄▄ ▀█▄ ██ ██ ██▀██ ██ ██ ██ ██ ██ ▀███████▀ ▀████▀ ██ ██ ██ ██ ██ ██ ▀████▀*/initSort : function( c, cell, event ) {if ( c.table.isUpdating ) {// let any updates complete before initializing a sortreturn setTimeout( function(){ts.initSort( c, cell, event );}, 50 );}
var arry, indx, headerIndx, dir, temp, tmp, $header,notMultiSort = !event[ c.sortMultiSortKey ],table = c.table,len = c.$headers.length,// get current column indexcol = parseInt( $( cell ).attr( \'data-column\' ), 10 ),order = c.sortVars[ col ].order;
// Only call sortStart if sorting is enabledc.$table.triggerHandler( \'sortStart\', table );// get current column sort ordertmp = ( c.sortVars[ col ].count + 1 ) % order.length;c.sortVars[ col ].count = event[ c.sortResetKey ] ? 2 : tmp;// reset all sorts on non-current column - issue #30if ( c.sortRestart ) {for ( headerIndx = 0; headerIndx < len; headerIndx++ ) {$header = c.$headers.eq( headerIndx );tmp = parseInt( $header.attr( \'data-column\' ), 10 );// only reset counts on columns that weren\'t just clicked on and if not included in a multisortif ( col !== tmp && ( notMultiSort || $header.hasClass( ts.css.sortNone ) ) ) {c.sortVars[ tmp ].count = -1;}}}// user only wants to sort on one columnif ( notMultiSort ) {// flush the sort listc.sortList = [];c.last.sortList = [];if ( c.sortForce !== null ) {arry = c.sortForce;for ( indx = 0; indx < arry.length; indx++ ) {if ( arry[ indx ][ 0 ] !== col ) {c.sortList[ c.sortList.length ] = arry[ indx ];}}}// add column to sort listdir = order[ c.sortVars[ col ].count ];if ( dir < 2 ) {c.sortList[ c.sortList.length ] = [ col, dir ];// add other columns if header spans across multipleif ( cell.colSpan > 1 ) {for ( indx = 1; indx < cell.colSpan; indx++ ) {c.sortList[ c.sortList.length ] = [ col + indx, dir ];// update count on columns in colSpanc.sortVars[ col + indx ].count = $.inArray( dir, order );}}}// multi column sorting} else {// get rid of the sortAppend before adding more - fixes issue #115 & #523c.sortList = $.extend( [], c.last.sortList );
// the user has clicked on an already sorted columnif ( ts.isValueInArray( col, c.sortList ) >= 0 ) {// reverse the sorting directionfor ( indx = 0; indx < c.sortList.length; indx++ ) {tmp = c.sortList[ indx ];if ( tmp[ 0 ] === col ) {// order.count seems to be incorrect when compared to cell.counttmp[ 1 ] = order[ c.sortVars[ col ].count ];if ( tmp[1] === 2 ) {c.sortList.splice( indx, 1 );c.sortVars[ col ].count = -1;}}}} else {// add column to sort list arraydir = order[ c.sortVars[ col ].count ];if ( dir < 2 ) {c.sortList[ c.sortList.length ] = [ col, dir ];// add other columns if header spans across multipleif ( cell.colSpan > 1 ) {for ( indx = 1; indx < cell.colSpan; indx++ ) {c.sortList[ c.sortList.length ] = [ col + indx, dir ];// update count on columns in colSpanc.sortVars[ col + indx ].count = $.inArray( dir, order );}}}}}// save sort before applying sortAppendc.last.sortList = $.extend( [], c.sortList );if ( c.sortList.length && c.sortAppend ) {arry = $.isArray( c.sortAppend ) ? c.sortAppend : c.sortAppend[ c.sortList[ 0 ][ 0 ] ];if ( !ts.isEmptyObject( arry ) ) {for ( indx = 0; indx < arry.length; indx++ ) {if ( arry[ indx ][ 0 ] !== col && ts.isValueInArray( arry[ indx ][ 0 ], c.sortList ) < 0 ) {dir = arry[ indx ][ 1 ];temp = ( \'\' + dir ).match( /^(a|d|s|o|n)/ );if ( temp ) {tmp = c.sortList[ 0 ][ 1 ];switch ( temp[ 0 ] ) {case \'d\' :dir = 1;break;case \'s\' :dir = tmp;break;case \'o\' :dir = tmp === 0 ? 1 : 0;break;case \'n\' :dir = ( tmp + 1 ) % order.length;break;default:dir = 0;break;}}c.sortList[ c.sortList.length ] = [ arry[ indx ][ 0 ], dir ];}}}}// sortBegin event triggered immediately before the sortc.$table.triggerHandler( \'sortBegin\', table );// setTimeout needed so the processing icon shows upsetTimeout( function() {// set css for headersts.setHeadersCss( c );ts.multisort( c );ts.appendCache( c );c.$table.triggerHandler( \'sortBeforeEnd\', table );c.$table.triggerHandler( \'sortEnd\', table );}, 1 );},
// sort multiple columnsmultisort : function( c ) { /*jshint loopfunc:true */var tbodyIndex, sortTime, colMax, rows, tmp,table = c.table,sorter = [],dir = 0,textSorter = c.textSorter || \'\',sortList = c.sortList,sortLen = sortList.length,len = c.$tbodies.length;if ( c.serverSideSorting || ts.isEmptyObject( c.cache ) ) {// empty table - fixes #206/#346return;}if ( c.debug ) { sortTime = new Date(); }// cache textSorter to optimize speedif ( typeof textSorter === \'object\' ) {colMax = c.columns;while ( colMax-- ) {tmp = ts.getColumnData( table, textSorter, colMax );if ( typeof tmp === \'function\' ) {sorter[ colMax ] = tmp;}}}for ( tbodyIndex = 0; tbodyIndex < len; tbodyIndex++ ) {colMax = c.cache[ tbodyIndex ].colMax;rows = c.cache[ tbodyIndex ].normalized;
rows.sort( function( a, b ) {var sortIndex, num, col, order, sort, x, y;// rows is undefined here in IE, so don\'t use it!for ( sortIndex = 0; sortIndex < sortLen; sortIndex++ ) {col = sortList[ sortIndex ][ 0 ];order = sortList[ sortIndex ][ 1 ];// sort direction, true = asc, false = descdir = order === 0;
if ( c.sortStable && a[ col ] === b[ col ] && sortLen === 1 ) {return a[ c.columns ].order - b[ c.columns ].order;}
// fallback to natural sort since it is more robustnum = /n/i.test( ts.getSortType( c.parsers, col ) );if ( num && c.strings[ col ] ) {// sort strings in numerical columnsif ( typeof ( ts.string[ c.strings[ col ] ] ) === \'boolean\' ) {num = ( dir ? 1 : -1 ) * ( ts.string[ c.strings[ col ] ] ? -1 : 1 );} else {num = ( c.strings[ col ] ) ? ts.string[ c.strings[ col ] ] || 0 : 0;}// fall back to built-in numeric sort// var sort = $.tablesorter[\'sort\' + s]( a[col], b[col], dir, colMax[col], table );sort = c.numberSorter ? c.numberSorter( a[ col ], b[ col ], dir, colMax[ col ], table ) :ts[ \'sortNumeric\' + ( dir ? \'Asc\' : \'Desc\' ) ]( a[ col ], b[ col ], num, colMax[ col ], col, c );} else {// set a & b depending on sort directionx = dir ? a : b;y = dir ? b : a;// text sort functionif ( typeof textSorter === \'function\' ) {// custom OVERALL text sortersort = textSorter( x[ col ], y[ col ], dir, col, table );} else if ( typeof sorter[ col ] === \'function\' ) {// custom text sorter for a SPECIFIC COLUMNsort = sorter[ col ]( x[ col ], y[ col ], dir, col, table );} else {// fall back to natural sortsort = ts[ \'sortNatural\' + ( dir ? \'Asc\' : \'Desc\' ) ]( a[ col ], b[ col ], col, c );}}if ( sort ) { return sort; }}return a[ c.columns ].order - b[ c.columns ].order;});}if ( c.debug ) {console.log( \'Applying sort \' + sortList.toString() + ts.benchmark( sortTime ) );}},
resortComplete : function( c, callback ) {if ( c.table.isUpdating ) {c.$table.triggerHandler( \'updateComplete\', c.table );}if ( $.isFunction( callback ) ) {callback( c.table );}},
checkResort : function( c, resort, callback ) {var sortList = $.isArray( resort ) ? resort : c.sortList,// if no resort parameter is passed, fallback to config.resort (true by default)resrt = typeof resort === \'undefined\' ? c.resort : resort;// don\'t try to resort if the table is still processing// this will catch spamming of the updateCell methodif ( resrt !== false && !c.serverSideSorting && !c.table.isProcessing ) {if ( sortList.length ) {ts.sortOn( c, sortList, function() {ts.resortComplete( c, callback );}, true );} else {ts.sortReset( c, function() {ts.resortComplete( c, callback );ts.applyWidget( c.table, false );} );}} else {ts.resortComplete( c, callback );ts.applyWidget( c.table, false );}},
sortOn : function( c, list, callback, init ) {var table = c.table;c.$table.triggerHandler( \'sortStart\', table );// update header count indexts.updateHeaderSortCount( c, list );// set css for headersts.setHeadersCss( c );// fixes #346if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {ts.buildCache( c );}c.$table.triggerHandler( \'sortBegin\', table );// sort the table and append it to the domts.multisort( c );ts.appendCache( c, init );c.$table.triggerHandler( \'sortBeforeEnd\', table );c.$table.triggerHandler( \'sortEnd\', table );ts.applyWidget( table );if ( $.isFunction( callback ) ) {callback( table );}},
sortReset : function( c, callback ) {c.sortList = [];ts.setHeadersCss( c );ts.multisort( c );ts.appendCache( c );var indx;for (indx = 0; indx < c.columns; indx++) {c.sortVars[ indx ].count = -1;}if ( $.isFunction( callback ) ) {callback( c.table );}},
getSortType : function( parsers, column ) {return ( parsers && parsers[ column ] ) ? parsers[ column ].type || \'\' : \'\';},
getOrder : function( val ) {// look for \'d\' in \'desc\' order; return truereturn ( /^d/i.test( val ) || val === 1 );},
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)sortNatural : function( a, b ) {if ( a === b ) { return 0; }a = a.toString();b = b.toString();var aNum, bNum, aFloat, bFloat, indx, max,regex = ts.regex;// first try and sort Hex codesif ( regex.hex.test( b ) ) {aNum = parseInt( ( a || \'\' ).match( regex.hex ), 16 );bNum = parseInt( ( b || \'\' ).match( regex.hex ), 16 );if ( aNum < bNum ) { return -1; }if ( aNum > bNum ) { return 1; }}// chunk/tokenizeaNum = ( a || \'\' ).replace( regex.chunk, \'\\0$1\\0\' ).replace( regex.chunks, \'\' ).split( \'\\0\' );bNum = ( b || \'\' ).replace( regex.chunk, \'\\0$1\\0\' ).replace( regex.chunks, \'\' ).split( \'\\0\' );max = Math.max( aNum.length, bNum.length );// natural sorting through split numeric strings and default stringsfor ( indx = 0; indx < max; indx++ ) {// find floats not starting with \'0\', string or 0 if not definedaFloat = isNaN( aNum[ indx ] ) ? aNum[ indx ] || 0 : parseFloat( aNum[ indx ] ) || 0;bFloat = isNaN( bNum[ indx ] ) ? bNum[ indx ] || 0 : parseFloat( bNum[ indx ] ) || 0;// handle numeric vs string comparison - number < string - (Kyle Adams)if ( isNaN( aFloat ) !== isNaN( bFloat ) ) { return isNaN( aFloat ) ? 1 : -1; }// rely on string comparison if different types - i.e. \'02\' < 2 != \'02\' < \'2\'if ( typeof aFloat !== typeof bFloat ) {aFloat += \'\';bFloat += \'\';}if ( aFloat < bFloat ) { return -1; }if ( aFloat > bFloat ) { return 1; }}return 0;},
sortNaturalAsc : function( a, b, col, c ) {if ( a === b ) { return 0; }var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];if ( a === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? -1 : 1 ) : -empty || -1; }if ( b === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? 1 : -1 ) : empty || 1; }return ts.sortNatural( a, b );},
sortNaturalDesc : function( a, b, col, c ) {if ( a === b ) { return 0; }var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];if ( a === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? -1 : 1 ) : empty || 1; }if ( b === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? 1 : -1 ) : -empty || -1; }return ts.sortNatural( b, a );},
// basic alphabetical sortsortText : function( a, b ) {return a > b ? 1 : ( a < b ? -1 : 0 );},
// return text string value by adding up ascii value// so the text is somewhat sorted when using a digital sort// this is NOT an alphanumeric sortgetTextValue : function( val, num, max ) {if ( max ) {// make sure the text value is greater than the max numerical value (max)var indx,len = val ? val.length : 0,n = max + num;for ( indx = 0; indx < len; indx++ ) {n += val.charCodeAt( indx );}return num * n;}return 0;},
sortNumericAsc : function( a, b, num, max, col, c ) {if ( a === b ) { return 0; }var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];if ( a === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? -1 : 1 ) : -empty || -1; }if ( b === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? 1 : -1 ) : empty || 1; }if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }return a - b;},
sortNumericDesc : function( a, b, num, max, col, c ) {if ( a === b ) { return 0; }var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];if ( a === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? -1 : 1 ) : empty || 1; }if ( b === \'\' && empty !== 0 ) { return typeof empty === \'boolean\' ? ( empty ? 1 : -1 ) : -empty || -1; }if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }return b - a;},
sortNumeric : function( a, b ) {return a - b;},
/*██ ██ ██ ██ █████▄ ▄████▄ ██████ ██████ ▄███████ ██ ██ ██ ██ ██ ██ ▄▄▄ ██▄▄ ██ ▀█▄██ ██ ██ ██ ██ ██ ██ ▀██ ██▀▀ ██ ▀█▄███████▀ ██ █████▀ ▀████▀ ██████ ██ █████▀*/addWidget : function( widget ) {if ( widget.id && !ts.isEmptyObject( ts.getWidgetById( widget.id ) ) ) {console.warn( \'"\' + widget.id + \'" widget was loaded more than once!\' );}ts.widgets[ ts.widgets.length ] = widget;},
hasWidget : function( $table, name ) {$table = $( $table );return $table.length && $table[ 0 ].config && $table[ 0 ].config.widgetInit[ name ] || false;},
getWidgetById : function( name ) {var indx, widget,len = ts.widgets.length;for ( indx = 0; indx < len; indx++ ) {widget = ts.widgets[ indx ];if ( widget && widget.id && widget.id.toLowerCase() === name.toLowerCase() ) {return widget;}}},
applyWidgetOptions : function( table ) {var indx, widget, wo,c = table.config,len = c.widgets.length;if ( len ) {for ( indx = 0; indx < len; indx++ ) {widget = ts.getWidgetById( c.widgets[ indx ] );if ( widget && widget.options ) {wo = $.extend( true, {}, widget.options );c.widgetOptions = $.extend( true, wo, c.widgetOptions );// add widgetOptions to defaults for option validator$.extend( true, ts.defaults.widgetOptions, widget.options );}}}},
addWidgetFromClass : function( table ) {var len, indx,c = table.config,// look for widgets to apply from table class// don\'t match from \'ui-widget-content\'; use \S instead of \w to include widgets// with dashes in the name, e.g. "widget-test-2" extracts out "test-2"regex = \'^\' + c.widgetClass.replace( ts.regex.templateName, \'(\\S+)+\' ) + \'$\',widgetClass = new RegExp( regex, \'g\' ),// split up table class (widget id\'s can include dashes) - stop using match// otherwise only one widget gets extracted, see #1109widgets = ( table.className || \'\' ).split( ts.regex.spaces );if ( widgets.length ) {len = widgets.length;for ( indx = 0; indx < len; indx++ ) {if ( widgets[ indx ].match( widgetClass ) ) {c.widgets[ c.widgets.length ] = widgets[ indx ].replace( widgetClass, \'$1\' );}}}},
applyWidgetId : function( table, id, init ) {table = $(table)[0];var applied, time, name,c = table.config,wo = c.widgetOptions,widget = ts.getWidgetById( id );if ( widget ) {name = widget.id;applied = false;// add widget name to option list so it gets reapplied after sorting, filtering, etcif ( $.inArray( name, c.widgets ) < 0 ) {c.widgets[ c.widgets.length ] = name;}if ( c.debug ) { time = new Date(); }
if ( init || !( c.widgetInit[ name ] ) ) {// set init flag first to prevent calling init more than once (e.g. pager)c.widgetInit[ name ] = true;if ( table.hasInitialized ) {// don\'t reapply widget options on tablesorter initts.applyWidgetOptions( table );}if ( typeof widget.init === \'function\' ) {applied = true;if ( c.debug ) {console[ console.group ? \'group\' : \'log\' ]( \'Initializing \' + name + \' widget\' );}widget.init( table, widget, c, wo );}}if ( !init && typeof widget.format === \'function\' ) {applied = true;if ( c.debug ) {console[ console.group ? \'group\' : \'log\' ]( \'Updating \' + name + \' widget\' );}widget.format( table, c, wo, false );}if ( c.debug ) {if ( applied ) {console.log( \'Completed \' + ( init ? \'initializing \' : \'applying \' ) + name + \' widget\' + ts.benchmark( time ) );if ( console.groupEnd ) { console.groupEnd(); }}}}},
applyWidget : function( table, init, callback ) {table = $( table )[ 0 ]; // in case this is called externallyvar indx, len, names, widget, time,c = table.config,widgets = [];// prevent numerous consecutive widget applicationsif ( init !== false && table.hasInitialized && ( table.isApplyingWidgets || table.isUpdating ) ) {return;}if ( c.debug ) { time = new Date(); }ts.addWidgetFromClass( table );// prevent "tablesorter-ready" from firing multiple times in a rowclearTimeout( c.timerReady );if ( c.widgets.length ) {table.isApplyingWidgets = true;// ensure unique widget idsc.widgets = $.grep( c.widgets, function( val, index ) {return $.inArray( val, c.widgets ) === index;});names = c.widgets || [];len = names.length;// build widget array & add priority as neededfor ( indx = 0; indx < len; indx++ ) {widget = ts.getWidgetById( names[ indx ] );if ( widget && widget.id ) {// set priority to 10 if not definedif ( !widget.priority ) { widget.priority = 10; }widgets[ indx ] = widget;} else if ( c.debug ) {console.warn( \'"\' + names[ indx ] + \'" widget code does not exist!\' );}}// sort widgets by prioritywidgets.sort( function( a, b ) {return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;});// add/update selected widgetslen = widgets.length;if ( c.debug ) {console[ console.group ? \'group\' : \'log\' ]( \'Start \' + ( init ? \'initializing\' : \'applying\' ) + \' widgets\' );}for ( indx = 0; indx < len; indx++ ) {widget = widgets[ indx ];if ( widget && widget.id ) {ts.applyWidgetId( table, widget.id, init );}}if ( c.debug && console.groupEnd ) { console.groupEnd(); }}c.timerReady = setTimeout( function() {table.isApplyingWidgets = false;$.data( table, \'lastWidgetApplication\', new Date() );c.$table.triggerHandler( \'tablesorter-ready\' );// callback executed on init onlyif ( !init && typeof callback === \'function\' ) {callback( table );}if ( c.debug ) {widget = c.widgets.length;console.log( \'Completed \' +( init === true ? \'initializing \' : \'applying \' ) + widget +\' widget\' + ( widget !== 1 ? \'s\' : \'\' ) + ts.benchmark( time ) );}}, 10 );},
removeWidget : function( table, name, refreshing ) {table = $( table )[ 0 ];var index, widget, indx, len,c = table.config;// if name === true, add all widgets from $.tablesorter.widgetsif ( name === true ) {name = [];len = ts.widgets.length;for ( indx = 0; indx < len; indx++ ) {widget = ts.widgets[ indx ];if ( widget && widget.id ) {name[ name.length ] = widget.id;}}} else {// name can be either an array of widgets names,// or a space/comma separated list of widget namesname = ( $.isArray( name ) ? name.join( \',\' ) : name || \'\' ).toLowerCase().split( /[\s,]+/ );}len = name.length;for ( index = 0; index < len; index++ ) {widget = ts.getWidgetById( name[ index ] );indx = $.inArray( name[ index ], c.widgets );// don\'t remove the widget from config.widget if refreshingif ( indx >= 0 && refreshing !== true ) {c.widgets.splice( indx, 1 );}if ( widget && widget.remove ) {if ( c.debug ) {console.log( ( refreshing ? \'Refreshing\' : \'Removing\' ) + \' "\' + name[ index ] + \'" widget\' );}widget.remove( table, c, c.widgetOptions, refreshing );c.widgetInit[ name[ index ] ] = false;}}},
refreshWidgets : function( table, doAll, dontapply ) {table = $( table )[ 0 ]; // see issue #243var indx, widget,c = table.config,curWidgets = c.widgets,widgets = ts.widgets,len = widgets.length,list = [],callback = function( table ) {$( table ).triggerHandler( \'refreshComplete\' );};// remove widgets not defined in config.widgets, unless doAll is truefor ( indx = 0; indx < len; indx++ ) {widget = widgets[ indx ];if ( widget && widget.id && ( doAll || $.inArray( widget.id, curWidgets ) < 0 ) ) {list[ list.length ] = widget.id;}}ts.removeWidget( table, list.join( \',\' ), true );if ( dontapply !== true ) {// call widget init ifts.applyWidget( table, doAll || false, callback );if ( doAll ) {// apply widget formatts.applyWidget( table, false, callback );}} else {callback( table );}},
/*██ ██ ██████ ██ ██ ██ ██████ ██ ██████ ▄███████ ██ ██ ██ ██ ██ ██ ██ ██▄▄ ▀█▄██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀█▄▀████▀ ██ ██ ██████ ██ ██ ██ ██████ █████▀*/benchmark : function( diff ) {return ( \' (\' + ( new Date().getTime() - diff.getTime() ) + \' ms)\' );},// deprecated ts.loglog : function() {console.log( arguments );},
// $.isEmptyObject from jQuery v1.4isEmptyObject : function( obj ) {/*jshint forin: false */for ( var name in obj ) {return false;}return true;},
isValueInArray : function( column, arry ) {var indx,len = arry && arry.length || 0;for ( indx = 0; indx < len; indx++ ) {if ( arry[ indx ][ 0 ] === column ) {return indx;}}return -1;},
formatFloat : function( str, table ) {if ( typeof str !== \'string\' || str === \'\' ) { return str; }// allow using formatFloat without a table; defaults to US number formatvar num,usFormat = table && table.config ? table.config.usNumberFormat !== false :typeof table !== \'undefined\' ? table : true;if ( usFormat ) {// US Format - 1,234,567.89 -> 1234567.89str = str.replace( ts.regex.comma, \'\' );} else {// German Format = 1.234.567,89 -> 1234567.89// French Format = 1 234 567,89 -> 1234567.89str = str.replace( ts.regex.digitNonUS, \'\' ).replace( ts.regex.comma, \'.\' );}if ( ts.regex.digitNegativeTest.test( str ) ) {// make (#) into a negative number -> (10) = -10str = str.replace( ts.regex.digitNegativeReplace, \'-$1\' );}num = parseFloat( str );// return the text instead of zeroreturn isNaN( num ) ? $.trim( str ) : num;},
isDigit : function( str ) {// replace all unwanted chars and matchreturn isNaN( str ) ?ts.regex.digitTest.test( str.toString().replace( ts.regex.digitReplace, \'\' ) ) :str !== \'\';},
// computeTableHeaderCellIndexes from:// http://www.javascripttoolbox.com/lib/table/examples.php// http://www.javascripttoolbox.com/temp/table_cellindex.htmlcomputeColumnIndex : function( $rows, c ) {var i, j, k, l, cell, cells, rowIndex, rowSpan, colSpan, firstAvailCol,// total columns has been calculated, use it to set the matrixrowcolumns = c && c.columns || 0,matrix = [],matrixrow = new Array( columns );for ( i = 0; i < $rows.length; i++ ) {cells = $rows[ i ].cells;for ( j = 0; j < cells.length; j++ ) {cell = cells[ j ];rowIndex = cell.parentNode.rowIndex;rowSpan = cell.rowSpan || 1;colSpan = cell.colSpan || 1;if ( typeof matrix[ rowIndex ] === \'undefined\' ) {matrix[ rowIndex ] = [];}// Find first available column in the first rowfor ( k = 0; k < matrix[ rowIndex ].length + 1; k++ ) {if ( typeof matrix[ rowIndex ][ k ] === \'undefined\' ) {firstAvailCol = k;break;}}// jscs:disable disallowEmptyBlocksif ( columns && cell.cellIndex === firstAvailCol ) {// don\'t to anything} else if ( cell.setAttribute ) {// jscs:enable disallowEmptyBlocks// add data-column (setAttribute = IE8+)cell.setAttribute( \'data-column\', firstAvailCol );} else {// remove once we drop support for IE7 - 1/12/2016$( cell ).attr( \'data-column\', firstAvailCol );}for ( k = rowIndex; k < rowIndex + rowSpan; k++ ) {if ( typeof matrix[ k ] === \'undefined\' ) {matrix[ k ] = [];}matrixrow = matrix[ k ];for ( l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {matrixrow[ l ] = \'x\';}}}}return matrixrow.length;},
// automatically add a colgroup with col elements set to a percentage widthfixColumnWidth : function( table ) {table = $( table )[ 0 ];var overallWidth, percent, $tbodies, len, index,c = table.config,$colgroup = c.$table.children( \'colgroup\' );// remove plugin-added colgroup, in case we need to refresh the widthsif ( $colgroup.length && $colgroup.hasClass( ts.css.colgroup ) ) {$colgroup.remove();}if ( c.widthFixed && c.$table.children( \'colgroup\' ).length === 0 ) {$colgroup = $( \'<colgroup class="\' + ts.css.colgroup + \'">\' );overallWidth = c.$table.width();// only add col for visible columns - fixes #371$tbodies = c.$tbodies.find( \'tr:first\' ).children( \':visible\' );len = $tbodies.length;for ( index = 0; index < len; index++ ) {percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + \'%\';$colgroup.append( $( \'<col>\' ).css( \'width\', percent ) );}c.$table.prepend( $colgroup );}},
// get sorter, string, empty, etc options for each column from// jQuery data, metadata, header option or header class name (\'sorter-false\')// priority = jQuery data > meta > headers option > header class namegetData : function( header, configHeader, key ) {var meta, cl4ss,val = \'\',$header = $( header );if ( !$header.length ) { return \'\'; }meta = $.metadata ? $header.metadata() : false;cl4ss = \' \' + ( $header.attr( \'class\' ) || \'\' );if ( typeof $header.data( key ) !== \'undefined\' ||typeof $header.data( key.toLowerCase() ) !== \'undefined\' ) {// \'data-lockedOrder\' is assigned to \'lockedorder\'; but \'data-locked-order\' is assigned to \'lockedOrder\'// \'data-sort-initial-order\' is assigned to \'sortInitialOrder\'val += $header.data( key ) || $header.data( key.toLowerCase() );} else if ( meta && typeof meta[ key ] !== \'undefined\' ) {val += meta[ key ];} else if ( configHeader && typeof configHeader[ key ] !== \'undefined\' ) {val += configHeader[ key ];} else if ( cl4ss !== \' \' && cl4ss.match( \' \' + key + \'-\' ) ) {// include sorter class name \'sorter-text\', etc; now works with \'sorter-my-custom-parser\'val = cl4ss.match( new RegExp( \'\\s\' + key + \'-([\\w-]+)\' ) )[ 1 ] || \'\';}return $.trim( val );},
getColumnData : function( table, obj, indx, getCell, $headers ) {if ( typeof obj !== \'object\' || obj === null ) {return obj;}table = $( table )[ 0 ];var $header, key,c = table.config,$cells = ( $headers || c.$headers ),// c.$headerIndexed is not defined initially$cell = c.$headerIndexed && c.$headerIndexed[ indx ] ||$cells.filter( \'[data-column="\' + indx + \'"]:last\' );if ( typeof obj[ indx ] !== \'undefined\' ) {return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ];}for ( key in obj ) {if ( typeof key === \'string\' ) {$header = $cell// header cell with class/id.filter( key )// find elements within the header cell with cell/id.add( $cell.find( key ) );if ( $header.length ) {return obj[ key ];}}}return;},
// *** Process table ***// add processing indicatorisProcessing : function( $table, toggle, $headers ) {$table = $( $table );var c = $table[ 0 ].config,// default to all headers$header = $headers || $table.find( \'.\' + ts.css.header );if ( toggle ) {// don\'t use sortList if custom $headers usedif ( typeof $headers !== \'undefined\' && c.sortList.length > 0 ) {// get headers from the sortList$header = $header.filter( function() {// get data-column from attr to keep compatibility with jQuery 1.2.6return this.sortDisabled ?false :ts.isValueInArray( parseFloat( $( this ).attr( \'data-column\' ) ), c.sortList ) >= 0;});}$table.add( $header ).addClass( ts.css.processing + \' \' + c.cssProcessing );} else {$table.add( $header ).removeClass( ts.css.processing + \' \' + c.cssProcessing );}},
// detach tbody but save the position// don\'t use tbody because there are portions that look for a tbody index (updateCell)processTbody : function( table, $tb, getIt ) {table = $( table )[ 0 ];if ( getIt ) {table.isProcessing = true;$tb.before( \'<colgroup class="tablesorter-savemyplace"/>\' );return $.fn.detach ? $tb.detach() : $tb.remove();}var holdr = $( table ).find( \'colgroup.tablesorter-savemyplace\' );$tb.insertAfter( holdr );holdr.remove();table.isProcessing = false;},
clearTableBody : function( table ) {$( table )[ 0 ].config.$tbodies.children().detach();},
// used when replacing accented characters during sortingcharacterEquivalents : {\'a\' : \'\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5\', // áàâãäąå\'A\' : \'\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5\', // ÁÀÂÃÄĄÅ\'c\' : \'\u00e7\u0107\u010d\', // çćč\'C\' : \'\u00c7\u0106\u010c\', // ÇĆČ\'e\' : \'\u00e9\u00e8\u00ea\u00eb\u011b\u0119\', // éèêëěę\'E\' : \'\u00c9\u00c8\u00ca\u00cb\u011a\u0118\', // ÉÈÊËĚĘ\'i\' : \'\u00ed\u00ec\u0130\u00ee\u00ef\u0131\', // íìİîïı\'I\' : \'\u00cd\u00cc\u0130\u00ce\u00cf\', // ÍÌİÎÏ\'o\' : \'\u00f3\u00f2\u00f4\u00f5\u00f6\u014d\', // óòôõöō\'O\' : \'\u00d3\u00d2\u00d4\u00d5\u00d6\u014c\', // ÓÒÔÕÖŌ\'ss\': \'\u00df\', // ß (s sharp)\'SS\': \'\u1e9e\', // ẞ (Capital sharp s)\'u\' : \'\u00fa\u00f9\u00fb\u00fc\u016f\', // úùûüů\'U\' : \'\u00da\u00d9\u00db\u00dc\u016e\' // ÚÙÛÜŮ},
replaceAccents : function( str ) {var chr,acc = \'[\',eq = ts.characterEquivalents;if ( !ts.characterRegex ) {ts.characterRegexArray = {};for ( chr in eq ) {if ( typeof chr === \'string\' ) {acc += eq[ chr ];ts.characterRegexArray[ chr ] = new RegExp( \'[\' + eq[ chr ] + \']\', \'g\' );}}ts.characterRegex = new RegExp( acc + \']\' );}if ( ts.characterRegex.test( str ) ) {for ( chr in eq ) {if ( typeof chr === \'string\' ) {str = str.replace( ts.characterRegexArray[ chr ], chr );}}}return str;},
validateOptions : function( c ) {var setting, setting2, typ, timer,// ignore options containing an arrayignore = \'headers sortForce sortList sortAppend widgets\'.split( \' \' ),orig = c.originalSettings;if ( orig ) {if ( c.debug ) {timer = new Date();}for ( setting in orig ) {typ = typeof ts.defaults[setting];if ( typ === \'undefined\' ) {console.warn( \'Tablesorter Warning! "table.config.\' + setting + \'" option not recognized\' );} else if ( typ === \'object\' ) {for ( setting2 in orig[setting] ) {typ = ts.defaults[setting] && typeof ts.defaults[setting][setting2];if ( $.inArray( setting, ignore ) < 0 && typ === \'undefined\' ) {console.warn( \'Tablesorter Warning! "table.config.\' + setting + \'.\' + setting2 + \'" option not recognized\' );}}}}if ( c.debug ) {console.log( \'validate options time:\' + ts.benchmark( timer ) );}}},
// restore headersrestoreHeaders : function( table ) {var index, $cell,c = $( table )[ 0 ].config,$headers = c.$table.find( c.selectorHeaders ),len = $headers.length;// don\'t use c.$headers here in case header cells were swappedfor ( index = 0; index < len; index++ ) {$cell = $headers.eq( index );// only restore header cells if it is wrapped// because this is also used by the updateAll methodif ( $cell.find( \'.\' + ts.css.headerIn ).length ) {$cell.html( c.headerContent[ index ] );}}},
destroy : function( table, removeClasses, callback ) {table = $( table )[ 0 ];if ( !table.hasInitialized ) { return; }// remove all widgetsts.removeWidget( table, true, false );var events,$t = $( table ),c = table.config,debug = c.debug,$h = $t.find( \'thead:first\' ),$r = $h.find( \'tr.\' + ts.css.headerRow ).removeClass( ts.css.headerRow + \' \' + c.cssHeaderRow ),$f = $t.find( \'tfoot:first > tr\' ).children( \'th, td\' );if ( removeClasses === false && $.inArray( \'uitheme\', c.widgets ) >= 0 ) {// reapply uitheme classes, in case we want to maintain appearance$t.triggerHandler( \'applyWidgetId\', [ \'uitheme\' ] );$t.triggerHandler( \'applyWidgetId\', [ \'zebra\' ] );}// remove widget added rows, just in case$h.find( \'tr\' ).not( $r ).remove();// disable tablesorter - not using .unbind( namespace ) because namespacing was// added in jQuery v1.4.3 - see http://api.jquery.com/event.namespace/events = \'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton \' +\'appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave \' +\'keypress sortBegin sortEnd resetToLoadState \'.split( \' \' ).join( c.namespace + \' \' );$t.removeData( \'tablesorter\' ).unbind( events.replace( ts.regex.spaces, \' \' ) );c.$headers.add( $f ).removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join( \' \' ) ).removeAttr( \'data-column\' ).removeAttr( \'aria-label\' ).attr( \'aria-disabled\', \'true\' );$r.find( c.selectorSort ).unbind( ( \'mousedown mouseup keypress \'.split( \' \' ).join( c.namespace + \' \' ) ).replace( ts.regex.spaces, \' \' ) );ts.restoreHeaders( table );$t.toggleClass( ts.css.table + \' \' + c.tableClass + \' tablesorter-\' + c.theme, removeClasses === false );$t.removeClass(c.namespace.slice(1));// clear flag in case the plugin is initialized againtable.hasInitialized = false;delete table.config.cache;if ( typeof callback === \'function\' ) {callback( table );}if ( debug ) {console.log( \'tablesorter has been removed\' );}}
};
$.fn.tablesorter = function( settings ) {return this.each( function() {var table = this,// merge & extend config optionsc = $.extend( true, {}, ts.defaults, settings, ts.instanceMethods );// save initial settingsc.originalSettings = settings;// create a table from data (build table widget)if ( !table.hasInitialized && ts.buildTable && this.nodeName !== \'TABLE\' ) {// return the table (in case the original target is the table\'s container)ts.buildTable( table, c );} else {ts.setup( table, c );}});};
// set up debug logsif ( !( window.console && window.console.log ) ) {// access $.tablesorter.logs for browsers that don\'t have a console...ts.logs = [];/*jshint -W020 */console = {};console.log = console.warn = console.error = console.table = function() {var arg = arguments.length > 1 ? arguments : arguments[0];ts.logs[ ts.logs.length ] = { date: Date.now(), log: arg };};}
// add default parsersts.addParser({id : \'no-parser\',is : function() {return false;},format : function() {return \'\';},type : \'text\'});
ts.addParser({id : \'text\',is : function() {return true;},format : function( str, table ) {var c = table.config;if ( str ) {str = $.trim( c.ignoreCase ? str.toLocaleLowerCase() : str );str = c.sortLocaleCompare ? ts.replaceAccents( str ) : str;}return str;},type : \'text\'});
ts.regex.nondigit = /[^\w,. \-()]/g;ts.addParser({id : \'digit\',is : function( str ) {return ts.isDigit( str );},format : function( str, table ) {var num = ts.formatFloat( ( str || \'\' ).replace( ts.regex.nondigit, \'\' ), table );return str && typeof num === \'number\' ? num :str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;},type : \'numeric\'});
ts.regex.currencyReplace = /[+\-,. ]/g;ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;ts.addParser({id : \'currency\',is : function( str ) {str = ( str || \'\' ).replace( ts.regex.currencyReplace, \'\' );// test for £$€¤¥¢return ts.regex.currencyTest.test( str );},format : function( str, table ) {var num = ts.formatFloat( ( str || \'\' ).replace( ts.regex.nondigit, \'\' ), table );return str && typeof num === \'number\' ? num :str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;},type : \'numeric\'});
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme// now, this regex can be updated before initializationts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\/(www\.)?/;ts.addParser({id : \'url\',is : function( str ) {return ts.regex.urlProtocolTest.test( str );},format : function( str ) {return str ? $.trim( str.replace( ts.regex.urlProtocolReplace, \'\' ) ) : str;},type : \'text\'});
ts.regex.dash = /-/g;ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;ts.addParser({id : \'isoDate\',is : function( str ) {return ts.regex.isoDate.test( str );},format : function( str, table ) {var date = str ? new Date( str.replace( ts.regex.dash, \'/\' ) ) : str;return date instanceof Date && isFinite( date ) ? date.getTime() : str;},type : \'numeric\'});
ts.regex.percent = /%/g;ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;ts.addParser({id : \'percent\',is : function( str ) {return ts.regex.percentTest.test( str ) && str.length < 15;},format : function( str, table ) {return str ? ts.formatFloat( str.replace( ts.regex.percent, \'\' ), table ) : str;},type : \'numeric\'});
// added image parser to core v2.17.9ts.addParser({id : \'image\',is : function( str, table, node, $node ) {return $node.find( \'img\' ).length > 0;},format : function( str, table, cell ) {return $( cell ).find( \'img\' ).attr( table.config.imgAttr || \'alt\' ) || str;},parsed : true, // filter widget flagtype : \'text\'});
ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parserts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;ts.addParser({id : \'usLongDate\',is : function( str ) {// two digit years are not allowed cross-browser// Jan 01, 2013 12:34:56 PM or 01 Jan 2013return ts.regex.usLongDateTest1.test( str ) || ts.regex.usLongDateTest2.test( str );},format : function( str, table ) {var date = str ? new Date( str.replace( ts.regex.dateReplace, \'$1 $2\' ) ) : str;return date instanceof Date && isFinite( date ) ? date.getTime() : str;},type : \'numeric\'});
// testing for ##-##-#### or ####-##-##, so it\'s not perfect; time can be includedts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;// escaped "-" because JSHint in Firefox was showing it as an errorts.regex.shortDateReplace = /[\-.,]/g;// XXY covers MDY & DMY formatsts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;ts.convertFormat = function( dateString, format ) {dateString = ( dateString || \'\' ).replace( ts.regex.spaces, \' \' ).replace( ts.regex.shortDateReplace, \'/\' );if ( format === \'mmddyyyy\' ) {dateString = dateString.replace( ts.regex.shortDateXXY, \'$3/$1/$2\' );} else if ( format === \'ddmmyyyy\' ) {dateString = dateString.replace( ts.regex.shortDateXXY, \'$3/$2/$1\' );} else if ( format === \'yyyymmdd\' ) {dateString = dateString.replace( ts.regex.shortDateYMD, \'$1/$2/$3\' );}var date = new Date( dateString );return date instanceof Date && isFinite( date ) ? date.getTime() : \'\';};
ts.addParser({id : \'shortDate\', // \'mmddyyyy\', \'ddmmyyyy\' or \'yyyymmdd\'is : function( str ) {str = ( str || \'\' ).replace( ts.regex.spaces, \' \' ).replace( ts.regex.shortDateReplace, \'/\' );return ts.regex.shortDateTest.test( str );},format : function( str, table, cell, cellIndex ) {if ( str ) {var c = table.config,$header = c.$headerIndexed[ cellIndex ],format = $header.length && $header.data( \'dateFormat\' ) ||ts.getData( $header, ts.getColumnData( table, c.headers, cellIndex ), \'dateFormat\' ) ||c.dateFormat;// save format because getData can be slow...if ( $header.length ) {$header.data( \'dateFormat\', format );}return ts.convertFormat( str, format ) || str;}return str;},type : \'numeric\'});
// match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tkts.regex.timeTest = /^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i;ts.regex.timeMatch = /(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i;ts.addParser({id : \'time\',is : function( str ) {return ts.regex.timeTest.test( str );},format : function( str, table ) {// isolate time... ignore month, day and yearvar temp,timePart = ( str || \'\' ).match( ts.regex.timeMatch ),orig = new Date( str ),// no time component? default to 00:00 by leaving it out, but only if str is definedtime = str && ( timePart !== null ? timePart[ 0 ] : \'00:00 AM\' ),date = time ? new Date( \'2000/01/01 \' + time.replace( ts.regex.dateReplace, \'$1 $2\' ) ) : time;if ( date instanceof Date && isFinite( date ) ) {temp = orig instanceof Date && isFinite( orig ) ? orig.getTime() : 0;// if original string was a valid date, add it to the decimal so the column sorts in some kind of order// luckily new Date() ignores the decimalsreturn temp ? parseFloat( date.getTime() + \'.\' + orig.getTime() ) : date.getTime();}return str;},type : \'numeric\'});
ts.addParser({id : \'metadata\',is : function() {return false;},format : function( str, table, cell ) {var c = table.config,p = ( !c.parserMetadataName ) ? \'sortValue\' : c.parserMetadataName;return $( cell ).metadata()[ p ];},type : \'numeric\'});
/*██████ ██████ █████▄ █████▄ ▄████▄ ▄█▀ ██▄▄ ██▄▄██ ██▄▄██ ██▄▄██▄█▀ ██▀▀ ██▀▀██ ██▀▀█ ██▀▀████████ ██████ █████▀ ██ ██ ██ ██*/// add default widgetsts.addWidget({id : \'zebra\',priority : 90,format : function( table, c, wo ) {var $visibleRows, $row, count, isEven, tbodyIndex, rowIndex, len,child = new RegExp( c.cssChildRow, \'i\' ),$tbodies = c.$tbodies.add( $( c.namespace + \'_extra_table\' ).children( \'tbody:not(.\' + c.cssInfoBlock + \')\' ) );for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {// loop through the visible rowscount = 0;$visibleRows = $tbodies.eq( tbodyIndex ).children( \'tr:visible\' ).not( c.selectorRemove );len = $visibleRows.length;for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {$row = $visibleRows.eq( rowIndex );// style child rows the same way the parent row was styledif ( !child.test( $row[ 0 ].className ) ) { count++; }isEven = ( count % 2 === 0 );$row.removeClass( wo.zebra[ isEven ? 1 : 0 ] ).addClass( wo.zebra[ isEven ? 0 : 1 ] );}}},remove : function( table, c, wo, refreshing ) {if ( refreshing ) { return; }var tbodyIndex, $tbody,$tbodies = c.$tbodies,toRemove = ( wo.zebra || [ \'even\', \'odd\' ] ).join( \' \' );for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ){$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody$tbody.children().removeClass( toRemove );ts.processTbody( table, $tbody, false ); // restore tbody}}});
})( jQuery );