Timepicker: timepicker is closed when orientationchange event fired
[platform/framework/web/web-ui-fw.git] / src / js / widgets / jquery.mobile.tizen.datetimepicker.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Shows date and time, and make them able to be changed by user
3 //>>label: Datetime picker
4 //>>group: Tizen:Widgets
5
6 define( [ 'jquery.mobile.tizen.widgetex', 'jquery.mobile.tizen.popupwindow', 'jquery.mobile.tizen.popupwindow.ctxpopup' ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
8
9 /*global Globalize:false, range:false, regexp:false*/
10 /*
11  * jQuery Mobile Widget @VERSION
12  *
13  * This software is licensed under the MIT licence (as defined by the OSI at
14  * http://www.opensource.org/licenses/mit-license.php)
15  *
16  * ***************************************************************************
17  * Copyright (C) 2011 by Intel Corporation Ltd.
18  *
19  * Permission is hereby granted, free of charge, to any person obtaining a
20  * copy of this software and associated documentation files (the "Software"),
21  * to deal in the Software without restriction, including without limitation
22  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23  * and/or sell copies of the Software, and to permit persons to whom the
24  * Software is furnished to do so, subject to the following conditions:
25  *
26  * The above copyright notice and this permission notice shall be included in
27  * all copies or substantial portions of the Software.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35  * DEALINGS IN THE SOFTWARE.
36  * ***************************************************************************
37  *
38  * Authors: Salvatore Iovene <salvatore.iovene@intel.com>
39  *                      Daehyon Jung <darrenh.jung@samsung.com>
40  */
41
42 /**
43  * datetimepicker is a widget that lets the user select a date and/or a 
44  * time. If you'd prefer use as auto-initialization of form elements, 
45  * use input elements with type=date/time/datetime within form tag
46  * as same as other form elements.
47  * 
48  * HTML Attributes:
49  * 
50  *      data-role: 'datetimepicker'
51  *      data-format: date format string. e.g) "MMM dd yyyy, HH:mm"
52  *      type: 'date', 'datetime', 'time'
53  *      value: pre-set value. only accepts ISO date string. e.g) "2012-05-04", "2012-05-04T01:02:03+09:00" 
54  *      data-date: any date/time string "new Date()" accepts.
55  *
56  * Options:
57  *      type: 'date', 'datetime', 'time'
58  *      format: see data-format in HTML Attributes.
59  *      value: see value in HTML Attributes.
60  *      date: preset value as JavaScript Date Object representation.
61  *
62  * APIs:
63  *      value( datestring )
64  *              : Set date/time to 'datestring'.
65  *      value()
66  *              : Get current selected date/time as W3C DTF style string.
67  *      getValue() - replaced with 'value()'
68  *              : same as value()
69  *      setValue( datestring ) - replaced with 'value(datestring)'
70  *              : same as value( datestring )
71  *      changeTypeFormat( type, format ) - deprecated
72  *              : Change Type and Format options. use datetimepicker( "option", "format" ) instead
73  *
74  * Events:
75  *      date-changed: Raised when date/time was changed. Date-changed event will be deprecated
76  *
77  * Examples:
78  *      <ul data-role="listview">
79  *              <li class="ui-li-3-2-2">
80  *                      <span class="ui-li-text-main">
81  *                              <input type="datetime" name="demo-date" id="demo-date" 
82  *                                      data-format="MMM dd yyyy hh:mm tt"/>
83  *                      </span>
84  *                      <span class="ui-li-text-sub">
85  *                              Date/Time Picker - <span id="selected-date1"><em>(select a date first)</em></span>
86  *                      </span>
87  *              </li>
88  *              <li class="ui-li-3-2-2">
89  *                      <span class="ui-li-text-main">
90  *                              <input type="date" name="demo-date2" id="demo-date2"/>
91  *                      </span>
92  *                      <span class="ui-li-text-sub">
93  *                              Date Picker  - <span id="selected-date2"><em>(select a date first)</em></span>
94  *                      </span>
95  *              </li>
96  *              <li class="ui-li-3-2-2">
97  *                      <span class="ui-li-text-main">
98  *                              <input type="time" name="demo-date3" id="demo-date3"/>
99  *                      </span>
100  *                      <span class="ui-li-text-sub">
101  *                              Time Picker - <span id="selected-date3"><em>(select a date first)</em></span>
102  *                      </span>
103  *              </li>
104  *      </ul>
105  * How to get a return value:
106  * ==========================
107  * Bind to the 'date-changed' event, e.g.:
108  *    $("#myDatetimepicker").bind("change", function() {
109  *                      // your code
110  *    });
111  */
112
113 /**
114         @class DateTimePicker
115         The picker widgets show a control that you can use to enter date and time values. <br/> To add a date time picker widget to the application, use the following code:
116
117                         <li class="ui-li-dialogue ui-datetime">
118                                 <div class="ui-datetime-text-main">
119                                         <input type="datetime" data-format="MMM dd yyyy hh:mm:ss" name="demo-date" id="demo-date" />
120                                 </div>
121                                 <div class="ui-li-text-sub">Date/Time Picker
122                                         <span id="selected-date1"><em>(select a date first)</em></span>
123                                 </div>
124                         </li>
125 */
126
127
128 ( function ( $, window, undefined ) {
129         $.widget( "tizen.datetimepicker", $.tizen.widgetex, {
130
131                 options: {
132                         type: null, // date, time, datetime applicable
133                         format: null,
134                         date: null,
135                         initSelector: "input[type='date'], input[type='datetime'], input[type='time'], :jqmData(role='datetimepicker')"
136                 },
137
138                 container : null,
139
140                 _calendar: function () {
141                         return window.Globalize.culture().calendars.standard;
142                 },
143
144                 _value: {
145                         attr: "data-" + ( $.mobile.ns || "" ) + "date",
146                         signal: "date-changed"
147                 },
148
149                 _daysInMonth: [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ],
150
151                 _isLeapYear: function ( year ) {
152                         return year % 4 ? 0 : ( year % 100 ? 1 : ( year % 400 ? 0 : 1 ) );
153                 },
154
155                 _makeTwoDigits: function ( val ) {
156                         var ret = val.toString(10);
157                         if ( val < 10 ) {
158                                 ret = "0" + ret;
159                         }
160                         return ret;
161                 },
162
163                 _setType: function ( type ) {
164                         //datetime, date, time
165                         switch (type) {
166                         case 'datetime':
167                         case 'date':
168                         case 'time':
169                                 this.options.type = type;
170                                 break;
171                         default:
172                                 this.options.type = 'datetime';
173                                 break;
174                         }
175
176                         this.element.attr( "data-" + ( $.mobile.ns ? $.mobile.ns + "-" : "" ) + "type", this.options.type );
177                         return this.options.type;
178                 },
179
180                 _setFormat: function ( format ) {
181                         if ( this.options.format != format ) {
182                                 this.options.format = format;
183                         } else {
184                                 return;
185                         }
186
187                         this.ui.children().remove();
188
189                         var token = this._parsePattern( format ),
190                                 div = document.createElement('div'),
191                                 pat,
192                                 tpl,
193                                 period,
194                                 btn,
195                                 obj = this;
196
197                         while ( token.length > 0 ) {
198                                 pat = token.shift();
199                                 tpl = '<span class="ui-datefield-%1" data-pat="' + pat + '">%2</span>';
200                                 switch ( pat ) {
201                                 case 'H': //0 1 2 3 ... 21 22 23
202                                 case 'HH': //00 01 02 ... 21 22 23
203                                 case 'h': //0 1 2 3 ... 11 12
204                                 case 'hh': //00 01 02 ... 11 12
205                                         $(div).append( tpl.replace('%1', 'hour') );
206                                         break;
207                                 case 'mm': //00 01 ... 59
208                                 case 'm': //0 1 2 ... 59
209                                         if ( this.options.type == 'date' ) {
210                                                 $(div).append( tpl.replace('%1', 'month') );
211                                         } else {
212                                                 $(div).append( tpl.replace('%1', 'min') );
213                                         }
214                                         break;
215                                 case 'ss':
216                                 case 's':
217                                         $(div).append( tpl.replace('%1', 'sec') );
218                                         break;
219                                 case 'd': // day of month 5
220                                 case 'dd': // day of month(leading zero) 05
221                                         $(div).append( tpl.replace('%1', 'day') );
222                                         break;
223                                 case 'M': // Month of year 9
224                                 case 'MM': // Month of year(leading zero) 09
225                                 case 'MMM':
226                                 case 'MMMM':
227                                         $(div).append( tpl.replace('%1', 'month') );
228                                         break;
229                                 case 'yy':      // year two digit
230                                 case 'yyyy': // year four digit
231                                         $(div).append( tpl.replace('%1', 'year') );
232                                         break;
233                                 case 't': //AM / PM indicator(first letter) A, P
234                                         // add button
235                                 case 'tt': //AM / PM indicator AM/PM
236                                         // add button
237                                         btn = '<a href="#" class="ui-datefield-period"' +
238                                                 ' data-role="button" data-inline="true">period</a>';
239                                         $(div).append( btn );
240                                         break;
241                                 case 'g':
242                                 case 'gg':
243                                         $(div).append( tpl.replace('%1', 'era').replace('%2', this._calendar().eras.name) );
244                                         break;
245                                 case '\t':
246                                         $(div).append( tpl.replace('%1', 'tab').replace('%2', pat) );
247                                         break;
248                                 default : // string or any non-clickable object
249                                         $(div).append( tpl.replace('%1', 'seperator').replace('%2', pat) );
250                                         break;
251                                 }
252                         }
253
254                         this.ui.append( div );
255                         if ( this.options.date ) {
256                                 this._setDate( this.options.date );
257                         }
258
259                         this.ui.find('.ui-datefield-period').buttonMarkup().bind( 'vclick', function ( e ) {
260                                 obj._switchAmPm( obj );
261                         });
262
263                         this.element.attr( "data-" + ( $.mobile.ns ? $.mobile.ns + "-" : "" ) + "format", this.options.format );
264                         return this.options.format;
265                 },
266
267                 _setDate: function ( newdate ) {
268                         if ( typeof ( newdate ) == "string" ) {
269                                 newdate = new Date( newdate );
270                         }
271
272                         var fields = $('span,a', this.ui),
273                                 type,
274                                 fn,
275                                 $field,
276                                 btn,
277                                 i;
278
279                         function getMonth() {
280                                 return newdate.getMonth() + 1;
281                         }
282
283                         for ( i = 0; i < fields.length; i++ ) {
284                                 $field = $(fields[i]);
285                                 type = $field.attr("class").match(/ui-datefield-([\w]*)/);
286                                 if ( !type ) {
287                                         type = "";
288                                 }
289                                 switch ( type[1] ) {
290                                 case 'hour':
291                                         fn = newdate.getHours;
292                                         break;
293                                 case 'min':
294                                         fn = newdate.getMinutes;
295                                         break;
296                                 case 'sec':
297                                         fn = newdate.getSeconds;
298                                         break;
299                                 case 'year':
300                                         fn = newdate.getFullYear;
301                                         break;
302                                 case 'month':
303                                         fn = getMonth;
304                                         break;
305                                 case 'day':
306                                         fn = newdate.getDate;
307                                         break;
308                                 case 'period':
309                                         fn = newdate.getHours() < 12 ? this._calendar().AM[0] : this._calendar().PM[0];
310                                         btn = $field.find( '.ui-btn-text' );
311                                         if ( btn.length == 0 ) {
312                                                 $field.text(fn);
313                                         } else if ( btn.text() != fn ) {
314                                                 btn.text( fn );
315                                         }
316                                         fn = null;
317                                         break;
318                                 default:
319                                         fn = null;
320                                         break;
321                                 }
322                                 if ( fn ) {
323                                         this._updateField( $field, fn.call( newdate ) );
324                                 }
325                         }
326
327                         this.options.date = newdate;
328
329                         this._setValue( newdate );
330
331                         this.element.attr( "data-" + ( $.mobile.ns ? $.mobile.ns + "-" : "" ) + "date", this.options.date );
332                         return this.options.date;
333                 },
334
335                 destroy: function () {
336                         if ( this.ui ) {
337                                 this.ui.remove();
338                         }
339
340                         if ( this.element ) {
341                                 this.element.show();
342                         }
343                 },
344
345                 value: function ( val ) {
346                         function timeStr( t, obj ) {
347                                 return obj._makeTwoDigits( t.getHours() ) + ':' +
348                                         obj._makeTwoDigits( t.getMinutes() ) + ':' +
349                                         obj._makeTwoDigits( t.getSeconds() );
350                         }
351
352                         function dateStr( d, obj ) {
353                                 return ( ( d.getFullYear() % 10000 ) + 10000 ).toString().substr(1) + '-' +
354                                         obj._makeTwoDigits( d.getMonth() + 1 ) + '-' +
355                                         obj._makeTwoDigits( d.getDate() );
356                         }
357
358                         var rvalue = null;
359                         if ( val ) {
360                                 rvalue = this._setDate( val );
361                         } else {
362                                 switch ( this.options.type ) {
363                                 case 'time':
364                                         rvalue = timeStr( this.options.date, this );
365                                         break;
366                                 case 'date':
367                                         rvalue = dateStr( this.options.date, this );
368                                         break;
369                                 default:
370                                         rvalue = dateStr( this.options.date, this ) + 'T' + timeStr( this.options.date, this );
371                                         break;
372                                 }
373                         }
374                         return rvalue;
375                 },
376
377                 setValue: function ( newdate ) {
378                         console.warn( "setValue was deprecated. use datetimepicker('option', 'date', value) instead." );
379                         return this.value( newdate );
380                 },
381
382                 /**
383                  * return W3C DTF string
384                  */
385                 getValue: function () {
386                         console.warn("getValue() was deprecated. use datetimepicker('value') instead.");
387                         return this.value();
388                 },
389
390                 _updateField: function ( target, value ) {
391                         if ( !target || target.length == 0 ) {
392                                 return;
393                         }
394
395                         if ( value == 0 ) {
396                                 value = "0";
397                         }
398
399                         var pat = target.jqmData( 'pat' ),
400                                 hour,
401                                 text,
402                                 self = this;
403
404                         switch ( pat ) {
405                         case 'H':
406                         case 'HH':
407                         case 'h':
408                         case 'hh':
409                                 hour = value;
410                                 if ( pat.charAt(0) == 'h' ) {
411                                         if ( hour > 12 ) {
412                                                 hour -= 12;
413                                         } else if ( hour == 0 ) {
414                                                 hour = 12;
415                                         }
416                                 }
417                                 hour = this._makeTwoDigits( hour );
418                                 text = hour;
419                                 break;
420                         case 'm':
421                         case 'M':
422                         case 'd':
423                         case 's':
424                                 text = value;
425                                 break;
426                         case 'mm':
427                         case 'dd':
428                         case 'MM':
429                         case 'ss':
430                                 text = this._makeTwoDigits( value );
431                                 break;
432                         case 'MMM':
433                                 text = this._calendar().months.namesAbbr[ value - 1];
434                                 break;
435                         case 'MMMM':
436                                 text = this._calendar().months.names[ value - 1 ];
437                                 break;
438                         case 'yy':
439                                 text = this._makeTwoDigits( value % 100 );
440                                 break;
441                         case 'yyyy':
442                                 if ( value < 10 ) {
443                                         value = '000' + value;
444                                 } else if ( value < 100 ) {
445                                         value = '00' + value;
446                                 } else if ( value < 1000 ) {
447                                         value = '0' + value;
448                                 }
449                                 text = value;
450                                 break;
451                         }
452
453                         // to avoid reflow where its value isn't out-dated
454                         if ( target.text() != text ) {
455                                 if ( target.hasClass("ui-datefield-selected") ) {
456                                         target.addClass("out");
457                                         this._new_value = text;
458
459                                         target.animationComplete( function () {
460                                                 target.text( self._new_value);
461                                                 target.addClass("in")
462                                                         .removeClass("out");
463
464                                                 target.animationComplete( function () {
465                                                         target.removeClass("in").
466                                                                 removeClass("ui-datefield-selected");
467                                                 });
468                                         });
469                                 } else {
470                                         target.text( text );
471                                 }
472                         }
473                 },
474
475                 _switchAmPm: function ( obj ) {
476                         if ( this._calendar().AM != null ) {
477                                 var date = new Date( this.options.date ),
478                                         text,
479                                         change = 1000 * 60 * 60 * 12;
480                                 if ( date.getHours() > 11 ) {
481                                         change = -change;
482                                 }
483                                 date.setTime( date.getTime() + change );
484                                 this._setDate( date );
485                         }
486                 },
487
488                 _parsePattern: function ( pattern ) {
489                         var regex = /\/|\s|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|f|gg|g|\'[\w\W]*\'$|[\w\W]/g,
490                                 matches,
491                                 i;
492
493                         matches = pattern.match( regex );
494
495                         for ( i = 0; i < matches.length; i++ ) {
496                                 if ( matches[i].charAt(0) == "'" ) {
497                                         matches[i] = matches[i].substr( 1, matches[i].length - 2 );
498                                 }
499                         }
500
501                         return matches;
502                 },
503
504                 changeTypeFormat: function ( type, format ) {
505                         console.warn('changeTypeFormat() was deprecated. use datetimepicker("option", "type"|"format", value) instead');
506                         if ( type ) {
507                                 this._setType( type );
508                         }
509
510                         if ( format ) {
511                                 this._setFormat( format );
512                         }
513                 },
514
515                 _create: function () {
516                         var obj = this;
517
518                         if ( this.element.is( "input" ) ) {
519                                 ( function ( obj ) {
520                                         var type, value, format;
521
522                                         type = obj.element.get(0).getAttribute( "type" );
523                                         obj.options.type = type;
524
525                                         value = obj.element.get(0).getAttribute( "value" );
526                                         if ( value ) {
527                                                 obj.options.date = new Date( value );
528                                         }
529                                 }( this ) );
530                         }
531
532                         if ( !this.options.format ) {
533                                 switch ( this.options.type ) {
534                                 case 'datetime':
535                                         this.options.format = this._calendar().patterns.d + "\t" + this._calendar().patterns.t;
536                                         break;
537                                 case 'date':
538                                         this.options.format = this._calendar().patterns.d;
539                                         break;
540                                 case 'time':
541                                         this.options.format = this._calendar().patterns.t;
542                                         break;
543                                 }
544                         }
545
546                         if ( !this.options.date ) {
547                                 this.options.date = new Date();
548                         }
549
550                         this.element.hide();
551                         this.ui = $('<div class="ui-datefield"></div>');
552                         $(this.element).after( this.ui );
553
554                         this._popup_open = false;
555                         this.ui.bind('vclick', function ( e ) {
556                                 obj._showDataSelector( obj, this, e.target );
557                         });
558
559                         $.extend( this, {
560                                 _globalHandlers: [
561                                         {
562                                                 src: $( window ),
563                                                 handler: {
564                                                         orientationchange: $.proxy( this, "_orientationHandler" )
565                                                 }
566                                         }
567                                 ]
568                         });
569
570                         $.each( this._globalHandlers, function( idx, value ) {
571                                 value.src.bind( value.handler );
572                         });
573                 },
574                 _orientationHandler: function() {
575                         var self = this;
576                         if( self._popup_open ) {
577                                 self._popup_open = false;
578                                 self.container.popupwindow( 'close' );
579                         }
580                         return false;
581                 },
582                 _populateDataSelector: function ( field, pat ) {
583                         var values,
584                                 numItems,
585                                 current,
586                                 data,
587                                 range = window.range,
588                                 local,
589                                 yearlb,
590                                 yearhb,
591                                 day;
592
593                         switch ( field ) {
594                         case 'hour':
595                                 if ( pat == 'H' || pat == 'HH' ) {
596                                         // twentyfour
597                                         values = range( 0, 23 );
598                                         data = range( 0, 23 );
599                                         current = this.options.date.getHours();
600                                 } else {
601                                         values = range( 1, 12 );
602                                         current = this.options.date.getHours() - 1;//11
603                                         if ( current >= 11 ) {
604                                                 current = current - 12;
605                                                 data = range( 13, 23 );
606                                                 data.push( 12 ); // consider 12:00 am as 00:00
607                                         } else {
608                                                 data = range( 1, 11 );
609                                                 data.push( 0 );
610                                         }
611                                         if ( current < 0 ) {
612                                                 current = 11; // 12:00 or 00:00
613                                         }
614                                 }
615                                 if ( pat.length == 2 ) {
616                                         // two digit
617                                         values = values.map( this._makeTwoDigits );
618                                 }
619                                 numItems = values.length;
620                                 break;
621                         case 'min':
622                         case 'sec':
623                                 values = range( 0, 59 );
624                                 if ( pat.length == 2 ) {
625                                         values = values.map( this._makeTwoDigits );
626                                 }
627                                 data = range( 0, 59 );
628                                 current = ( field == 'min' ? this.options.date.getMinutes() : this.options.date.getSeconds() );
629                                 numItems = values.length;
630                                 break;
631                         case 'year':
632                                 yearlb = 1900;
633                                 yearhb = 2100;
634                                 data = range( yearlb, yearhb );
635                                 current = this.options.date.getFullYear() - yearlb;
636                                 values = range( yearlb, yearhb );
637                                 numItems = values.length;
638                                 break;
639                         case 'month':
640                                 switch ( pat.length ) {
641                                 case 1:
642                                         values = range( 1, 12 );
643                                         break;
644                                 case 2:
645                                         values = range( 1, 12 ).map( this._makeTwoDigits );
646                                         break;
647                                 case 3:
648                                         values = this._calendar().months.namesAbbr.slice();
649                                         break;
650                                 case 4:
651                                         values = this._calendar().months.names.slice();
652                                         break;
653                                 }
654                                 if ( values.length == 13 ) { // @TODO Lunar calendar support
655                                         if ( values[12] == "" ) { // to remove lunar calendar reserved space
656                                                 values.pop();
657                                         }
658                                 }
659                                 data = range( 1, values.length );
660                                 current = this.options.date.getMonth();
661                                 numItems = values.length;
662                                 break;
663                         case 'day':
664                                 day = this._daysInMonth[ this.options.date.getMonth() ];
665                                 if ( day == 28 ) {
666                                         day += this._isLeapYear( this.options.date.getFullYear() );
667                                 }
668                                 values = range( 1, day );
669                                 if ( pat.length == 2 ) {
670                                         values = values.map( this._makeTwoDigits );
671                                 }
672                                 data = range( 1, day );
673                                 current = this.options.date.getDate() - 1;
674                                 numItems = day;
675                                 break;
676                         }
677
678                         return {
679                                 values: values,
680                                 data: data,
681                                 numItems: numItems,
682                                 current: current
683                         };
684
685                 },
686
687                 _showDataSelector: function ( obj, ui, target ) {
688                         target = $(target);
689
690                         var attr = target.attr("class"),
691                                 field = attr ? attr.match(/ui-datefield-([\w]*)/) : undefined,
692                                 pat,
693                                 data,
694                                 values,
695                                 numItems,
696                                 current,
697                                 valuesData,
698                                 html,
699                                 datans,
700                                 $ul,
701                                 $div,
702                                 $ctx,
703                                 $li,
704                                 i,
705                                 newLeft = 10,
706                                 self = this;
707
708                         if ( !attr ) {
709                                 return;
710                         }
711                         if ( !field ) {
712                                 return;
713                         }
714                         if ( this._popup_open ) {
715                                 return;
716                         }
717
718                         target.not('.ui-datefield-seperator').addClass('ui-datefield-selected');
719
720                         pat = target.jqmData('pat');
721                         data = obj._populateDataSelector.call( obj, field[1], pat );
722
723                         values = data.values;
724                         numItems = data.numItems;
725                         current = data.current;
726                         valuesData = data.data;
727
728                         if ( values ) {
729                                 datans = "data-" + ($.mobile.ns ? ($.mobile.ns + '-') : "") + 'val="';
730                                 for ( i = 0; i < values.length; i++ ) {
731                                         html += '<li><a class="ui-link" ' + datans + valuesData[i] + '">' + values[i] + '</a></li>';
732                                 }
733
734                                 $ul = $("<ul></ul>");
735                                 $div = $('<div class="ui-datetimepicker-selector" data-transition="fade" data-fade="false"></div>');
736                                 $div.append( $ul ).appendTo( ui );
737                                 $ctx = $div.ctxpopup();
738                                 $ctx.parents('.ui-popupwindow').addClass('ui-datetimepicker');
739                                 $li = $(html);
740                                 $( $li[current] ).addClass("current");
741                                 $div.jqmData( "list", $li );
742                                 $div.circularview();
743                                 if( !obj._reflow ) {
744                                         obj._reflow = function() {
745                                                 $div.circularview( "reflow" );
746                                                 $div.circularview( 'centerTo', '.current', 0 );
747                                         }
748                                         $(window).bind( "resize" , obj._reflow );
749                                 }
750                                 // cause ctxpopup forced to subtract 10
751                                 if ( $( window ).width() / 2 < target.offset().left ) {
752                                         newLeft = -10;
753                                 }
754                                 $ctx.popupwindow( 'open',
755                                                 target.offset().left + ( target.width() / 2 ) + newLeft - window.pageXOffset ,
756                                                 target.offset().top + target.height() - window.pageYOffset );
757
758                                 this.container = $ctx;
759                                 this._popup_open = true;
760
761                                 $div.bind('popupafterclose', function ( e ) {
762                                         if ( obj._reflow ) {
763                                                 $(window).unbind("resize", obj._reflow);
764                                                 obj._reflow = null;
765                                         }
766
767                                         if ( !( target.hasClass("in") || target.hasClass("out") ) ) {
768                                                 target.removeClass("ui-datefield-selected");
769                                         }
770
771                                         $div.unbind( 'popupafterclose' );
772                                         $ul.unbind( 'vclick' );
773                                         $(obj).unbind( 'update' );
774                                         $ctx.popupwindow( 'destroy' );
775                                         $div.remove();
776
777                                         self._popup_open = false;
778                                 });
779
780                                 $(obj).bind( 'update', function ( e, val ) {
781                                         var date = new Date( this.options.date ),
782                                                 month,
783                                                 date_calibration = function () {
784                                                         date.setDate( 1 );
785                                                         date.setDate( date.getDate() - 1 );
786                                                 };
787
788                                         switch ( field[1] ) {
789                                         case 'min':
790                                                 date.setMinutes( val );
791                                                 break;
792                                         case 'hour':
793                                                 date.setHours( val );
794                                                 break;
795                                         case 'sec':
796                                                 date.setSeconds( val );
797                                                 break;
798                                         case 'year':
799                                                 month = date.getMonth();
800                                                 date.setFullYear( val );
801
802                                                 if ( date.getMonth() != month ) {
803                                                         date_calibration();
804                                                 }
805                                                 break;
806                                         case 'month':
807                                                 date.setMonth( val - 1 );
808
809                                                 if ( date.getMonth() == val ) {
810                                                         date_calibration();
811                                                 }
812                                                 break;
813                                         case 'day':
814                                                 date.setDate( val );
815                                                 break;
816                                         }
817
818                                         obj._setDate( date );
819
820                                         $ctx.popupwindow( 'close' );
821                                 });
822
823                                 $ul.bind( 'click', function ( e ) {
824                                         if ( $(e.target).is('a') ) {
825                                                 $ul.find(".current").removeClass("current");
826                                                 $(e.target).parent().addClass('current');
827                                                 var val = $(e.target).jqmData("val");
828                                                 $(obj).trigger( 'update', val ); // close popup, unselect field
829                                         }
830                                 });
831
832                                 $div.circularview( 'centerTo', '.current', 500 );
833                                 $div.bind( 'scrollend' , function ( e ) {
834                                         if ( !obj._reflow ) {
835                                                 obj._reflow = function () {
836                                                         $div.circularview("reflow");
837                                                 };
838                                                 $(window).bind("resize", obj._reflow);
839                                         }
840                                 });
841                         }
842                         return ui;
843                 }
844
845         });
846
847         $(document).bind("pagecreate create", function ( e ) {
848                 $($.tizen.datetimepicker.prototype.options.initSelector, e.target)
849                         .not(":jqmData(role='none'), :jqmData(role='nojs')")
850                         .datetimepicker();
851         });
852
853 } ( jQuery, this ) );
854
855 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
856 } );
857 //>>excludeEnd("jqmBuildExclude");