PageSourceSearch

https://ta.org.tw/assets/bootstrap-datepicker/js/bootstrap-datepicker_zh.js

js ta.org.tw collected 2026-10-02 10:06:03 UTC 13,714 bytes, 454 lines download raw bytes

1/* =========================================================
2 * bootstrap-datepicker.js 
3 * http://www.eyecon.ro/bootstrap-datepicker
4 * =========================================================
5 * Copyright 2012 Stefan Petre
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ========================================================= */
19 
20!function( $ ) {
21	
22	// Picker object
23	
24	var Datepicker = function(element, options){
25		this.element = $(element);
26		this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
27		this.picker = $(DPGlobal.template)
28							.appendTo('body')
29							.on({
30								click: $.proxy(this.click, this),
31								mousedown: $.proxy(this.mousedown, this)
32							});
33		this.isInput = this.element.is('input');
34		this.component = this.element.is('.date') ? this.element.find('.input-group-addon') : false;
35		
36		if (this.isInput) {
37			this.element.on({
38				focus: $.proxy(this.show, this),
39				blur: $.proxy(this.hide, this),
40				keyup: $.proxy(this.update, this)
41			});
42		} else {
43			if (this.component){
44				this.component.on('click', $.proxy(this.show, this));
45			} else {
46				this.element.on('click', $.proxy(this.show, this));
47			}
48		}
49		this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0;
50		if (typeof this.minViewMode === 'string') {
51			switch (this.minViewMode) {
52				case 'months':
53					this.minViewMode = 1;
54					break;
55				case 'years':
56					this.minViewMode = 2;
57					break;
58				default:
59					this.minViewMode = 0;
60					break;
61			}
62		}
63		this.viewMode = options.viewMode||this.element.data('date-viewmode')||0;
64		if (typeof this.viewMode === 'string') {
65			switch (this.viewMode) {
66				case 'months':
67					this.viewMode = 1;
68					break;
69				case 'years':
70					this.viewMode = 2;
71					break;
72				default:
73					this.viewMode = 0;
74					break;
75			}
76		}
77		this.startViewMode = this.viewMode;
78		this.weekStart = options.weekStart||this.element.data('date-weekstart')||0;
79		this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
80		this.fillDow();
81		this.fillMonths();
82		this.update();
83		this.showMode();
84	};
85	
86	Datepicker.prototype = {
87		constructor: Datepicker,
88		
89		show: function(e) {
90			this.picker.show();
91			this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
92			this.place();
93			$(window).on('resize', $.proxy(this.place, this));
94			if (e ) {
95				e.stopPropagation();
96				e.preventDefault();
97			}
98			if (!this.isInput) {
99				$(document).on('mousedown', $.proxy(this.hide, this));
100			}
101			this.element.trigger({
102				type: 'show',
103				date: this.date
104			});
105		},
106		
107		hide: function(){
108			this.picker.hide();
109			$(window).off('resize', this.place);
110			this.viewMode = this.startViewMode;
111			this.showMode();
112			if (!this.isInput) {
113				$(document).off('mousedown', this.hide);
114			}
115			//this.set();
116			this.element.trigger({
117				type: 'hide',
118				date: this.date
119			});
120		},
121		
122		set: function() {
123			var formated = DPGlobal.formatDate(this.date, this.format);
124			if (!this.isInput) {
125				if (this.component){
126					this.element.find('input').prop('value', formated);
127				}
128				this.element.data('date', formated);
129			} else {
130				this.element.prop('value', formated);
131			}
132		},
133		
134		setValue: function(newDate) {
135			if (typeof newDate === 'string') {
136				this.date = DPGlobal.parseDate(newDate, this.format);
137			} else {
138				this.date = new Date(newDate);
139			}
140			this.set();
141			this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
142			this.fill();
143		},
144		
145		place: function(){
146			var offset = this.component ? this.component.offset() : this.element.offset();
147			this.picker.css({
148				top: offset.top + this.height,
149				left: offset.left
150			});
151		},
152		
153		update: function(newDate){
154			this.date = DPGlobal.parseDate(
155				typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')),
156				this.format
157			);
158			this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
159			this.fill();
160		},
161		
162		fillDow: function(){
163			var dowCnt = this.weekStart;
164			var html = '<tr>';
165			while (dowCnt < this.weekStart + 7) {
166				html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>';
167			}
168			html += '</tr>';
169			this.picker.find('.datepicker-days thead').append(html);
170		},
171		
172		fillMonths: function(){
173			var html = '';
174			var i = 0
175			while (i < 12) {
176				html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>';
177			}
178			this.picker.find('.datepicker-months td').append(html);
179		},
180		
181		fill: function() {
182			var d = new Date(this.viewDate),
183				year = d.getFullYear(),
184				month = d.getMonth(),
185				currentDate = this.date.valueOf();
186			this.picker.find('.datepicker-days th:eq(1)')
187						.text(DPGlobal.dates.months[month]+' '+year);
188			var prevMonth = new Date(year, month-1, 28,0,0,0,0),
189				day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
190			prevMonth.setDate(day);
191			prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
192			var nextMonth = new Date(prevMonth);
193			nextMonth.setDate(nextMonth.getDate() + 42);
194			nextMonth = nextMonth.valueOf();
195			html = [];
196			var clsName;
197			while(prevMonth.valueOf() < nextMonth) {
198				if (prevMonth.getDay() === this.weekStart) {
199					html.push('<tr>');
200				}
201				clsName = '';
202				if (prevMonth.getMonth() < month) {
203					clsName += ' old';
204				} else if (prevMonth.getMonth() > month) {
205					clsName += ' new';
206				}
207				if (prevMonth.valueOf() === currentDate) {
208					clsName += ' active';
209				}
210				html.push('<td class="day'+clsName+'">'+prevMonth.getDate() + '</td>');
211				if (prevMonth.getDay() === this.weekEnd) {
212					html.push('</tr>');
213				}
214				prevMonth.setDate(prevMonth.getDate()+1);
215			}
216			this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
217			var currentYear = this.date.getFullYear();
218			
219			var months = this.picker.find('.datepicker-months')
220						.find('th:eq(1)')
221							.text(year)
222							.end()
223						.find('span').removeClass('active');
224			if (currentYear === year) {
225				months.eq(this.date.getMonth()).addClass('active');
226			}
227			
228			html = '';
229			year = parseInt(year/10, 10) * 10;
230			var yearCont = this.picker.find('.datepicker-years')
231								.find('th:eq(1)')
232									.text(year + '-' + (year + 9))
233									.end()
234								.find('td');
235			year -= 1;
236			for (var i = -1; i < 11; i++) {
237				html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>';
238				year += 1;
239			}
240			yearCont.html(html);
241		},
242		
243		click: function(e) {
244			e.stopPropagation();
245			e.preventDefault();
246			var target = $(e.target).closest('span, td, th');
247			if (target.length === 1) {
248				switch(target[0].nodeName.toLowerCase()) {
249					case 'th':
250						switch(target[0].className) {
251							case 'switch':
252								this.showMode(1);
253								break;
254							case 'prev':
255							case 'next':
256								this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call(
257									this.viewDate,
258									this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + 
259									DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1)
260								);
261								this.fill();
262								this.set();
263								break;
264						}
265						break;
266					case 'span':
267						if (target.is('.month')) {
268							var month = target.parent().find('span').index(target);
269							this.viewDate.setMonth(month);
270						} else {
271							var year = parseInt(target.text(), 10)||0;
272							this.viewDate.setFullYear(year);
273						}
274						if (this.viewMode !== 0) {
275							this.date = new Date(this.viewDate);
276							this.element.trigger({
277								type: 'changeDate',
278								date: this.date,
279								viewMode: DPGlobal.modes[this.viewMode].clsName
280							});
281						}
282						this.showMode(-1);
283						this.fill();
284						this.set();
285						break;
286					case 'td':
287						if (target.is('.day')){
288							var day = parseInt(target.text(), 10)||1;
289							var month = this.viewDate.getMonth();
290							if (target.is('.old')) {
291								month -= 1;
292							} else if (target.is('.new')) {
293								month += 1;
294							}
295							var year = this.viewDate.getFullYear();
296							this.date = new Date(year, month, day,0,0,0,0);
297							this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0);
298							this.fill();
299							this.set();
300							this.element.trigger({
301								type: 'changeDate',
302								date: this.date,
303								viewMode: DPGlobal.modes[this.viewMode].clsName
304							});
305						}
306						break;
307				}
308			}
309		},
310		
311		mousedown: function(e){
312			e.stopPropagation();
313			e.preventDefault();
314		},
315		
316		showMode: function(dir) {
317			if (dir) {
318				this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
319			}
320			this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
321		}
322	};
323	
324	$.fn.datepicker = function ( option, val ) {
325		return this.each(function () {
326			var $this = $(this),
327				data = $this.data('datepicker'),
328				options = typeof option === 'object' && option;
329			if (!data) {
330				$this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
331			}
332			if (typeof option === 'string') data[option](val);
333		});
334	};
335
336	$.fn.datepicker.defaults = {
337	};
338	$.fn.datepicker.Constructor = Datepicker;
339	
340	var DPGlobal = {
341		modes: [
342			{
343				clsName: 'days',
344				navFnc: 'Month',
345				navStep: 1
346			},
347			{
348				clsName: 'months',
349				navFnc: 'FullYear',
350				navStep: 1
351			},
352			{
353				clsName: 'years',
354				navFnc: 'FullYear',
355				navStep: 10
356		}],
357		dates:{
358			days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
359			daysShort: ["日", "一", "二", "三", "四", "五", "六", "日"],
360			daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
361			months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
362			monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]
363		},
364		isLeapYear: function (year) {
365			return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
366		},
367		getDaysInMonth: function (year, month) {
368			return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
369		},
370		parseFormat: function(format){
371			var separator = format.match(/[.\/\-\s].*?/),
372				parts = format.split(/\W+/);
373			if (!separator || !parts || parts.length === 0){
374				throw new Error("Invalid date format.");
375			}
376			return {separator: separator, parts: parts};
377		},
378		parseDate: function(date, format) {
379			var parts = date.split(format.separator),
380				date = new Date(),
381				val;
382			date.setHours(0);
383			date.setMinutes(0);
384			date.setSeconds(0);
385			date.setMilliseconds(0);
386			if (parts.length === format.parts.length) {
387				for (var i=0, cnt = format.parts.length; i < cnt; i++) {
388					val = parseInt(parts[i], 10)||1;
389					switch(format.parts[i]) {
390						case 'dd':
391						case 'd':
392							date.setDate(val);
393							break;
394						case 'mm':
395						case 'm':
396							date.setMonth(val - 1);
397							break;
398						case 'yy':
399							date.setFullYear(2000 + val);
400							break;
401						case 'yyyy':
402							date.setFullYear(val);
403							break;
404					}
405				}
406			}
407			return date;
408		},
409		formatDate: function(date, format){
410			var val = {
411				d: date.getDate(),
412				m: date.getMonth() + 1,
413				yy: date.getFullYear().toString().substring(2),
414				yyyy: date.getFullYear()
415			};
416			val.dd = (val.d < 10 ? '0' : '') + val.d;
417			val.mm = (val.m < 10 ? '0' : '') + val.m;
418			var date = [];
419			for (var i=0, cnt = format.parts.length; i < cnt; i++) {
420				date.push(val[format.parts[i]]);
421			}
422			return date.join(format.separator);
423		},
424		headTemplate: '<thead>'+
425							'<tr>'+
426								'<th class="prev">&lsaquo;</th>'+
427								'<th colspan="5" class="switch"></th>'+
428								'<th class="next">&rsaquo;</th>'+
429							'</tr>'+
430						'</thead>',
431		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
432	};
433	DPGlobal.template = '<div class="datepicker dropdown-menu">'+
434							'<div class="datepicker-days">'+
435								'<table class=" table-condensed">'+
436									DPGlobal.headTemplate+
437									'<tbody></tbody>'+
438								'</table>'+
439							'</div>'+
440							'<div class="datepicker-months">'+
441								'<table class="table-condensed">'+
442									DPGlobal.headTemplate+
443									DPGlobal.contTemplate+
444								'</table>'+
445							'</div>'+
446							'<div class="datepicker-years">'+
447								'<table class="table-condensed">'+
448									DPGlobal.headTemplate+
449									DPGlobal.contTemplate+
450								'</table>'+
451							'</div>'+
452						'</div>';
453
454}( window.jQuery )

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.