wuyuntao / timepicker

Yet another jQuery timepicker plugin

wuyuntao (author)
Mon Aug 18 20:20:10 -0700 2008
commit  9d9fb41a28c2872b37cbd0b634b783874dfa6a54
tree    c6a9107e1edd383e1ba358fb1ac16062f5aa0ca6
parent  bacba2bd3ae6fb90c8c3a7854c5b4d54a2ad9f2c
timepicker / timepicker.js
100644 346 lines (309 sloc) 12.391 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/*
* Yet Another jQuery Timepicker Plugin
* version 0.2
*
* Copyright (c) 2008 Wu Yuntao <http://luliban.com/blog/>
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* http://plugins.jquery.com/project/yatimepicker
*
*/
 
(function($) {
 
var PROP_NAME = 'timepicker';
 
/* Scoreboard plugin.
* Used as a single hour, minute and second picker in Timepicker
*/
$.fn.scoreboard = function(options) {
    if (!this.length) return this;
 
    var debug = false,
        increaseInterval = null,
        decreaseInterval = null,
        _frequency = 200,
        _mainWrapClass = 'scoreboard',
        _increaseButtonClass = 'increase-button',
        _decreaseButtonClass = 'decrease-button',
        _scoreWrapClass = 'score';
 
    options = $.extend({
        /* minimum value of score */
        min: 0,
        /* maximum value of score */
        max: 20,
        /* initial value of score */
        init: 10,
        /* if ``loop`` is true, value turns to its maxium when reaching its minimum,
* and vice versa */
        loop: true,
        /* digit of score */
        digit: 2
    }, options || {});
    /* Verify options */
    if (options.min >= options.max) throw new Error("``max`` cannot less than ``min``");
    if (options.init < options.min || options.init > options.max)
        throw new Error("``init`` cannot less than ``min`` or great than ``max``");
    var score = options.init;
 
    /* HTML Template */
    var _html = '<div class="' + _mainWrapClass + '"><div class="' + _increaseButtonClass
              + '"><span></span></div><div class="' + _scoreWrapClass + '"><span>'
              + padLeft(score) + '</span></div><div class="' + _decreaseButtonClass
              + '"><span></span></div></div>';
    this.html(_html);
    var _increaseButton = this.find('div.' + _increaseButtonClass + ' span');
    var _decreaseButton = this.find('div.' + _decreaseButtonClass + ' span');
    var _scoreWrap = this.find('div.' + _scoreWrapClass + ' span');
 
    /* When increase-button clicked, score increases. When button is continuously pressed,
* score increases every 0.2 second. The same as decrease-button.
*/
    _increaseButton.click(function(e) {
        increase();
    }).mousedown(function(e) {
        if (!isRightClick(e)) increaseInterval = window.setInterval(increase, _frequency);
    }).mouseup(function(e) {
        if (!isRightClick(e)) window.clearInterval(increaseInterval);
    }).mouseout(function(e) {
        if (!isRightClick(e)) window.clearInterval(increaseInterval);
    });
 
    _decreaseButton.click(function(e) {
        decrease();
    }).mousedown(function(e) {
        if (!isRightClick(e)) decreaseInterval = window.setInterval(decrease, _frequency);
    }).mouseup(function(e) {
        if (!isRightClick(e)) window.clearInterval(decreaseInterval);
    }).mouseout(function(e) {
        if (!isRightClick(e)) window.clearInterval(decreaseInterval);
    });
 
    function isRightClick(e) {
        var rightclick;
if (!e) var e = window.event;
if (e.which) rightclick = (e.which == 3);
else if (e.button) rightclick = (e.button == 2);
        return rightclick;
    }
 
    function getScore() {
        return parseInt(_scoreWrap.html(), 10);
    }
 
    function increase() {
        score = getScore();
        score == options.max ? score = (options.loop ? options.min : score) : ++score;
        _scoreWrap.html(padLeft(score));
        return score;
    }
 
    function decrease() {
        score = getScore();
        score == options.min ? score = (options.loop ? options.max : score) : --score;
        _scoreWrap.html(padLeft(score));
        return score;
    }
 
    function padLeft(val) {
        if (val.toString().length >= options.digit) return String(val);
        return padLeft("0" + val);
    }
 
};
 
/* Timepicker plugin
* Use timeboard to pick up any time.
*/
$.fn.timepicker = function(options) {
    if (!this.length) return this;
 
    var debug = false,
        _input = this,
        _timepicker = null,
        _timepickerPosition = null,
        _hourpicker = null,
        _minutepicker = null,
        _secondpicker = null,
        _hourScore = null,
        _minuteScore = null,
        _secondScore = null,
        _timepickerShowing = false,
        _mainClass = 'timepicker',
        _inputClass = 'timepicker-input',
        _mainWrap = 'time-picker-wrap',
        _timeboardWrapClass = 'time-board-wrap',
        _hourWrapClass = 'hour-picker-wrap',
        _minuteWrapClass = 'minute-picker-wrap',
        _secondWrapClass = 'second-picker-wrap',
        _suggestWrapClass = 'suggest-picker-wrap',
        _timeSuggestWrapClass = 'time-suggest-wrap',
        _buttonWrapClass = 'button-wrap',
        _clearWrapClass = 'clear-wrap',
_clearText = 'Clear', // Display text for clear link
        _closeWrapClass = 'close-wrap',
_closeText = 'Close', // Display text for close link
        _suggestTimeNames = {
            'Now': null, // Calculate when needed
            '6 a.m.': [6, 0, 0],
            'Noon': [12, 0, 0],
            '8 p.m.': [20, 0, 0],
            'Midnight': [0, 0, 0]
        };
 
    var _html = '<div id="' + _mainWrap + '" class="' + _mainClass
              + '" style="display:none;"><table><tbody><tr class="'
              + _timeboardWrapClass + '"><td class="' + _hourWrapClass
              + '"></td><td>:</td><td class="' + _minuteWrapClass
              + '"></td><td>:</td><td class="' + _secondWrapClass
              + '"></td></tr><tr class="' + _timeSuggestWrapClass
              + '"><td class="grey" colspan="5">Now</td></tr><tr class="' + _timeSuggestWrapClass
              + '"><td colspan="5">6 a.m.</td></tr><tr class="' + _timeSuggestWrapClass
              + '"><td class="grey" colspan="5">Noon</td></tr><tr class="' + _timeSuggestWrapClass
              + '"><td colspan="5">8 p.m.</td></tr><tr class="' + _timeSuggestWrapClass
              + '"><td class="grey" colspan="5">Midnight</td></tr><tr class="' + _buttonWrapClass
              + '"><td class="' + _clearWrapClass + '" colspan="2"><span>' + _clearText
              + '</span></td><td></td><td class="' + _closeWrapClass
              + '" colspan="2"><span>' + _closeText
              + '</span></td></tr></tbody></table></div>';
 
    /* Default options
*/
    options = $.extend({
        showAnim: 'show', // name of jQuery animation for popup
        duration: 'normal', // Duration of display/closure
        defaultTime: '00:00:00' // Used when field is blank: 00:00:00
    }, options || {});
 
    // Convert date object into time string
    if (typeof options.defaultTime == 'object')
        options.defaultTime = options.defaultTime.toTimeString().split(' ')[0];
    this.focus(showTimepicker).click(showTimepicker).keydown(doKeyDown);
    $(document.body).mousedown(checkExternalClick);
 
    function initialTimepicker() {
        _input.after(_html);
        _input.addClass(_inputClass);
        _timepicker = $('#' + _mainWrap);
        _hourpicker = _timepicker.find('td.' + _hourWrapClass),
        _minutepicker = _timepicker.find('td.' + _minuteWrapClass),
        _secondpicker = _timepicker.find('td.' + _secondWrapClass);
        _hourpicker.scoreboard({ 'min': 0, 'max': 23, 'init': 0, 'digit': 2 });
        _minutepicker.scoreboard({ 'min': 0, 'max': 59, 'init': 0, 'digit': 2 });
        _secondpicker.scoreboard({ 'min': 0, 'max': 59, 'init': 0, 'digit': 2 });
        _hourScore = _hourpicker.find('.score span');
        _minuteScore = _minutepicker.find('.score span');
        _secondScore = _secondpicker.find('.score span');
 
        _timepicker.find('td.' + _clearWrapClass).click(doClear);
        _timepicker.find('td.' + _closeWrapClass).click(doClose);
        _timepicker.find('tr.' + _timeSuggestWrapClass + ' td').click(doTimeSuggest);
 
        if (options.defaultTime) {
            var time = options.defaultTime.split(':');
            setTime(time[0], time[1], time[2]);
        }
    }
 
    function showTimepicker() {
        if (_timepicker == null) initialTimepicker();
        if (!_timepickerShowing) {
            var current = _input.val();
            if (current.match(/^[0-9]{1,2}:[0-9]{1,2}(:[0-9]{1,2})?$/)) {
                current = current.split(':');
                setTime(current[0], current[1], current[2]);
            }
            setPosition(this);
            switch (options.showAnim) {
                case 'show': _timepicker.show(options.duration);
                             break;
                case 'fade': _timepicker.fadeIn(options.duration);
                             break;
                case 'slide': _timepicker.slideDown(options.duration);
                              break;
            }
            _timepickerShowing = true;
            return;
        }
    }
 
    function hideTimepicker() {
        if (_timepickerShowing) {
            switch (options.showAnim) {
                case 'show': _timepicker.hide(options.duration);
                             break;
                case 'fade': _timepicker.fadeOut(options.duration);
                             break;
                case 'slide': _timepicker.slideUp(options.duration);
                              break;
            }
            _timepickerShowing = false;
            return;
        }
    }
 
    function toggleTimepicker() {
        if (_timepickerShowing) hideTimepicker();
        else showTimepicker();
    }
 
    // Set position of timepicker
    function setPosition(input) {
        var _inputPosition = $(input).offset();
        _timepickerPosition = [_inputPosition.left, _inputPosition.top + input.offsetHeight];
        if ($.browser.opera) { // correction for Opera when scrolled
_timepickerPosition[0] -= document.documentElement.scrollLeft;
_timepickerPosition[1] -= document.documentElement.scrollTop;
        }
        _timepicker.css({ 'left': _timepickerPosition[0] + 'px',
                          'top': _timepickerPosition[1] + 'px' });
    }
 
    function doKeyDown(e) {
        var handled = true;
        if (_timepickerShowing) {
            switch (e.keyCode) {
                // Tab key
                case 9: getTime();
                        hideTimepicker();
                        break;
                // ESC key
                case 27: hideTimepicker();
                         break;
            }
        } else {
            handled = false;
        }
if (handled) {
e.preventDefault();
e.stopPropagation();
}
    }
 
    function doTimeSuggest(e) {
        var suggest = $(this).html();
        if (suggest == 'Now') {
            // If suggests "Now", calculate time immediately
            var now = new Date();
            _suggestTimeNames[suggest] = [now.getHours(), now.getMinutes(), now.getSeconds()];
        }
        var time = _suggestTimeNames[suggest];
        setTime(time[0], time[1], time[2]);
        return time;
    }
 
    function doClear() {
        // Clear time in the ``_input``
        _input.val("");
        hideTimepicker();
        return;
    }
 
    function doClose() {
        // Get time on board and insert the time into ``_input``
        getTime();
        hideTimepicker();
        return;
    }
 
    function getTime() {
        // Get time on board
        var time = _hourScore.html() + ':' + _minuteScore.html() + ':' + _secondScore.html();
        _input.val(time);
        return time;
    }
 
    function setTime(hour, minute, second) {
        // Set time on board
        if (typeof hour == 'undefined') hour = 0;
        if (typeof minute == 'undefined') minute = 0;
        if (typeof second == 'undefined') second = 0;
        _hourScore.html(padLeft(hour));
        _minuteScore.html(padLeft(minute));
        _secondScore.html(padLeft(second));
        return getTime();
    }
 
    function padLeft(val) {
        if (val.toString().length >= 2) return String(val);
        return padLeft("0" + val);
    }
 
    function checkExternalClick(e) {
        if (!_timepickerShowing) return;
        var target = $(e.target);
        if ((target.parents('#' + _mainWrap).length == 0) &&
            !target.hasClass(_inputClass) &&
            !target.hasClass(_mainClass))
            hideTimepicker();
    }
 
};
 
})(jQuery);