rockyan

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="确定" />\',

\'&nbsp;<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 );

 

分类:

技术点:

相关文章: