bootstrap daterangepicker 添加阴历及节假日
所有的新增都用 'myAdd start'和'myAdd end'标注,所有的修改都用'myChange start'和'myChange end'标注。
借用了 1900-2100区间内的公历、农历互转 自己添加了节假日数组及一个方法:传入calendar(公历或农历)m月d日获得该日期的节假日,修改后的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * @1900-2100区间内的公历、农历互转 3 * @charset UTF-8 4 * @Author Jea杨(JJonline@JJonline.Cn) 5 * @change by liyimin 6 * @Time 2014-7-21 7 * @Time 2016-8-13 Fixed 2033hex、Attribution Annals 8 * @Time 2016-9-25 Fixed lunar LeapMonth Param Bug 9 * @Version 1.0.2 10 * @公历转农历:myCalendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0] 11 * @农历转公历:myCalendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] 12 */ 13 var myCalendar = { 14 /** 15 * 农历1900-2100的润大小信息表 16 * @Array Of Property 17 * @return Hex 18 */ 19 lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, //1900-1909 20 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, //1910-1919 21 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, //1920-1929 22 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, //1930-1939 23 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, //1940-1949 24 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, //1950-1959 25 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, //1960-1969 26 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, //1970-1979 27 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //1980-1989 28 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, //1990-1999 29 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009 30 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019 31 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029 32 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039 33 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049 34 /**Add By JJonline@JJonline.Cn**/ 35 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059 36 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069 37 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079 38 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089 39 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099 40 0x0d520 41 ], //2100 42 /** 43 * 公历每个月份的天数普通表 44 * @Array Of Property 45 * @return Number 46 */ 47 solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], 48 /** 49 * 天干地支之天干速查表 50 * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] 51 * @return Cn string 52 */ 53 Gan: ["\u7532", "\u4e59", "\u4e19", "\u4e01", "\u620a", "\u5df1", "\u5e9a", "\u8f9b", "\u58ec", "\u7678"], 54 /** 55 * 天干地支之地支速查表 56 * @Array Of Property 57 * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] 58 * @return Cn string 59 */ 60 Zhi: ["\u5b50", "\u4e11", "\u5bc5", "\u536f", "\u8fb0", "\u5df3", "\u5348", "\u672a", "\u7533", "\u9149", "\u620c", "\u4ea5"], 61 /** 62 * 天干地支之地支速查表<=>生肖 63 * @Array Of Property 64 * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] 65 * @return Cn string 66 */ 67 Animals: ["\u9f20", "\u725b", "\u864e", "\u5154", "\u9f99", "\u86c7", "\u9a6c", "\u7f8a", "\u7334", "\u9e21", "\u72d7", "\u732a"], 68 /** 69 * 24节气速查表 70 * @Array Of Property 71 * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] 72 * @return Cn string 73 */ 74 solarTerm: ["\u5c0f\u5bd2", "\u5927\u5bd2", "\u7acb\u6625", "\u96e8\u6c34", "\u60ca\u86f0", "\u6625\u5206", "\u6e05\u660e", "\u8c37\u96e8", "\u7acb\u590f", "\u5c0f\u6ee1", "\u8292\u79cd", "\u590f\u81f3", "\u5c0f\u6691", "\u5927\u6691", "\u7acb\u79cb", "\u5904\u6691", "\u767d\u9732", "\u79cb\u5206", "\u5bd2\u9732", "\u971c\u964d", "\u7acb\u51ac", "\u5c0f\u96ea", "\u5927\u96ea", "\u51ac\u81f3"], 75 /** 76 * 1900-2100各年的24节气日期速查表 77 * @Array Of Property 78 * @return 0x string For splice 79 */ 80 sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'], 81 /** 82 * 数字转中文速查表 83 * @Array Of Property 84 * @trans ['日','一','二','三','四','五','六','七','八','九','十'] 85 * @return Cn string 86 */ 87 nStr1: ["\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341"], 88 /** 89 * 日期转农历称呼速查表 90 * @Array Of Property 91 * @trans ['初','十','廿','卅'] 92 * @return Cn string 93 */ 94 nStr2: ["\u521d", "\u5341", "\u5eff", "\u5345"], 95 /** 96 * 月份转农历称呼速查表 97 * @Array Of Property 98 * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] 99 * @return Cn string 100 */ 101 nStr3: ["\u6b63", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341", "\u51ac", "\u814a"], 102 103 /**myAdd start 104 * 节假日 105 * @Array Of Property 106 * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] 107 * @return Cn string 108 */ 109 //公历节日 110 sFtv: ["0101 元旦", "0214 情人节", 111 // "0308 妇女", 112 // "0312 植树", 113 // "0315 消费者权益日", 114 // "0401 愚人", 115 "0501 劳动节", 116 // "0504 青年", 117 // "0512 护士", 118 // "0601 儿童", 119 // "0701 建党", 120 // "0801 建军", 121 // "0910 教师节", 122 // "0928 孔子诞辰", 123 "1001 国庆节", 124 // "1006 老人", 125 // "1024 联合国日", 126 "1224 平安夜", "1225 圣诞" 127 ], 128 //农历节日 129 lFtv: ["0101 春节", "0115 元宵", "0505 端午", "0707 七夕", "0715 中元", "0815 中秋", "0909 重阳", "1208 腊八", "1224 小年"], 130 /**myAdd end*/ 131 132 /** 133 * 返回农历y年一整年的总天数 134 * @param lunar Year 135 * @return Number 136 * @eg:var count = myCalendar.lYearDays(1987) ;//count=387 137 */ 138 lYearDays: function(y) { 139 var i, sum = 348; 140 for (i = 0x8000; i > 0x8; i >>= 1) { 141 sum += (myCalendar.lunarInfo[y - 1900] & i) ? 1 : 0; 142 } 143 return (sum + myCalendar.leapDays(y)); 144 }, 145 /** 146 * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 147 * @param lunar Year 148 * @return Number (0-12) 149 * @eg:var leapMonth = myCalendar.leapMonth(1987) ;//leapMonth=6 150 */ 151 leapMonth: function(y) { //闰字编码 \u95f0 152 return (myCalendar.lunarInfo[y - 1900] & 0xf); 153 }, 154 /** 155 * 返回农历y年闰月的天数 若该年没有闰月则返回0 156 * @param lunar Year 157 * @return Number (0、29、30) 158 * @eg:var leapMonthDay = myCalendar.leapDays(1987) ;//leapMonthDay=29 159 */ 160 leapDays: function(y) { 161 if (myCalendar.leapMonth(y)) { 162 return ((myCalendar.lunarInfo[y - 1900] & 0x10000) ? 30 : 29); 163 } 164 return (0); 165 }, 166 /** 167 * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 168 * @param lunar Year 169 * @return Number (-1、29、30) 170 * @eg:var MonthDay = myCalendar.monthDays(1987,9) ;//MonthDay=29 171 */ 172 monthDays: function(y, m) { 173 if (m > 12 || m < 1) { 174 return -1 175 } //月份参数从1至12,参数错误返回-1 176 return ((myCalendar.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29); 177 }, 178 /** 179 * 返回公历(!)y年m月的天数 180 * @param solar Year 181 * @return Number (-1、28、29、30、31) 182 * @eg:var solarMonthDay = myCalendar.leapDays(1987) ;//solarMonthDay=30 183 */ 184 solarDays: function(y, m) { 185 if (m > 12 || m < 1) { 186 return -1 187 } //若参数错误 返回-1 188 var ms = m - 1; 189 if (ms == 1) { //2月份的闰平规律测算后确认返回28或29 190 return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28); 191 } else { 192 return (myCalendar.solarMonth[ms]); 193 } 194 }, 195 /** 196 * 农历年份转换为干支纪年 197 * @param lYear 农历年的年份数 198 * @return Cn string 199 */ 200 toGanZhiYear: function(lYear) { 201 var ganKey = (lYear - 3) % 10; 202 var zhiKey = (lYear - 3) % 12; 203 if (ganKey == 0) ganKey = 10; //如果余数为0则为最后一个天干 204 if (zhiKey == 0) zhiKey = 12; //如果余数为0则为最后一个地支 205 return myCalendar.Gan[ganKey - 1] + myCalendar.Zhi[zhiKey - 1]; 206 }, 207 /** 208 * 公历月、日判断所属星座 209 * @param cMonth [description] 210 * @param cDay [description] 211 * @return Cn string 212 */ 213 toAstro: function(cMonth, cDay) { 214 var s = "\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf"; 215 var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]; 216 return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + "\u5ea7"; //座 217 }, 218 /** 219 * 传入offset偏移量返回干支 220 * @param offset 相对甲子的偏移量 221 * @return Cn string 222 */ 223 toGanZhi: function(offset) { 224 return myCalendar.Gan[offset % 10] + myCalendar.Zhi[offset % 12]; 225 }, 226 /**myAdd start 227 * 传入calendar(公历或农历)m月d日获得该日期的节假日 228 * @param 229 * @return 230 * @eg:var 231 */ 232 getFestivals: function(m, d, calendar) { 233 var festivals; 234 if (calendar == 'lunar') { 235 festivalsArr = myCalendar.lFtv; 236 } else if (calendar == 'solar') { 237 festivalsArr = myCalendar.sFtv; 238 } 239 for (var i = 0, len = festivalsArr.length; i < len; i++) { 240 if (m == parseInt(festivalsArr[i].substr(0, 2)) && d == parseInt(festivalsArr[i].substr(2, 4))) { 241 return festivalsArr[i].substr(5); 242 } 243 } 244 }, 245 /**myAdd end*/ 246 247 /** 248 * 传入公历(!)y年获得该年第n个节气的公历日期 249 * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 250 * @return day Number 251 * @eg:var _24 = myCalendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 252 */ 253 getTerm: function(y, n) { 254 if (y < 1900 || y > 2100) { 255 return -1; 256 } 257 if (n < 1 || n > 24) { 258 return -1; 259 } 260 var _table = myCalendar.sTermInfo[y - 1900]; 261 var _info = [ 262 parseInt('0x' + _table.substr(0, 5)).toString(), 263 parseInt('0x' + _table.substr(5, 5)).toString(), 264 parseInt('0x' + _table.substr(10, 5)).toString(), 265 parseInt('0x' + _table.substr(15, 5)).toString(), 266 parseInt('0x' + _table.substr(20, 5)).toString(), 267 parseInt('0x' + _table.substr(25, 5)).toString() 268 ]; 269 var _calday = [ 270 _info[0].substr(0, 1), 271 _info[0].substr(1, 2), 272 _info[0].substr(3, 1), 273 _info[0].substr(4, 2), 274 _info[1].substr(0, 1), 275 _info[1].substr(1, 2), 276 _info[1].substr(3, 1), 277 _info[1].substr(4, 2), 278 _info[2].substr(0, 1), 279 _info[2].substr(1, 2), 280 _info[2].substr(3, 1), 281 _info[2].substr(4, 2), 282 _info[3].substr(0, 1), 283 _info[3].substr(1, 2), 284 _info[3].substr(3, 1), 285 _info[3].substr(4, 2), 286 _info[4].substr(0, 1), 287 _info[4].substr(1, 2), 288 _info[4].substr(3, 1), 289 _info[4].substr(4, 2), 290 _info[5].substr(0, 1), 291 _info[5].substr(1, 2), 292 _info[5].substr(3, 1), 293 _info[5].substr(4, 2), 294 ]; 295 return parseInt(_calday[n - 1]); 296 }, 297 /** 298 * 传入农历数字月份返回汉语通俗表示法 299 * @param lunar month 300 * @return Cn string 301 * @eg:var cnMonth = myCalendar.toChinaMonth(12) ;//cnMonth='腊月' 302 */ 303 toChinaMonth: function(m) { // 月 => \u6708 304 if (m > 12 || m < 1) { 305 return -1 306 } //若参数错误 返回-1 307 var s = myCalendar.nStr3[m - 1]; 308 s += "\u6708"; //加上月字 309 return s; 310 }, 311 /** 312 * 传入农历日期数字返回汉字表示法 313 * @param lunar day 314 * @return Cn string 315 * @eg:var cnDay = myCalendar.toChinaDay(21) ;//cnMonth='廿一' 316 */ 317 toChinaDay: function(d) { //日 => \u65e5 318 var s; 319 switch (d) { 320 case 10: 321 s = '\u521d\u5341'; 322 break; 323 case 20: 324 s = '\u4e8c\u5341'; 325 break; 326 break; 327 case 30: 328 s = '\u4e09\u5341'; 329 break; 330 break; 331 default: 332 s = myCalendar.nStr2[Math.floor(d / 10)]; 333 s += myCalendar.nStr1[d % 10]; 334 } 335 return (s); 336 }, 337 /** 338 * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” 339 * @param y year 340 * @return Cn string 341 * @eg:var animal = myCalendar.getAnimal(1987) ;//animal='兔' 342 */ 343 getAnimal: function(y) { 344 return myCalendar.Animals[(y - 4) % 12] 345 }, 346 /** 347 * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON 348 * @param y solar year 349 * @param m solar month 350 * @param d solar day 351 * @return JSON object 352 * @eg:console.log(myCalendar.solar2lunar(1987,11,01)); 353 */ 354 solar2lunar: function(y, m, d) { //参数区间1900.1.31~2100.12.31 355 if (y < 1900 || y > 2100) { 356 return -1; 357 } //年份限定、上限 358 if (y == 1900 && m == 1 && d < 31) { 359 return -1; 360 } //下限 361 if (!y) { //未传参 获得当天 362 var objDate = new Date(); 363 } else { 364 var objDate = new Date(y, parseInt(m) - 1, d) 365 } 366 var i, leap = 0, 367 temp = 0; 368 //修正ymd参数 369 var y = objDate.getFullYear(), 370 m = objDate.getMonth() + 1, 371 d = objDate.getDate(); 372 var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000; 373 for (i = 1900; i < 2101 && offset > 0; i++) { 374 temp = myCalendar.lYearDays(i); 375 offset -= temp; 376 } 377 if (offset < 0) { 378 offset += temp; 379 i--; 380 } 381 //是否今天 382 var isTodayObj = new Date(), 383 isToday = false; 384 if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) { 385 isToday = true; 386 } 387 //星期几 388 var nWeek = objDate.getDay(), 389 cWeek = myCalendar.nStr1[nWeek]; 390 if (nWeek == 0) { 391 nWeek = 7; 392 } //数字表示周几顺应天朝周一开始的惯例 393 //农历年 394 var year = i; 395 var leap = myCalendar.leapMonth(i); //闰哪个月 396 var isLeap = false; 397 //效验闰月 398 for (i = 1; i < 13 && offset > 0; i++) { 399 //闰月 400 if (leap > 0 && i == (leap + 1) && isLeap == false) { 401 --i; 402 isLeap = true; 403 temp = myCalendar.leapDays(year); //计算农历闰月天数 404 } else { 405 temp = myCalendar.monthDays(year, i); //计算农历普通月天数 406 } 407 //解除闰月 408 if (isLeap == true && i == (leap + 1)) { 409 isLeap = false; 410 } 411 offset -= temp; 412 } 413 if (offset == 0 && leap > 0 && i == leap + 1) 414 if (isLeap) { 415 isLeap = false; 416 } else { 417 isLeap = true; 418 --i; 419 } 420 if (offset < 0) { 421 offset += temp; 422 --i; 423 } 424 //农历月 425 var month = i; 426 //农历日 427 var day = offset + 1; 428 //天干地支处理 429 var sm = m - 1; 430 var gzY = myCalendar.toGanZhiYear(year); 431 //月柱 1900年1月小寒以前为 丙子月(60进制12) 432 var firstNode = myCalendar.getTerm(year, (m * 2 - 1)); //返回当月「节」为几日开始 433 var secondNode = myCalendar.getTerm(year, (m * 2)); //返回当月「节」为几日开始 434 //依据12节气修正干支月 435 var gzM = myCalendar.toGanZhi((y - 1900) * 12 + m + 11); 436 if (d >= firstNode) { 437 gzM = myCalendar.toGanZhi((y - 1900) * 12 + m + 12); 438 } 439 //传入的日期的节气与否 440 var isTerm = false; 441 var Term = null; 442 if (firstNode == d) { 443 isTerm = true; 444 Term = myCalendar.solarTerm[m * 2 - 2]; 445 } 446 if (secondNode == d) { 447 isTerm = true; 448 Term = myCalendar.solarTerm[m * 2 - 1]; 449 } 450 //日柱 当月一日与 1900/1/1 相差天数 451 var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10; 452 var gzD = myCalendar.toGanZhi(dayCyclical + d - 1); 453 //该日期所属的星座 454 var astro = myCalendar.toAstro(m, d); 455 return { 456 'lYear': year, 457 'lMonth': month, 458 'lDay': day, 459 'Animal': myCalendar.getAnimal(year), 460 'IMonthCn': (isLeap ? "\u95f0" : '') + myCalendar.toChinaMonth(month), 461 'IDayCn': myCalendar.toChinaDay(day), 462 'cYear': y, 463 'cMonth': m, 464 'cDay': d, 465 'lunarFestivals': myCalendar.getFestivals(month, day, 'lunar'), //myAdd 466 'calendarFestivals': myCalendar.getFestivals(m, d, 'solar'), //myAdd 467 'gzYear': gzY, 468 'gzMonth': gzM, 469 'gzDay': gzD, 470 'isToday': isToday, 471 'isLeap': isLeap, 472 'nWeek': nWeek, 473 'ncWeek': "\u661f\u671f" + cWeek, 474 'isTerm': isTerm, 475 'Term': Term, 476 'astro': astro 477 }; 478 }, 479 /** 480 * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON 481 * @param y lunar year 482 * @param m lunar month 483 * @param d lunar day 484 * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] 485 * @return JSON object 486 * @eg:console.log(myCalendar.lunar2solar(1987,9,10)); 487 */ 488 lunar2solar: function(y, m, d, isLeapMonth) { //参数区间1900.1.31~2100.12.1 489 var isLeapMonth = !!isLeapMonth; 490 var leapOffset = 0; 491 var leapMonth = myCalendar.leapMonth(y); 492 var leapDay = myCalendar.leapDays(y); 493 if (isLeapMonth && (leapMonth != m)) { 494 return -1; 495 } //传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 496 if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { 497 return -1; 498 } //超出了最大极限值 499 var day = myCalendar.monthDays(y, m); 500 var _day = day; 501 //bugFix 2016-9-25 502 //if month is leap, _day use leapDays method 503 if (isLeapMonth) { 504 _day = myCalendar.leapDays(y, m); 505 } 506 if (y < 1900 || y > 2100 || d > _day) { 507 return -1; 508 } //参数合法性效验 509 //计算农历的时间差 510 var offset = 0; 511 for (var i = 1900; i < y; i++) { 512 offset += myCalendar.lYearDays(i); 513 } 514 var leap = 0, 515 isAdd = false; 516 for (var i = 1; i < m; i++) { 517 leap = myCalendar.leapMonth(y); 518 if (!isAdd) { //处理闰月 519 if (leap <= i && leap > 0) { 520 offset += myCalendar.leapDays(y); 521 isAdd = true; 522 } 523 } 524 offset += myCalendar.monthDays(y, i); 525 } 526 //转换闰月农历 需补充该年闰月的前一个月的时差 527 if (isLeapMonth) { 528 offset += day; 529 } 530 //1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) 531 var stmap = Date.UTC(1900, 1, 30, 0, 0, 0); 532 var calObj = new Date((offset + d - 31) * 86400000 + stmap); 533 var cY = calObj.getUTCFullYear(); 534 var cM = calObj.getUTCMonth() + 1; 535 var cD = calObj.getUTCDate(); 536 return myCalendar.solar2lunar(cY, cM, cD); 537 } 538 };
对daterangepicker修改后的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * @version: 2.1.22 3 * @author: Dan Grossman http://www.dangrossman.info/ 4 * change by liyimin 5 * @copyright: Copyright (c) 2012-2016 Dan Grossman. All rights reserved. 6 * @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php 7 * @website: https://www.improvely.com/ 8 */ 9 // Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js 10 (function(root, factory) { 11 if (typeof define === 'function' && define.amd) { 12 // AMD. Make globaly available as well 13 define(['moment', 'jquery'], function(moment, jquery) { 14 return (root.daterangepicker = factory(moment, jquery)); 15 }); 16 } else if (typeof module === 'object' && module.exports) { 17 // Node / Browserify 18 //isomorphic issue 19 var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined; 20 if (!jQuery) { 21 jQuery = require('jquery'); 22 if (!jQuery.fn) jQuery.fn = {}; 23 } 24 module.exports = factory(require('moment'), jQuery); 25 } else { 26 // Browser globals 27 root.daterangepicker = factory(root.moment, root.jQuery); 28 } 29 }(this, function(moment, $) { 30 var DateRangePicker = function(element, options, cb) { 31 //default settings for options 32 this.parentEl = 'body'; 33 this.element = $(element); 34 this.startDate = moment().startOf('day'); 35 this.endDate = moment().endOf('day'); 36 this.minDate = false; 37 this.maxDate = false; 38 this.dateLimit = false; 39 this.autoApply = false; 40 this.singleDatePicker = false; 41 this.showDropdowns = false; 42 this.showWeekNumbers = false; 43 this.showISOWeekNumbers = false; 44 this.timePicker = false; 45 this.timePicker24Hour = false; 46 this.timePickerIncrement = 1; 47 this.timePickerSeconds = false; 48 this.linkedCalendars = true; 49 this.autoUpdateInput = true; 50 this.alwaysShowCalendars = false; 51 this.ranges = {}; 52 this.opens = 'right'; 53 if (this.element.hasClass('pull-right')) this.opens = 'left'; 54 this.drops = 'down'; 55 if (this.element.hasClass('dropup')) this.drops = 'up'; 56 this.buttonClasses = 'btn btn-sm'; 57 this.applyClass = 'btn-success'; 58 this.cancelClass = 'btn-default'; 59 this.locale = { 60 direction: 'ltr', 61 format: 'MM/DD/YYYY', 62 separator: ' - ', 63 applyLabel: 'Apply', 64 cancelLabel: 'Cancel', 65 weekLabel: 'W', 66 customRangeLabel: 'Custom Range', 67 daysOfWeek: moment.weekdaysMin(), 68 monthNames: moment.monthsShort(), 69 firstDay: moment.localeData().firstDayOfWeek() 70 }; 71 this.callback = function() {}; 72 //some state information 73 this.isShowing = false; 74 this.leftCalendar = {}; 75 this.rightCalendar = {}; 76 //custom options from user 77 if (typeof options !== 'object' || options === null) options = {}; 78 //allow setting options with data attributes 79 //data-api options will be overwritten with custom javascript options 80 options = $.extend(this.element.data(), options); 81 //html template for the picker UI 82 if (typeof options.template !== 'string' && !(options.template instanceof $)) options.template = '<div class="daterangepicker dropdown-menu">' + '<div class="calendar left">' + '<div class="daterangepicker_input">' + '<input class="input-mini form-control" type="text" name="daterangepicker_start" value="" />' + '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' + '<div class="calendar-time">' + '<div></div>' + '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' + '</div>' + '</div>' + '<div class="calendar-table"></div>' + '</div>' + '<div class="calendar right">' + '<div class="daterangepicker_input">' + '<input class="input-mini form-control" type="text" name="daterangepicker_end" value="" />' + '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' + '<div class="calendar-time">' + '<div></div>' + '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' + '</div>' + '</div>' + '<div class="calendar-table"></div>' + '</div>' + '<div class="ranges">' + '<div class="range_inputs">' + '<button class="applyBtn" disabled="disabled" type="button"></button> ' + '<button class="cancelBtn" type="button"></button>' + '</div>' + '</div>' + '</div>'; 83 this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); 84 this.container = $(options.template).appendTo(this.parentEl); 85 // 86 // handle all the possible options overriding defaults 87 // 88 if (typeof options.locale === 'object') { 89 if (typeof options.locale.direction === 'string') this.locale.direction = options.locale.direction; 90 if (typeof options.locale.format === 'string') this.locale.format = options.locale.format; 91 if (typeof options.locale.separator === 'string') this.locale.separator = options.locale.separator; 92 if (typeof options.locale.daysOfWeek === 'object') this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); 93 if (typeof options.locale.monthNames === 'object') this.locale.monthNames = options.locale.monthNames.slice(); 94 if (typeof options.locale.firstDay === 'number') this.locale.firstDay = options.locale.firstDay; 95 if (typeof options.locale.applyLabel === 'string') this.locale.applyLabel = options.locale.applyLabel; 96 if (typeof options.locale.cancelLabel === 'string') this.locale.cancelLabel = options.locale.cancelLabel; 97 if (typeof options.locale.weekLabel === 'string') this.locale.weekLabel = options.locale.weekLabel; 98 if (typeof options.locale.customRangeLabel === 'string') this.locale.customRangeLabel = options.locale.customRangeLabel; 99 } 100 this.container.addClass(this.locale.direction); 101 if (typeof options.startDate === 'string') this.startDate = moment(options.startDate, this.locale.format); 102 if (typeof options.endDate === 'string') this.endDate = moment(options.endDate, this.locale.format); 103 if (typeof options.minDate === 'string') this.minDate = moment(options.minDate, this.locale.format); 104 if (typeof options.maxDate === 'string') this.maxDate = moment(options.maxDate, this.locale.format); 105 if (typeof options.startDate === 'object') this.startDate = moment(options.startDate); 106 if (typeof options.endDate === 'object') this.endDate = moment(options.endDate); 107 if (typeof options.minDate === 'object') this.minDate = moment(options.minDate); 108 if (typeof options.maxDate === 'object') this.maxDate = moment(options.maxDate); 109 // sanity check for bad options 110 if (this.minDate && this.startDate.isBefore(this.minDate)) this.startDate = this.minDate.clone(); 111 // sanity check for bad options 112 if (this.maxDate && this.endDate.isAfter(this.maxDate)) this.endDate = this.maxDate.clone(); 113 if (typeof options.applyClass === 'string') this.applyClass = options.applyClass; 114 if (typeof options.cancelClass === 'string') this.cancelClass = options.cancelClass; 115 if (typeof options.dateLimit === 'object') this.dateLimit = options.dateLimit; 116 if (typeof options.opens === 'string') this.opens = options.opens; 117 if (typeof options.drops === 'string') this.drops = options.drops; 118 if (typeof options.showWeekNumbers === 'boolean') this.showWeekNumbers = options.showWeekNumbers; 119 if (typeof options.showISOWeekNumbers === 'boolean') this.showISOWeekNumbers = options.showISOWeekNumbers; 120 if (typeof options.buttonClasses === 'string') this.buttonClasses = options.buttonClasses; 121 if (typeof options.buttonClasses === 'object') this.buttonClasses = options.buttonClasses.join(' '); 122 if (typeof options.showDropdowns === 'boolean') this.showDropdowns = options.showDropdowns; 123 if (typeof options.singleDatePicker === 'boolean') { 124 this.singleDatePicker = options.singleDatePicker; 125 if (this.singleDatePicker) this.endDate = this.startDate.clone(); 126 } 127 if (typeof options.timePicker === 'boolean') this.timePicker = options.timePicker; 128 if (typeof options.timePickerSeconds === 'boolean') this.timePickerSeconds = options.timePickerSeconds; 129 if (typeof options.timePickerIncrement === 'number') this.timePickerIncrement = options.timePickerIncrement; 130 if (typeof options.timePicker24Hour === 'boolean') this.timePicker24Hour = options.timePicker24Hour; 131 if (typeof options.autoApply === 'boolean') this.autoApply = options.autoApply; 132 if (typeof options.autoUpdateInput === 'boolean') this.autoUpdateInput = options.autoUpdateInput; 133 if (typeof options.linkedCalendars === 'boolean') this.linkedCalendars = options.linkedCalendars; 134 if (typeof options.isInvalidDate === 'function') this.isInvalidDate = options.isInvalidDate; 135 if (typeof options.isCustomDate === 'function') this.isCustomDate = options.isCustomDate; 136 if (typeof options.alwaysShowCalendars === 'boolean') this.alwaysShowCalendars = options.alwaysShowCalendars; 137 // update day names order to firstDay 138 if (this.locale.firstDay != 0) { 139 var iterator = this.locale.firstDay; 140 while (iterator > 0) { 141 this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); 142 iterator--; 143 } 144 } 145 var start, end, range; 146 //if no start/end dates set, check if an input element contains initial values 147 if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { 148 if ($(this.element).is('input[type=text]')) { 149 var val = $(this.element).val(), 150 split = val.split(this.locale.separator); 151 start = end = null; 152 if (split.length == 2) { 153 start = moment(split[0], this.locale.format); 154 end = moment(split[1], this.locale.format); 155 } else if (this.singleDatePicker && val !== "") { 156 start = moment(val, this.locale.format); 157 end = moment(val, this.locale.format); 158 } 159 if (start !== null && end !== null) { 160 this.setStartDate(start); 161 this.setEndDate(end); 162 } 163 } 164 } 165 if (typeof options.ranges === 'object') { 166 for (range in options.ranges) { 167 if (typeof options.ranges[range][0] === 'string') start = moment(options.ranges[range][0], this.locale.format); 168 else start = moment(options.ranges[range][0]); 169 if (typeof options.ranges[range][1] === 'string') end = moment(options.ranges[range][1], this.locale.format); 170 else end = moment(options.ranges[range][1]); 171 // If the start or end date exceed those allowed by the minDate or dateLimit 172 // options, shorten the range to the allowable period. 173 if (this.minDate && start.isBefore(this.minDate)) start = this.minDate.clone(); 174 var maxDate = this.maxDate; 175 if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate)) maxDate = start.clone().add(this.dateLimit); 176 if (maxDate && end.isAfter(maxDate)) end = maxDate.clone(); 177 // If the end of the range is before the minimum or the start of the range is 178 // after the maximum, don't display this range option at all. 179 if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day'))) continue; 180 //Support unicode chars in the range names. 181 var elem = document.createElement('textarea'); 182 elem.innerHTML = range; 183 var rangeHtml = elem.value; 184 this.ranges[rangeHtml] = [start, end]; 185 } 186 var list = '<ul>'; 187 for (range in this.ranges) { 188 list += '<li>' + range + '</li>'; 189 } 190 list += '<li>' + this.locale.customRangeLabel + '</li>'; 191 list += '</ul>'; 192 this.container.find('.ranges').prepend(list); 193 } 194 if (typeof cb === 'function') { 195 this.callback = cb; 196 } 197 if (!this.timePicker) { 198 this.startDate = this.startDate.startOf('day'); 199 this.endDate = this.endDate.endOf('day'); 200 this.container.find('.calendar-time').hide(); 201 } 202 //can't be used together for now 203 if (this.timePicker && this.autoApply) this.autoApply = false; 204 if (this.autoApply && typeof options.ranges !== 'object') { 205 this.container.find('.ranges').hide(); 206 } else if (this.autoApply) { 207 this.container.find('.applyBtn, .cancelBtn').addClass('hide'); 208 } 209 if (this.singleDatePicker) { 210 this.container.addClass('single'); 211 this.container.find('.calendar.left').addClass('single'); 212 this.container.find('.calendar.left').show(); 213 this.container.find('.calendar.right').hide(); 214 this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide(); 215 if (!this.timePicker) { 216 this.container.find('.ranges').hide(); 217 } 218 } 219 if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) { 220 this.container.addClass('show-calendar'); 221 } 222 this.container.addClass('opens' + this.opens); 223 //swap the position of the predefined ranges if opens right 224 if (typeof options.ranges !== 'undefined' && this.opens == 'right') { 225 this.container.find('.ranges').prependTo(this.container.find('.calendar.left').parent()); 226 } 227 //apply CSS classes and labels to buttons 228 this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses); 229 if (this.applyClass.length) this.container.find('.applyBtn').addClass(this.applyClass); 230 if (this.cancelClass.length) this.container.find('.cancelBtn').addClass(this.cancelClass); 231 this.container.find('.applyBtn').html(this.locale.applyLabel); 232 this.container.find('.cancelBtn').html(this.locale.cancelLabel); 233 // 234 // event listeners 235 // 236 this.container.find('.calendar').on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)).on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)).on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this)).on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)).on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this)).on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this)).on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this)).on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this)).on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this)) 237 //.on('keyup.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this)) 238 .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this)); 239 this.container.find('.ranges').on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)).on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)).on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)).on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this)).on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this)); 240 if (this.element.is('input') || this.element.is('button')) { 241 this.element.on({ 242 'click.daterangepicker': $.proxy(this.show, this), 243 'focus.daterangepicker': $.proxy(this.show, this), 244 'keyup.daterangepicker': $.proxy(this.elementChanged, this), 245 'keydown.daterangepicker': $.proxy(this.keydown, this) 246 }); 247 } else { 248 this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); 249 } 250 // 251 // if attached to a text input, set the initial value 252 // 253 if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { 254 this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); 255 this.element.trigger('change'); 256 } else if (this.element.is('input') && this.autoUpdateInput) { 257 this.element.val(this.startDate.format(this.locale.format)); 258 this.element.trigger('change'); 259 } 260 }; 261 DateRangePicker.prototype = { 262 constructor: DateRangePicker, 263 setStartDate: function(startDate) { 264 if (typeof startDate === 'string') this.startDate = moment(startDate, this.locale.format); 265 if (typeof startDate === 'object') this.startDate = moment(startDate); 266 if (!this.timePicker) this.startDate = this.startDate.startOf('day'); 267 if (this.timePicker && this.timePickerIncrement) this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 268 if (this.minDate && this.startDate.isBefore(this.minDate)) { 269 this.startDate = this.minDate; 270 if (this.timePicker && this.timePickerIncrement) this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 271 } 272 if (this.maxDate && this.startDate.isAfter(this.maxDate)) { 273 this.startDate = this.maxDate; 274 if (this.timePicker && this.timePickerIncrement) this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 275 } 276 if (!this.isShowing) this.updateElement(); 277 this.updateMonthsInView(); 278 }, 279 setEndDate: function(endDate) { 280 if (typeof endDate === 'string') this.endDate = moment(endDate, this.locale.format); 281 if (typeof endDate === 'object') this.endDate = moment(endDate); 282 if (!this.timePicker) this.endDate = this.endDate.endOf('day'); 283 if (this.timePicker && this.timePickerIncrement) this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 284 if (this.endDate.isBefore(this.startDate)) this.endDate = this.startDate.clone(); 285 if (this.maxDate && this.endDate.isAfter(this.maxDate)) this.endDate = this.maxDate; 286 if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate)) this.endDate = this.startDate.clone().add(this.dateLimit); 287 this.previousRightTime = this.endDate.clone(); 288 if (!this.isShowing) this.updateElement(); 289 this.updateMonthsInView(); 290 }, 291 isInvalidDate: function() { 292 return false; 293 }, 294 isCustomDate: function() { 295 return false; 296 }, 297 updateView: function() { 298 if (this.timePicker) { 299 this.renderTimePicker('left'); 300 this.renderTimePicker('right'); 301 if (!this.endDate) { 302 this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled'); 303 } else { 304 this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled'); 305 } 306 } 307 if (this.endDate) { 308 this.container.find('input[name="daterangepicker_end"]').removeClass('active'); 309 this.container.find('input[name="daterangepicker_start"]').addClass('active'); 310 } else { 311 this.container.find('input[name="daterangepicker_end"]').addClass('active'); 312 this.container.find('input[name="daterangepicker_start"]').removeClass('active'); 313 } 314 this.updateMonthsInView(); 315 this.updateCalendars(); 316 this.updateFormInputs(); 317 }, 318 updateMonthsInView: function() { 319 if (this.endDate) { 320 //if both dates are visible already, do nothing 321 if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month && (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) && (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))) { 322 return; 323 } 324 this.leftCalendar.month = this.startDate.clone().date(2); 325 if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) { 326 this.rightCalendar.month = this.endDate.clone().date(2); 327 } else { 328 this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); 329 } 330 } else { 331 if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) { 332 this.leftCalendar.month = this.startDate.clone().date(2); 333 this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); 334 } 335 } 336 if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) { 337 this.rightCalendar.month = this.maxDate.clone().date(2); 338 this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month'); 339 } 340 }, 341 updateCalendars: function() { 342 if (this.timePicker) { 343 var hour, minute, second; 344 if (this.endDate) { 345 hour = parseInt(this.container.find('.left .hourselect').val(), 10); 346 minute = parseInt(this.container.find('.left .minuteselect').val(), 10); 347 second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; 348 if (!this.timePicker24Hour) { 349 var ampm = this.container.find('.left .ampmselect').val(); 350 if (ampm === 'PM' && hour < 12) hour += 12; 351 if (ampm === 'AM' && hour === 12) hour = 0; 352 } 353 } else { 354 hour = parseInt(this.container.find('.right .hourselect').val(), 10); 355 minute = parseInt(this.container.find('.right .minuteselect').val(), 10); 356 second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; 357 if (!this.timePicker24Hour) { 358 var ampm = this.container.find('.right .ampmselect').val(); 359 if (ampm === 'PM' && hour < 12) hour += 12; 360 if (ampm === 'AM' && hour === 12) hour = 0; 361 } 362 } 363 this.leftCalendar.month.hour(hour).minute(minute).second(second); 364 this.rightCalendar.month.hour(hour).minute(minute).second(second); 365 } 366 this.renderCalendar('left'); 367 this.renderCalendar('right'); 368 //highlight any predefined range matching the current start and end dates 369 this.container.find('.ranges li').removeClass('active'); 370 if (this.endDate == null) return; 371 this.calculateChosenLabel(); 372 }, 373 renderCalendar: function(side) { 374 // 375 // Build the matrix of dates that will populate the calendar 376 // 377 var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar; 378 var month = calendar.month.month(); 379 var year = calendar.month.year(); 380 var hour = calendar.month.hour(); 381 var minute = calendar.month.minute(); 382 var second = calendar.month.second(); 383 var daysInMonth = moment([year, month]).daysInMonth(); 384 var firstDay = moment([year, month, 1]); 385 var lastDay = moment([year, month, daysInMonth]); 386 var lastMonth = moment(firstDay).subtract(1, 'month').month(); 387 var lastYear = moment(firstDay).subtract(1, 'month').year(); 388 var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); 389 var dayOfWeek = firstDay.day(); 390 //initialize a 6 rows x 7 columns array for the calendar 391 var calendar = []; 392 calendar.firstDay = firstDay; 393 calendar.lastDay = lastDay; 394 for (var i = 0; i < 6; i++) { 395 calendar[i] = []; 396 } 397 //populate the calendar with date objects 398 var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; 399 if (startDay > daysInLastMonth) startDay -= 7; 400 if (dayOfWeek == this.locale.firstDay) startDay = daysInLastMonth - 6; 401 var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]); 402 var col, row; 403 for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { 404 if (i > 0 && col % 7 === 0) { 405 col = 0; 406 row++; 407 } 408 calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second); 409 curDate.hour(12); 410 if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { 411 calendar[row][col] = this.minDate.clone(); 412 } 413 if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { 414 calendar[row][col] = this.maxDate.clone(); 415 } 416 } 417 //make the calendar object available to hoverDate/clickDate 418 if (side == 'left') { 419 this.leftCalendar.calendar = calendar; 420 } else { 421 this.rightCalendar.calendar = calendar; 422 } 423 // 424 // Display the calendar 425 // 426 var minDate = side == 'left' ? this.minDate : this.startDate; 427 var maxDate = this.maxDate; 428 var selected = side == 'left' ? this.startDate : this.endDate; 429 var arrow = this.locale.direction == 'ltr' ? { 430 left: 'chevron-left', 431 right: 'chevron-right' 432 } : { 433 left: 'chevron-right', 434 right: 'chevron-left' 435 }; 436 var html = '<table class="table-condensed">'; 437 html += '<thead>'; 438 html += '<tr>'; 439 // add empty cell for week number 440 if (this.showWeekNumbers || this.showISOWeekNumbers) html += '<th></th>'; 441 if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) { 442 html += '<th class="prev available"><i class="fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '"></i></th>'; 443 } else { 444 html += '<th></th>'; 445 } 446 var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); 447 if (this.showDropdowns) { 448 var currentMonth = calendar[1][1].month(); 449 var currentYear = calendar[1][1].year(); 450 var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); 451 var minYear = (minDate && minDate.year()) || (currentYear - 50); 452 var inMinYear = currentYear == minYear; 453 var inMaxYear = currentYear == maxYear; 454 var monthHtml = '<select class="monthselect">'; 455 for (var m = 0; m < 12; m++) { 456 if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) { 457 monthHtml += "<option value='" + m + "'" + (m === currentMonth ? " selected='selected'" : "") + ">" + this.locale.monthNames[m] + "</option>"; 458 } else { 459 monthHtml += "<option value='" + m + "'" + (m === currentMonth ? " selected='selected'" : "") + " disabled='disabled'>" + this.locale.monthNames[m] + "</option>"; 460 } 461 } 462 monthHtml += "</select>"; 463 var yearHtml = '<select class="yearselect">'; 464 for (var y = minYear; y <= maxYear; y++) { 465 yearHtml += '<option value="' + y + '"' + (y === currentYear ? ' selected="selected"' : '') + '>' + y + '</option>'; 466 } 467 yearHtml += '</select>'; 468 dateHtml = monthHtml + yearHtml; 469 } 470 /*myAdd start*/ 471 var yearMonthArr = dateHtml.split('月'); 472 var myVar = { 473 lunar: null, 474 // classStr:cname.replace(/^\s+|\s+$/g, ''), 475 year: parseInt(yearMonthArr[1]), 476 month: parseInt(yearMonthArr[0]), 477 day: 1, 478 lunarDay: null, 479 startDate: this.startDate.format('YYYY-MM-DD').split('-'), 480 //endDate:('endDate' in this)?this.endDate.format('YYYY-MM-DD').split('-'):null, 481 lunarMonth: '' 482 } 483 if (this.endDate == null && myVar.startDate[1] == myVar.month && myVar.startDate[0] == myVar.year) { 484 // console.log('no endDate') 485 myVar.lunar = myCalendar.solar2lunar(myVar.startDate[0], myVar.startDate[1], myVar.startDate[2]); 486 myVar.lunarMonth = '(农历 ' + myVar.lunar.IMonthCn + ')'; 487 } else if (this.endDate !== null) { 488 //console.log('has endDate') 489 myVar.endDate = this.endDate.format('YYYY-MM-DD').split('-'); 490 if (side == 'left' && myVar.startDate[1] == myVar.month && myVar.startDate[0] == myVar.year) { 491 //console.log('left') 492 myVar.lunar = myCalendar.solar2lunar(myVar.startDate[0], myVar.startDate[1], myVar.startDate[2]); 493 myVar.lunarMonth = '(农历 ' + myVar.lunar.IMonthCn + ')'; 494 } else if (side == 'right' && myVar.endDate[1] == myVar.month && myVar.endDate[0] == myVar.year) { 495 //console.log('right') 496 myVar.lunar = myCalendar.solar2lunar(myVar.endDate[0], myVar.endDate[1], myVar.endDate[2]); 497 myVar.lunarMonth = '(农历 ' + myVar.lunar.IMonthCn + ')'; 498 } 499 } 500 // console.log(myVar.lunar); 501 /*myAdd end*/ 502 /*myChange start*/ 503 html += '<th colspan="5" class="month">' + dateHtml + myVar.lunarMonth + '</th>'; //(农历 '+ myVar.lunar.IMonthCn +') 504 /*myChange end*/ 505 if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) { 506 html += '<th class="next available"><i class="fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '"></i></th>'; 507 } else { 508 html += '<th></th>'; 509 } 510 html += '</tr>'; 511 html += '<tr>'; 512 // add week number label 513 if (this.showWeekNumbers || this.showISOWeekNumbers) html += '<th class="week">' + this.locale.weekLabel + '</th>'; 514 $.each(this.locale.daysOfWeek, function(index, dayOfWeek) { 515 html += '<th>' + dayOfWeek + '</th>'; 516 }); 517 html += '</tr>'; 518 html += '</thead>'; 519 html += '<tbody>'; 520 //adjust maxDate to reflect the dateLimit setting in order to 521 //grey out end dates beyond the dateLimit 522 if (this.endDate == null && this.dateLimit) { 523 var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day'); 524 if (!maxDate || maxLimit.isBefore(maxDate)) { 525 maxDate = maxLimit; 526 } 527 } 528 for (var row = 0; row < 6; row++) { 529 html += '<tr>'; 530 // add week number 531 if (this.showWeekNumbers) html += '<td class="week" weekDateData=' + calendar[row][0].year() + '-' + (calendar[row][0].month() + 1) + '-' + calendar[row][0].date() + '>' + calendar[row][0].week() + '</td>'; 532 else if (this.showISOWeekNumbers) html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>'; 533 for (var col = 0; col < 7; col++) { 534 var classes = []; 535 //highlight today's date 536 if (calendar[row][col].isSame(new Date(), "day")) classes.push('today'); 537 //highlight weekends 538 if (calendar[row][col].isoWeekday() > 5) classes.push('weekend'); 539 //grey out the dates in other months displayed at beginning and end of this calendar 540 if (calendar[row][col].month() != calendar[1][1].month()) classes.push('off'); 541 //don't allow selection of dates before the minimum date 542 if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day')) classes.push('off', 'disabled'); 543 //don't allow selection of dates after the maximum date 544 if (maxDate && calendar[row][col].isAfter(maxDate, 'day')) classes.push('off', 'disabled'); 545 //don't allow selection of date if a custom function decides it's invalid 546 if (this.isInvalidDate(calendar[row][col])) classes.push('off', 'disabled'); 547 //highlight the currently selected start date 548 if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) classes.push('active', 'start-date'); 549 //highlight the currently selected end date 550 if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) classes.push('active', 'end-date'); 551 //highlight dates in-between the selected dates 552 if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate) classes.push('in-range'); 553 //apply custom classes for this date 554 var isCustom = this.isCustomDate(calendar[row][col]); 555 if (isCustom !== false) { 556 if (typeof isCustom === 'string') classes.push(isCustom); 557 else Array.prototype.push.apply(classes, isCustom); 558 } 559 var cname = '', 560 disabled = false; 561 for (var i = 0; i < classes.length; i++) { 562 cname += classes[i] + ' '; 563 if (classes[i] == 'disabled') disabled = true; 564 } 565 if (!disabled) cname += 'available'; 566 /*myAdd start*/ 567 myVar.year = parseInt(calendar[row][col].format("YYYY")); 568 myVar.month = parseInt(calendar[row][col].month()) + 1; 569 myVar.day = calendar[row][col].date(); 570 myVar.lunar = myCalendar.solar2lunar(myVar.year, myVar.month, myVar.day); 571 myVar.lunarDay = myVar.lunar.IDayCn; 572 myVar.lunarDayClass = 'lunarDay'; 573 // console.log(myVar.lunar) 574 if (myVar.lunar.Term || myVar.lunar.lunarFestivals || myVar.lunar.calendarFestivals) { 575 myVar.lunarDay = myVar.lunar.lunarFestivals || myVar.lunar.calendarFestivals || myVar.lunar.Term; 576 myVar.lunarDayClass += ' lunarTerm'; 577 } 578 /*myAdd end*/ 579 html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '<br /><span class="' + myVar.lunarDayClass + '">' + myVar.lunarDay + '</span></td>'; 580 } 581 html += '</tr>'; 582 } 583 html += '</tbody>'; 584 html += '</table>'; 585 this.container.find('.calendar.' + side + ' .calendar-table').html(html); 586 }, 587 renderTimePicker: function(side) { 588 var html, selected, minDate, maxDate = this.maxDate; 589 if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate))) maxDate = this.startDate.clone().add(this.dateLimit); 590 if (side == 'left') { 591 selected = this.startDate.clone(); 592 minDate = this.minDate; 593 } else if (side == 'right') { 594 selected = this.endDate ? this.endDate.clone() : this.previousRightTime.clone(); 595 minDate = this.startDate; 596 if (selected.isBefore(this.startDate)) selected = this.startDate.clone(); 597 if (maxDate && selected.isAfter(maxDate)) selected = maxDate.clone(); 598 //Preserve the time already selected 599 var timeSelector = this.container.find('.calendar.right .calendar-time div'); 600 if (!this.endDate && timeSelector.html() != '') { 601 selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour()); 602 selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute()); 603 selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second()); 604 if (!this.timePicker24Hour) { 605 var ampm = timeSelector.find('.ampmselect option:selected').val(); 606 if (ampm === 'PM' && selected.hour() < 12) selected.hour(selected.hour() + 12); 607 if (ampm === 'AM' && selected.hour() === 12) selected.hour(0); 608 } 609 } 610 } 611 // 612 // hours 613 // 614 html = '<select class="hourselect">'; 615 var start = this.timePicker24Hour ? 0 : 1; 616 var end = this.timePicker24Hour ? 23 : 12; 617 for (var i = start; i <= end; i++) { 618 var i_in_24 = i; 619 if (!this.timePicker24Hour) i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i); 620 var time = selected.clone().hour(i_in_24); 621 var disabled = false; 622 if (minDate && time.minute(59).isBefore(minDate)) disabled = true; 623 if (maxDate && time.minute(0).isAfter(maxDate)) disabled = true; 624 if (i_in_24 == selected.hour() && !disabled) { 625 html += '<option value="' + i + '" selected="selected">' + i + '</option>'; 626 } else if (disabled) { 627 html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>'; 628 } else { 629 html += '<option value="' + i + '">' + i + '</option>'; 630 } 631 } 632 html += '</select> '; 633 // 634 // minutes 635 // 636 html += ': <select class="minuteselect">'; 637 for (var i = 0; i < 60; i += this.timePickerIncrement) { 638 var padded = i < 10 ? '0' + i : i; 639 var time = selected.clone().minute(i); 640 var disabled = false; 641 if (minDate && time.second(59).isBefore(minDate)) disabled = true; 642 if (maxDate && time.second(0).isAfter(maxDate)) disabled = true; 643 if (selected.minute() == i && !disabled) { 644 html += '<option value="' + i + '" selected="selected">' + padded + '</option>'; 645 } else if (disabled) { 646 html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>'; 647 } else { 648 html += '<option value="' + i + '">' + padded + '</option>'; 649 } 650 } 651 html += '</select> '; 652 // 653 // seconds 654 // 655 if (this.timePickerSeconds) { 656 html += ': <select class="secondselect">'; 657 for (var i = 0; i < 60; i++) { 658 var padded = i < 10 ? '0' + i : i; 659 var time = selected.clone().second(i); 660 var disabled = false; 661 if (minDate && time.isBefore(minDate)) disabled = true; 662 if (maxDate && time.isAfter(maxDate)) disabled = true; 663 if (selected.second() == i && !disabled) { 664 html += '<option value="' + i + '" selected="selected">' + padded + '</option>'; 665 } else if (disabled) { 666 html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>'; 667 } else { 668 html += '<option value="' + i + '">' + padded + '</option>'; 669 } 670 } 671 html += '</select> '; 672 } 673 // 674 // AM/PM 675 // 676 if (!this.timePicker24Hour) { 677 html += '<select class="ampmselect">'; 678 var am_html = ''; 679 var pm_html = ''; 680 if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate)) am_html = ' disabled="disabled" class="disabled"'; 681 if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate)) pm_html = ' disabled="disabled" class="disabled"'; 682 if (selected.hour() >= 12) { 683 html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>'; 684 } else { 685 html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>'; 686 } 687 html += '</select>'; 688 } 689 this.container.find('.calendar.' + side + ' .calendar-time div').html(html); 690 }, 691 updateFormInputs: function() { 692 //ignore mouse movements while an above-calendar text input has focus 693 if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) return; 694 this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format)); 695 if (this.endDate) this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format)); 696 if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) { 697 this.container.find('button.applyBtn').removeAttr('disabled'); 698 } else { 699 this.container.find('button.applyBtn').attr('disabled', 'disabled'); 700 } 701 }, 702 move: function() { 703 var parentOffset = { 704 top: 0, 705 left: 0 706 }, 707 containerTop; 708 var parentRightEdge = $(window).width(); 709 if (!this.parentEl.is('body')) { 710 parentOffset = { 711 top: this.parentEl.offset().top - this.parentEl.scrollTop(), 712 left: this.parentEl.offset().left - this.parentEl.scrollLeft() 713 }; 714 parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; 715 } 716 if (this.drops == 'up') containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; 717 else containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; 718 this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup'); 719 if (this.opens == 'left') { 720 this.container.css({ 721 top: containerTop, 722 right: parentRightEdge - this.element.offset().left - this.element.outerWidth(), 723 left: 'auto' 724 }); 725 if (this.container.offset().left < 0) { 726 this.container.css({ 727 right: 'auto', 728 left: 9 729 }); 730 } 731 } else if (this.opens == 'center') { 732 this.container.css({ 733 top: containerTop, 734 left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 - this.container.outerWidth() / 2, 735 right: 'auto' 736 }); 737 if (this.container.offset().left < 0) { 738 this.container.css({ 739 right: 'auto', 740 left: 9 741 }); 742 } 743 } else { 744 this.container.css({ 745 top: containerTop, 746 left: this.element.offset().left - parentOffset.left, 747 right: 'auto' 748 }); 749 if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { 750 this.container.css({ 751 left: 'auto', 752 right: 0 753 }); 754 } 755 } 756 }, 757 show: function(e) { 758 if (this.isShowing) return; 759 // Create a click proxy that is private to this instance of datepicker, for unbinding 760 this._outsideClickProxy = $.proxy(function(e) { 761 this.outsideClick(e); 762 }, this); 763 // Bind global datepicker mousedown for hiding and 764 $(document).on('mousedown.daterangepicker', this._outsideClickProxy) 765 // also support mobile devices 766 .on('touchend.daterangepicker', this._outsideClickProxy) 767 // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them 768 .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy) 769 // and also close when focus changes to outside the picker (eg. tabbing between controls) 770 .on('focusin.daterangepicker', this._outsideClickProxy); 771 // Reposition the picker if the window is resized while it's open 772 $(window).on('resize.daterangepicker', $.proxy(function(e) { 773 this.move(e); 774 }, this)); 775 this.oldStartDate = this.startDate.clone(); 776 this.oldEndDate = this.endDate.clone(); 777 this.previousRightTime = this.endDate.clone(); 778 this.updateView(); 779 this.container.show(); 780 this.move(); 781 this.element.trigger('show.daterangepicker', this); 782 this.isShowing = true; 783 }, 784 hide: function(e) { 785 if (!this.isShowing) return; 786 //incomplete date selection, revert to last values 787 if (!this.endDate) { 788 this.startDate = this.oldStartDate.clone(); 789 this.endDate = this.oldEndDate.clone(); 790 } 791 //if a new date range was selected, invoke the user callback function 792 if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) this.callback(this.startDate, this.endDate, this.chosenLabel); 793 //if picker is attached to a text input, update it 794 this.updateElement(); 795 $(document).off('.daterangepicker'); 796 $(window).off('.daterangepicker'); 797 this.container.hide(); 798 this.element.trigger('hide.daterangepicker', this); 799 this.isShowing = false; 800 }, 801 toggle: function(e) { 802 if (this.isShowing) { 803 this.hide(); 804 } else { 805 this.show(); 806 } 807 }, 808 outsideClick: function(e) { 809 var target = $(e.target); 810 // if the page is clicked anywhere except within the daterangerpicker/button 811 // itself then call this.hide() 812 if ( 813 // ie modal dialog fix 814 e.type == "focusin" || target.closest(this.element).length || target.closest(this.container).length || target.closest('.calendar-table').length) return; 815 this.hide(); 816 }, 817 showCalendars: function() { 818 this.container.addClass('show-calendar'); 819 this.move(); 820 this.element.trigger('showCalendar.daterangepicker', this); 821 }, 822 hideCalendars: function() { 823 this.container.removeClass('show-calendar'); 824 this.element.trigger('hideCalendar.daterangepicker', this); 825 }, 826 hoverRange: function(e) { 827 //ignore mouse movements while an above-calendar text input has focus 828 if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) return; 829 var label = e.target.innerHTML; 830 if (label == this.locale.customRangeLabel) { 831 this.updateView(); 832 } else { 833 var dates = this.ranges[label]; 834 this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format)); 835 this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format)); 836 } 837 }, 838 clickRange: function(e) { 839 var label = e.target.innerHTML; 840 this.chosenLabel = label; 841 if (label == this.locale.customRangeLabel) { 842 this.showCalendars(); 843 } else { 844 var dates = this.ranges[label]; 845 this.startDate = dates[0]; 846 this.endDate = dates[1]; 847 if (!this.timePicker) { 848 this.startDate.startOf('day'); 849 this.endDate.endOf('day'); 850 } 851 if (!this.alwaysShowCalendars) this.hideCalendars(); 852 this.clickApply(); 853 } 854 }, 855 clickPrev: function(e) { 856 var cal = $(e.target).parents('.calendar'); 857 if (cal.hasClass('left')) { 858 this.leftCalendar.month.subtract(1, 'month'); 859 if (this.linkedCalendars) this.rightCalendar.month.subtract(1, 'month'); 860 } else { 861 this.rightCalendar.month.subtract(1, 'month'); 862 } 863 this.updateCalendars(); 864 }, 865 clickNext: function(e) { 866 var cal = $(e.target).parents('.calendar'); 867 if (cal.hasClass('left')) { 868 this.leftCalendar.month.add(1, 'month'); 869 } else { 870 this.rightCalendar.month.add(1, 'month'); 871 if (this.linkedCalendars) this.leftCalendar.month.add(1, 'month'); 872 } 873 this.updateCalendars(); 874 }, 875 hoverDate: function(e) { 876 //ignore mouse movements while an above-calendar text input has focus 877 if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) return; 878 //ignore dates that can't be selected 879 if (!$(e.target).hasClass('available')) return; 880 //have the text inputs above calendars reflect the date being hovered over 881 var title = $(e.target).attr('data-title'); 882 var row = title.substr(1, 1); 883 var col = title.substr(3, 1); 884 var cal = $(e.target).parents('.calendar'); 885 var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; 886 if (this.endDate) { 887 this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format)); 888 } else { 889 this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format)); 890 } 891 //highlight the dates between the start date and the date being hovered as a potential end date 892 var leftCalendar = this.leftCalendar; 893 var rightCalendar = this.rightCalendar; 894 var startDate = this.startDate; 895 if (!this.endDate) { 896 this.container.find('.calendar td').each(function(index, el) { 897 //skip week numbers, only look at dates 898 if ($(el).hasClass('week')) return; 899 var title = $(el).attr('data-title'); 900 var row = title.substr(1, 1); 901 var col = title.substr(3, 1); 902 var cal = $(el).parents('.calendar'); 903 var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col]; 904 if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) { 905 $(el).addClass('in-range'); 906 } else { 907 $(el).removeClass('in-range'); 908 } 909 }); 910 } 911 }, 912 clickDate: function(e) { 913 if (!$(e.target).hasClass('available')) return; 914 var title = $(e.target).attr('data-title'); 915 var row = title.substr(1, 1); 916 var col = title.substr(3, 1); 917 var cal = $(e.target).parents('.calendar'); 918 var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; 919 // 920 // this function needs to do a few things: 921 // * alternate between selecting a start and end date for the range, 922 // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date 923 // * if autoapply is enabled, and an end date was chosen, apply the selection 924 // * if single date picker mode, and time picker isn't enabled, apply the selection immediately 925 // 926 if (this.endDate || date.isBefore(this.startDate, 'day')) { 927 if (this.timePicker) { 928 var hour = parseInt(this.container.find('.left .hourselect').val(), 10); 929 if (!this.timePicker24Hour) { 930 var ampm = this.container.find('.left .ampmselect').val(); 931 if (ampm === 'PM' && hour < 12) hour += 12; 932 if (ampm === 'AM' && hour === 12) hour = 0; 933 } 934 var minute = parseInt(this.container.find('.left .minuteselect').val(), 10); 935 var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; 936 date = date.clone().hour(hour).minute(minute).second(second); 937 } 938 this.endDate = null; 939 this.setStartDate(date.clone()); 940 } else if (!this.endDate && date.isBefore(this.startDate)) { 941 //special case: clicking the same date for start/end, 942 //but the time of the end date is before the start date 943 this.setEndDate(this.startDate.clone()); 944 } else { 945 if (this.timePicker) { 946 var hour = parseInt(this.container.find('.right .hourselect').val(), 10); 947 if (!this.timePicker24Hour) { 948 var ampm = this.container.find('.right .ampmselect').val(); 949 if (ampm === 'PM' && hour < 12) hour += 12; 950 if (ampm === 'AM' && hour === 12) hour = 0; 951 } 952 var minute = parseInt(this.container.find('.right .minuteselect').val(), 10); 953 var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; 954 date = date.clone().hour(hour).minute(minute).second(second); 955 } 956 this.setEndDate(date.clone()); 957 if (this.autoApply) { 958 this.calculateChosenLabel(); 959 this.clickApply(); 960 } 961 } 962 if (this.singleDatePicker) { 963 this.setEndDate(this.startDate); 964 if (!this.timePicker) this.clickApply(); 965 } 966 this.updateView(); 967 }, 968 calculateChosenLabel: function() { 969 var customRange = true; 970 var i = 0; 971 for (var range in this.ranges) { 972 if (this.timePicker) { 973 if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) { 974 customRange = false; 975 this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html(); 976 break; 977 } 978 } else { 979 //ignore times when comparing dates if time picker is not enabled 980 if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { 981 customRange = false; 982 this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html(); 983 break; 984 } 985 } 986 i++; 987 } 988 if (customRange) { 989 this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html(); 990 this.showCalendars(); 991 } 992 }, 993 clickApply: function(e) { 994 this.hide(); 995 this.element.trigger('apply.daterangepicker', this); 996 }, 997 clickCancel: function(e) { 998 this.startDate = this.oldStartDate; 999 this.endDate = this.oldEndDate; 1000 this.hide(); 1001 this.element.trigger('cancel.daterangepicker', this); 1002 }, 1003 monthOrYearChanged: function(e) { 1004 var isLeft = $(e.target).closest('.calendar').hasClass('left'), 1005 leftOrRight = isLeft ? 'left' : 'right', 1006 cal = this.container.find('.calendar.' + leftOrRight); 1007 // Month must be Number for new moment versions 1008 var month = parseInt(cal.find('.monthselect').val(), 10); 1009 var year = cal.find('.yearselect').val(); 1010 if (!isLeft) { 1011 if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) { 1012 month = this.startDate.month(); 1013 year = this.startDate.year(); 1014 } 1015 } 1016 if (this.minDate) { 1017 if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) { 1018 month = this.minDate.month(); 1019 year = this.minDate.year(); 1020 } 1021 } 1022 if (this.maxDate) { 1023 if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) { 1024 month = this.maxDate.month(); 1025 year = this.maxDate.year(); 1026 } 1027 } 1028 if (isLeft) { 1029 this.leftCalendar.month.month(month).year(year); 1030 if (this.linkedCalendars) this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month'); 1031 } else { 1032 this.rightCalendar.month.month(month).year(year); 1033 if (this.linkedCalendars) this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month'); 1034 } 1035 this.updateCalendars(); 1036 }, 1037 timeChanged: function(e) { 1038 var cal = $(e.target).closest('.calendar'), 1039 isLeft = cal.hasClass('left'); 1040 var hour = parseInt(cal.find('.hourselect').val(), 10); 1041 var minute = parseInt(cal.find('.minuteselect').val(), 10); 1042 var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0; 1043 if (!this.timePicker24Hour) { 1044 var ampm = cal.find('.ampmselect').val(); 1045 if (ampm === 'PM' && hour < 12) hour += 12; 1046 if (ampm === 'AM' && hour === 12) hour = 0; 1047 } 1048 if (isLeft) { 1049 var start = this.startDate.clone(); 1050 start.hour(hour); 1051 start.minute(minute); 1052 start.second(second); 1053 this.setStartDate(start); 1054 if (this.singleDatePicker) { 1055 this.endDate = this.startDate.clone(); 1056 } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) { 1057 this.setEndDate(start.clone()); 1058 } 1059 } else if (this.endDate) { 1060 var end = this.endDate.clone(); 1061 end.hour(hour); 1062 end.minute(minute); 1063 end.second(second); 1064 this.setEndDate(end); 1065 } 1066 //update the calendars so all clickable dates reflect the new time component 1067 this.updateCalendars(); 1068 //update the form inputs above the calendars with the new time 1069 this.updateFormInputs(); 1070 //re-render the time pickers because changing one selection can affect what's enabled in another 1071 this.renderTimePicker('left'); 1072 this.renderTimePicker('right'); 1073 }, 1074 formInputsChanged: function(e) { 1075 var isRight = $(e.target).closest('.calendar').hasClass('right'); 1076 var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format); 1077 var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format); 1078 if (start.isValid() && end.isValid()) { 1079 if (isRight && end.isBefore(start)) start = end.clone(); 1080 this.setStartDate(start); 1081 this.setEndDate(end); 1082 if (isRight) { 1083 this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format)); 1084 } else { 1085 this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format)); 1086 } 1087 } 1088 this.updateCalendars(); 1089 if (this.timePicker) { 1090 this.renderTimePicker('left'); 1091 this.renderTimePicker('right'); 1092 } 1093 }, 1094 elementChanged: function() { 1095 if (!this.element.is('input')) return; 1096 if (!this.element.val().length) return; 1097 if (this.element.val().length < this.locale.format.length) return; 1098 var dateString = this.element.val().split(this.locale.separator), 1099 start = null, 1100 end = null; 1101 if (dateString.length === 2) { 1102 start = moment(dateString[0], this.locale.format); 1103 end = moment(dateString[1], this.locale.format); 1104 } 1105 if (this.singleDatePicker || start === null || end === null) { 1106 start = moment(this.element.val(), this.locale.format); 1107 end = start; 1108 } 1109 if (!start.isValid() || !end.isValid()) return; 1110 this.setStartDate(start); 1111 this.setEndDate(end); 1112 this.updateView(); 1113 }, 1114 keydown: function(e) { 1115 //hide on tab or enter 1116 if ((e.keyCode === 9) || (e.keyCode === 13)) { 1117 this.hide(); 1118 } 1119 }, 1120 updateElement: function() { 1121 if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { 1122 this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); 1123 this.element.trigger('change'); 1124 } else if (this.element.is('input') && this.autoUpdateInput) { 1125 this.element.val(this.startDate.format(this.locale.format)); 1126 this.element.trigger('change'); 1127 } 1128 }, 1129 remove: function() { 1130 this.container.remove(); 1131 this.element.off('.daterangepicker'); 1132 this.element.removeData(); 1133 } 1134 }; 1135 $.fn.daterangepicker = function(options, callback) { 1136 this.each(function() { 1137 var el = $(this); 1138 if (el.data('daterangepicker')) el.data('daterangepicker').remove(); 1139 el.data('daterangepicker', new DateRangePicker(el, options, callback)); 1140 }); 1141 return this; 1142 }; 1143 return DateRangePicker; 1144 }));
调用方式没有任何改变,效果图:
不过存在一个问题,就是选择日期的时候点击农历日期无效,要点击公历日期(即数字)才能选中。