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