• 日期选择器-----tablesorter


    HTML:

    <li>
      <label>检查时间</label>
      <ul class="inspect_time">
        <li class="retrieval_color">今天</li>
        <li>昨天</li>
        <li>最近3天</li>
        <li>最近7天</li>
        <li style="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;
    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 {
    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 {
    80px;
    text-align: center;
    border: 1px solid #DDD;
    }

    .gri_dateRangeOptions div.gri_dateRangeInput {
    margin-bottom: 5px;
    }

    .gri_dateRangePreMonth {
    float: left;
    15px;
    height: 17px;
    background: url('./images/page.png') no-repeat 0 0;
    overflow: hidden;
    }

    .gri_dateRangeNextMonth {
    float: right;
    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{/*====*/
    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;
    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{*536px;}
    .ta_calendar1{*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{ 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;
    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;
    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;
    180px;
    z-index: 2;
    }

    .ta_ipt_text_s {
    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- 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' : 'u00e1u00e0u00e2u00e3u00e4u0105u00e5', // áàâãäąå'A' : 'u00c1u00c0u00c2u00c3u00c4u0104u00c5', // ÁÀÂÃÄĄÅ'c' : 'u00e7u0107u010d', // çćč'C' : 'u00c7u0106u010c', // ÇĆČ'e' : 'u00e9u00e8u00eau00ebu011bu0119', // éèêëěę'E' : 'u00c9u00c8u00cau00cbu011au0118', // ÉÈÊËĚĘ'i' : 'u00edu00ecu0130u00eeu00efu0131', // íìİîïı'I' : 'u00cdu00ccu0130u00ceu00cf', // ÍÌİÎÏ'o' : 'u00f3u00f2u00f4u00f5u00f6u014d', // óòôõöō'O' : 'u00d3u00d2u00d4u00d5u00d6u014c', // ÓÒÔÕÖŌ'ss': 'u00df', // ß (s sharp)'SS': 'u1e9e', // ẞ (Capital sharp s)'u' : 'u00fau00f9u00fbu00fcu016f', // úùûüů'U' : 'u00dau00d9u00dbu00dcu016e' // ÚÙÛÜŮ},
    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$u20acu00a4u00a5u00a2?.]|[u00a3$u20acu00a4u00a5u00a2?.]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 = /(ds*?%|%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 );

    ゛Toly★小饼干ゞ
  • 相关阅读:
    Flink (一)概述
    【转】你未必知道的49个CSS知识点
    【转】清除浮动的四种方式及其原理理解
    前端知识总结
    【转】CSS为什么这么难学?方法很重要!
    【转】chrome开发者工具各种骚技巧
    【ASP.NET Core】设置Web API 响应的数据格式——Produces 特性篇
    【ASP.NET Core】绑定到 CancellationToken 对象
    【ASP.NET Core】设置 Web API 响应数据的格式——FormatFilter特性篇
    【ASP.NET Core】MVC 控制器的模型绑定(宏观篇)
  • 原文地址:https://www.cnblogs.com/rockyan/p/7245054.html
Copyright © 2020-2023  润新知