PluginProbe
weForms – Easy Drag & Drop Contact Form Builder For WordPress / 1.6.20
weForms – Easy Drag & Drop Contact Form Builder For WordPress v1.6.20
1.6.7 1.6.8 1.6.9 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.18 1.6.19 1.6.2 1.6.20 1.6.21 1.6.22 1.6.23 1.6.24 1.6.25 1.6.26 1.6.27 1.6.28 1.6.3 1.6.4 1.6.5 1.6.6 All 74 releases
weforms / assets / js / weforms.js

weforms.js in weForms – Easy Drag & Drop Contact Form Builder For WordPress 1.6.20, at assets/js/weforms.js

4,880 lines 167.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* assets/wpuf/js/frontend-form.js */
2 ;(function($, window) {
3
4 $.fn.listautowidth = function() {
5 return this.each(function() {
6 var w = $(this).width();
7 var liw = w / $(this).children('li').length;
8 $(this).children('li').each(function(){
9 var s = $(this).outerWidth(true)-$(this).width();
10 $(this).width(liw-s);
11 });
12 });
13 };
14 $.fn.extend({
15 /**
16 * Custom jQuery serialize wrapper.
17 *
18 * When WordPress 5.6 increased the jQuery version to 3.5.1, the serialize function changed. Instead of
19 * sending spaces as "+", they are sent as "%20". This wrapper is for backwards compatibility.
20 *
21 * @todo This function is duplicated in both the frontend and backend. Need to have the code live in
22 * just one location.
23 *
24 * @since 1.6.7
25 */
26 weSerialize: function() {
27 return $( this ).serialize().replaceAll( '%20', '+' );
28 },
29 });
30 window.WP_User_Frontend = {
31
32 init: function() {
33
34 //enable multistep
35 this.enableMultistep(this);
36
37 // clone and remove repeated field
38 $('.wpuf-form').on('click', 'img.wpuf-clone-field', this.cloneField);
39 $('.wpuf-form').on('click', 'img.wpuf-remove-field', this.removeField);
40 $('.wpuf-form').on('click', 'a.wpuf-delete-avatar', this.deleteAvatar);
41 $('.wpuf-form').on('click', 'a#wpuf-post-draft', this.draftPost);
42 $('.wpuf-form').on('click', 'button#wpuf-account-update-profile', this.account_update_profile);
43
44 $('.wpuf-form-add').on('submit', this.formSubmit);
45 $('form#post').on('submit', this.adminPostSubmit);
46 // $( '.wpuf-form').on('keyup', '#pass1', this.check_pass_strength );
47
48 // refresh pluploads on each step change (multistep form)
49 $('.wpuf-form').on('step-change-fieldset', function(event, number, step) {
50 if ( wpuf_plupload_items.length ) {
51 for (var i = wpuf_plupload_items.length - 1; i >= 0; i--) {
52 wpuf_plupload_items[i].refresh();
53 }
54 }
55 if ( wpuf_map_items.length ) {
56 for (var i = wpuf_map_items.length - 1; i >= 0; i--) {
57 google.maps.event.trigger(wpuf_map_items[i].map, 'resize');
58 wpuf_map_items[i].map.setCenter(wpuf_map_items[i].center);
59 }
60 }
61 });
62
63 this.ajaxCategory();
64 // image insert
65 // this.insertImage();
66
67 //comfirmation alert for canceling subscription
68 $( ':submit[name="wpuf_user_subscription_cancel"]').click(function(e){
69 e.preventDefault();
70
71 swal({
72 text: wpuf_frontend.cancelSubMsg,
73 type: 'warning',
74 showCancelButton: true,
75 confirmButtonColor: '#d54e21',
76 confirmButtonText: wpuf_frontend.delete_it,
77 cancelButtonText: wpuf_frontend.cancel_it,
78 confirmButtonClass: 'btn btn-success',
79 cancelButtonClass: 'btn btn-danger',
80 }).then(function ( isConfirmed ) {
81 if ( !isConfirmed ) {
82 return false;
83 }
84 $('#wpuf_cancel_subscription').submit();
85 });
86 });
87 },
88
89 check_pass_strength : function() {
90 var pass1 = $('#pass1').val(), strength;
91
92 $('#pass-strength-result').show();
93
94 $('#pass-strength-result').removeClass('short bad good strong');
95 if ( ! pass1 ) {
96 $('#pass-strength-result').html( ' ' );
97 $('#pass-strength-result').hide();
98 return;
99 }
100
101 if ( typeof wp.passwordStrength != 'undefined' ) {
102
103 strength = wp.passwordStrength.meter( pass1, wp.passwordStrength.userInputBlacklist(), pass1 );
104
105 switch ( strength ) {
106 case 2:
107 $('#pass-strength-result').addClass('bad').html( pwsL10n.bad );
108 break;
109 case 3:
110 $('#pass-strength-result').addClass('good').html( pwsL10n.good );
111 break;
112 case 4:
113 $('#pass-strength-result').addClass('strong').html( pwsL10n.strong );
114 break;
115 case 5:
116 $('#pass-strength-result').addClass('short').html( pwsL10n.mismatch );
117 break;
118 default:
119 $('#pass-strength-result').addClass('short').html( pwsL10n['short'] );
120 }
121
122 }
123 },
124
125 enableMultistep: function(o) {
126
127 var js_obj = this;
128 var step_number = 0;
129 var progressbar_type = $(':hidden[name="wpuf_multistep_type"]').val();
130
131 if ( progressbar_type == null ) {
132 return;
133 }
134
135 // first fieldset doesn't have prev button,
136 // last fieldset doesn't have next button
137 $('fieldset.wpuf-multistep-fieldset').find('.wpuf-multistep-prev-btn').first().remove();
138 $('fieldset.wpuf-multistep-fieldset').find('.wpuf-multistep-next-btn').last().remove();
139
140 // at first first fieldset will be shown, and others will be hidden
141 $('.wpuf-form fieldset').removeClass('field-active').first().addClass('field-active');
142
143 if ( progressbar_type == 'progressive' && $('.wpuf-form .wpuf-multistep-fieldset').length != 0 ) {
144
145 var firstLegend = $('fieldset.wpuf-multistep-fieldset legend').first();
146 $('.wpuf-multistep-progressbar').html('<div class="wpuf-progress-percentage"></div>' );
147
148 var progressbar = $( ".wpuf-multistep-progressbar" ),
149 progressLabel = $( ".wpuf-progress-percentage" );
150
151 $( ".wpuf-multistep-progressbar" ).progressbar({
152 change: function() {
153 progressLabel.text( progressbar.progressbar( "value" ) + "%" );
154 }
155 });
156
157 $('.wpuf-multistep-fieldset legend').hide();
158
159 } else {
160 $('.wpuf-form').each(function() {
161 var this_obj = $(this);
162 var progressbar = $('.wpuf-multistep-progressbar', this_obj);
163 var nav = '';
164
165 progressbar.addClass('wizard-steps');
166 nav += '<ul class="wpuf-step-wizard">';
167
168 $('.wpuf-multistep-fieldset', this).each(function(){
169 nav += '<li>' + $.trim( $('legend', this).text() ) + '</li>';
170 $('legend', this).hide();
171 });
172
173 nav += '</ul>';
174 progressbar.append( nav );
175
176 $('.wpuf-step-wizard li', progressbar).first().addClass('active-step');
177 $('.wpuf-step-wizard', progressbar).listautowidth();
178 });
179 }
180
181 this.change_fieldset(step_number, progressbar_type);
182
183 $('fieldset .wpuf-multistep-prev-btn, fieldset .wpuf-multistep-next-btn').click(function(e) {
184 // js_obj.formSubmit();
185 if ( $(this).hasClass('wpuf-multistep-next-btn') ) {
186 var result = js_obj.formStepCheck( '', $(this).closest('fieldset') );
187
188 if ( result != false ) {
189 o.change_fieldset(++step_number,progressbar_type);
190 }
191
192 } else if ( $(this).hasClass('wpuf-multistep-prev-btn') ) {
193 o.change_fieldset( --step_number,progressbar_type );
194 }
195
196 var formDiv = $( "form.wpuf-form-add" );
197 var position = formDiv.offset().top;
198
199 // this changes the scrolling behavior to "smooth"
200 window.scrollTo({
201 top: position - 32,
202 behavior: "smooth"
203 });
204
205 return false;
206 });
207 },
208
209 change_fieldset: function(step_number, progressbar_type) {
210 var current_step = $('fieldset.wpuf-multistep-fieldset').eq(step_number);
211
212 $('fieldset.wpuf-multistep-fieldset').removeClass('field-active').eq(step_number).addClass('field-active');
213
214 $('.wpuf-step-wizard li').each(function(){
215 if ( $(this).index() <= step_number ){
216 progressbar_type == 'step_by_step'? $(this).addClass('passed-wpuf-ms-bar') : $('.wpuf-ps-bar',this).addClass('passed-wpuf-ms-bar');
217 } else {
218 progressbar_type == 'step_by_step'? $(this).removeClass('passed-wpuf-ms-bar') : $('.wpuf-ps-bar',this).removeClass('passed-wpuf-ms-bar');
219 }
220 });
221
222 $('.wpuf-step-wizard li').removeClass('wpuf-ms-bar-active active-step completed-step');
223 $('.passed-wpuf-ms-bar').addClass('completed-step').last().addClass('wpuf-ms-bar-active');
224 $('.wpuf-ms-bar-active').addClass('active-step');
225
226 var legend = $('fieldset.wpuf-multistep-fieldset').eq(step_number).find('legend').text();
227 legend = $.trim( legend );
228
229 if ( progressbar_type == 'progressive' && $('.wpuf-form .wpuf-multistep-fieldset').length != 0 ) {
230 var progress_percent = ( step_number + 1 ) * 100 / $('fieldset.wpuf-multistep-fieldset').length ;
231 var progress_percent = Number( progress_percent.toFixed(2) );
232 $( ".wpuf-multistep-progressbar" ).progressbar({value: progress_percent });
233 $( '.wpuf-progress-percentage' ).text( legend + ' (' + progress_percent + '%)');
234 }
235
236 // trigger a change event
237 $('.wpuf-form').trigger('step-change-fieldset', [ step_number, current_step ]);
238 },
239
240 ajaxCategory: function () {
241
242 var el = '.cat-ajax',
243 wrap = '.category-wrap';
244
245 $(wrap).on('change', el, function(){
246 currentLevel = parseInt( $(this).parent().attr('level') );
247 WP_User_Frontend.getChildCats( $(this), 'lvl', currentLevel+1, wrap, 'category');
248 });
249 },
250
251 getChildCats: function (dropdown, result_div, level, wrap_div, taxonomy) {
252
253 cat = $(dropdown).val();
254 results_div = result_div + level;
255 taxonomy = typeof taxonomy !== 'undefined' ? taxonomy : 'category';
256 field_attr = $(dropdown).siblings('span').data('taxonomy');
257
258 $.ajax({
259 type: 'post',
260 url: wpuf_frontend.ajaxurl,
261 data: {
262 action: 'wpuf_get_child_cat',
263 catID: cat,
264 nonce: wpuf_frontend.nonce,
265 field_attr: field_attr
266 },
267 beforeSend: function() {
268 $(dropdown).parent().parent().next('.loading').addClass('wpuf-loading');
269 },
270 complete: function() {
271 $(dropdown).parent().parent().next('.loading').removeClass('wpuf-loading');
272 },
273 success: function(html) {
274 //console.log( html ); return;
275 $(dropdown).parent().nextAll().each(function(){
276 $(this).remove();
277 });
278
279 if(html != "") {
280 $(dropdown).parent().addClass('hasChild').parent().append('<div id="'+result_div+level+'" level="'+level+'"></div>');
281 dropdown.parent().parent().find('#'+results_div).html(html).slideDown('fast');
282 }
283 }
284 });
285 },
286
287 cloneField: function(e) {
288 e.preventDefault();
289
290 var $div = $(this).closest('tr');
291 var $clone = $div.clone();
292 // console.log($clone);
293
294 //clear the inputs
295 $clone.find('input').val('');
296 $clone.find(':checked').attr('checked', '');
297 $div.after($clone);
298 },
299
300 removeField: function() {
301 //check if it's the only item
302 var $parent = $(this).closest('tr');
303 var items = $parent.siblings().andSelf().length;
304
305 if( items > 1 ) {
306 $parent.remove();
307 }
308 },
309
310 adminPostSubmit: function(e) {
311 e.preventDefault();
312
313 var form = $(this),
314 form_data = WP_User_Frontend.validateForm(form);
315
316 if (form_data) {
317 return true;
318 }
319 },
320
321 draftPost: function (e) {
322 e.preventDefault();
323
324 var self = $(this),
325 form = $(this).closest('form'),
326 form_data = form.weSerialize() + '&action=wpuf_draft_post',
327 post_id = form.find('input[type="hidden"][name="post_id"]').val();
328
329 var rich_texts = [],
330 val;
331
332 // grab rich texts from tinyMCE
333 $('.wpuf-rich-validation').each(function (index, item) {
334 var item = $(item);
335 var editor_id = item.data('id');
336 var item_name = item.data('name');
337 var val = $.trim( tinyMCE.get(editor_id).getContent() );
338
339 rich_texts.push(item_name + '=' + encodeURIComponent( val ) );
340 });
341
342 // append them to the form var
343 form_data = form_data + '&' + rich_texts.join('&');
344
345
346 self.after(' <span class="wpuf-loading"></span>');
347 $.post(wpuf_frontend.ajaxurl, form_data, function(res) {
348 // console.log(res, post_id);
349 if ( typeof post_id === 'undefined') {
350 var html = '<input type="hidden" name="post_id" value="' + res.post_id +'">';
351 html += '<input type="hidden" name="post_date" value="' + res.date +'">';
352 html += '<input type="hidden" name="post_author" value="' + res.post_author +'">';
353 html += '<input type="hidden" name="comment_status" value="' + res.comment_status +'">';
354
355 form.append( html );
356 }
357
358 self.next('span.wpuf-loading').remove();
359
360 self.after('<span class="wpuf-draft-saved">&nbsp; Post Saved</span>');
361 $('.wpuf-draft-saved').delay(2500).fadeOut('fast', function(){
362 $(this).remove();
363 });
364 })
365 },
366
367 // Frontend account dashboard update profile
368 account_update_profile: function (e) {
369 e.preventDefault();
370 var form = $(this).closest('form');
371
372 $.post(wpuf_frontend.ajaxurl, form.weSerialize(), function (res) {
373 if (res.success) {
374 form.find('.wpuf-error').hide();
375 form.find('.wpuf-success').show();
376 } else {
377 form.find('.wpuf-success').hide();
378 form.find('.wpuf-error').show();
379 form.find('.wpuf-error').text(res.data);
380 }
381 });
382 },
383
384 formStepCheck : function(e,fieldset) {
385 var form = fieldset,
386 submitButton = form.find('input[type=submit]');
387 form_data = WP_User_Frontend.validateForm(form);
388
389 if ( form_data == false ) {
390 WP_User_Frontend.addErrorNotice( self, 'bottom' );
391 }
392 return form_data;
393 },
394
395 formSubmit: function(e) {
396 e.preventDefault();
397
398 var form = $(this),
399 submitButton = form.find('input[type=submit]')
400 form_data = WP_User_Frontend.validateForm(form);
401
402 if (form_data) {
403
404 // send the request
405 form.find('li.wpuf-submit').append('<span class="wpuf-loading"></span>');
406 submitButton.attr('disabled', 'disabled').addClass('button-primary-disabled');
407
408 $.post(wpuf_frontend.ajaxurl, form_data, function(res) {
409 // var res = $.parseJSON(res);
410
411 if ( res.success) {
412
413 // enable external plugins to use events
414 $('body').trigger('wpuf:postform:success', res);
415
416 if ( res.show_message == true) {
417 form.before( '<div class="wpuf-success">' + res.message + '</div>');
418 form.slideUp( 'fast', function() {
419 form.remove();
420 });
421
422 //focus
423 $('html, body').animate({
424 scrollTop: $('.wpuf-success').offset().top - 100
425 }, 'fast');
426
427 } else {
428 window.location = res.redirect_to;
429 }
430
431 } else {
432
433 if ( typeof res.type !== 'undefined' && res.type === 'login' ) {
434
435 if ( confirm(res.error) ) {
436 window.location = res.redirect_to;
437 } else {
438 submitButton.removeAttr('disabled');
439 submitButton.removeClass('button-primary-disabled');
440 form.find('span.wpuf-loading').remove();
441 }
442
443 return;
444 } else {
445 if ( form.find('.g-recaptcha').length > 0 ) {
446 grecaptcha.reset();
447 }
448
449 swal({
450 html: res.error,
451 type: 'warning',
452 showCancelButton: false,
453 confirmButtonColor: '#d54e21',
454 confirmButtonText: 'OK',
455 cancelButtonClass: 'btn btn-danger',
456 });
457
458 }
459
460 submitButton.removeAttr('disabled');
461 }
462
463 submitButton.removeClass('button-primary-disabled');
464 form.find('span.wpuf-loading').remove();
465 });
466 }
467 },
468
469 validateForm: function( self ) {
470
471 var temp,
472 temp_val = '',
473 error = false,
474 error_items = [];
475 error_type = '';
476
477 // remove all initial errors if any
478 WP_User_Frontend.removeErrors(self);
479 WP_User_Frontend.removeErrorNotice(self);
480
481 // Validate: Required Fields
482 var required = self.find('[data-required="yes"]:visible');
483
484 required.each(function(i, item) {
485
486 var data_type = $(item).data('type')
487 val = '';
488
489 switch(data_type) {
490 case 'rich':
491 var name = $(item).data('id')
492 val = $.trim( tinyMCE.get(name).getContent() );
493
494 if ( val === '') {
495 error = true;
496
497 // make it warn collor
498 WP_User_Frontend.markError(item);
499 }
500 break;
501
502 case 'textarea':
503 case 'text':
504
505 val = $.trim( $(item).val() );
506
507 if ( val === '') {
508 error = true;
509 error_type = 'required';
510
511 // make it warn collor
512 WP_User_Frontend.markError( item, error_type );
513 }
514 break;
515
516 case 'password':
517 case 'confirm_password':
518 var hasRepeat = $(item).data('repeat');
519
520 val = $.trim( $(item).val() );
521
522 if ( val === '') {
523 error = true;
524 error_type = 'required';
525
526 // make it warn collor
527 WP_User_Frontend.markError( item, error_type );
528 }
529
530 if ( hasRepeat ) {
531 var repeatItem = $('[data-type="confirm_password"]').eq(0);;
532
533 if ( repeatItem.val() != val ) {
534 error = true;
535 error_type = 'mismatch';
536
537 WP_User_Frontend.markError( repeatItem, error_type );
538 }
539 }
540
541 break;
542
543 case 'select':
544 val = $(item).val();
545
546 // console.log(val);
547 if ( !val || val === '-1' ) {
548 error = true;
549 error_type = 'required';
550
551 // make it warn collor
552 WP_User_Frontend.markError( item, error_type );
553 }
554 break;
555
556 case 'multiselect':
557 val = $(item).val();
558
559 if ( val === null || val.length === 0 ) {
560 error = true;
561 error_type = 'required';
562
563 // make it warn collor
564 WP_User_Frontend.markError( item, error_type );
565 }
566 break;
567
568 case 'tax-checkbox':
569 var length = $(item).children().find('input:checked').length;
570
571 if ( !length ) {
572 error = true;
573 error_type = 'required';
574
575 // make it warn collor
576 WP_User_Frontend.markError( item, error_type );
577 }
578 break;
579
580 case 'radio':
581 var length = $(item).find('input:checked').length;
582
583 if ( !length ) {
584 error = true;
585 error_type = 'required';
586
587 // make it warn collor
588 WP_User_Frontend.markError( item, error_type );
589 }
590 break;
591
592 case 'file':
593 var length = $(item).find('ul').children().length;
594
595 if ( !length ) {
596 error = true;
597 error_type = 'required';
598
599 // make it warn collor
600 WP_User_Frontend.markError( item, error_type );
601 }
602 break;
603
604 case 'email':
605 var val = $(item).val();
606
607 if ( val !== '' ) {
608 //run the validation
609 if( !WP_User_Frontend.isValidEmail( val ) ) {
610 error = true;
611 error_type = 'validation';
612
613 WP_User_Frontend.markError( item, error_type );
614 }
615 } else if( val === '' ) {
616 error = true;
617 error_type = 'required';
618
619 WP_User_Frontend.markError( item, error_type );
620 }
621 break;
622
623
624 case 'url':
625 var val = $(item).val();
626
627 if ( val !== '' ) {
628 //run the validation
629 if( !WP_User_Frontend.isValidURL( val ) ) {
630 error = true;
631 error_type = 'validation';
632
633 WP_User_Frontend.markError( item, error_type );
634 }
635 }
636 break;
637
638 };
639
640 });
641
642 //check Google Map is required
643 var map_required = self.find('[data-required="yes"][name="google_map"]');
644 if ( map_required ) {
645 var val = $(map_required).val();
646 if ( val == ',' ) {
647 error = true;
648 error_type = 'required';
649
650 WP_User_Frontend.markError( map_required, error_type );
651 }
652 }
653
654 // if already some error found, bail out
655 if (error) {
656 // add error notice
657 WP_User_Frontend.addErrorNotice(self,'end');
658
659 return false;
660 }
661
662 var form_data = self.weSerialize(),
663 rich_texts = [];
664
665 // grab rich texts from tinyMCE
666 $('.wpuf-rich-validation', self).each(function (index, item) {
667 var item = $(item);
668 var editor_id = item.data('id');
669 var item_name = item.data('name');
670 var val = $.trim( tinyMCE.get(editor_id).getContent() );
671
672 rich_texts.push(item_name + '=' + encodeURIComponent( val ) );
673 });
674
675 // append them to the form var
676 form_data = form_data + '&' + rich_texts.join('&');
677 return form_data;
678 },
679
680 /**
681 *
682 * @param form
683 * @param position (value = bottom or end) end if form is onepare, bottom, if form is multistep
684 */
685 addErrorNotice: function( form, position ) {
686 if( position == 'bottom' ) {
687 $('.wpuf-multistep-fieldset:visible').append('<div class="wpuf-errors">' + wpuf_frontend.error_message + '</div>');
688 } else {
689 $(form).find('li.wpuf-submit').append('<div class="wpuf-errors">' + wpuf_frontend.error_message + '</div>');
690 }
691
692 },
693
694 removeErrorNotice: function(form) {
695 $(form).find('.wpuf-errors').remove();
696 },
697
698 markError: function(item, error_type) {
699
700 var error_string = '';
701 $(item).closest('li').addClass('has-error');
702
703 if ( error_type ) {
704 error_string = $(item).closest('li').data('label');
705 switch ( error_type ) {
706 case 'required' :
707 error_string = error_string + ' ' + error_str_obj[error_type];
708 break;
709 case 'mismatch' :
710 error_string = error_string + ' ' +error_str_obj[error_type];
711 break;
712 case 'validation' :
713 error_string = error_string + ' ' + error_str_obj[error_type];
714 break
715 }
716 $(item).siblings('.wpuf-error-msg').remove();
717 $(item).after('<div class="wpuf-error-msg">'+ error_string +'</div>')
718 }
719
720 $(item).focus();
721 },
722
723 removeErrors: function(item) {
724 $(item).find('.has-error').removeClass('has-error');
725 $('.wpuf-error-msg').remove();
726 },
727
728 isValidEmail: function( email ) {
729 var pattern = new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);
730 return pattern.test(email);
731 },
732 /**
733 * Validate a url.
734 *
735 * While we could use the standard HTML5 form validator for urls, this regex does a more thorough job.
736 *
737 * @link https://gist.github.com/dperini/729294
738 */
739 isValidURL: function(url) {
740 var urlregex = new RegExp(/^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/);
741 return urlregex.test(url);
742 },
743
744 insertImage: function(button, form_id) {
745
746 var container = 'wpuf-insert-image-container';
747
748 if ( ! $( '#' + button ).length ) {
749 return;
750 };
751
752 var imageUploader = new plupload.Uploader({
753 runtimes: 'html5,html4',
754 browse_button: button,
755 container: container,
756 multipart: true,
757 multipart_params: {
758 action: 'wpuf_insert_image',
759 form_id: $( '#' + button ).data('form_id')
760 },
761 multiple_queues: false,
762 multi_selection: false,
763 urlstream_upload: true,
764 file_data_name: 'wpuf_file',
765 max_file_size: '2mb',
766 url: wpuf_frontend_upload.plupload.url,
767 flash_swf_url: wpuf_frontend_upload.flash_swf_url,
768 filters: [{
769 title: 'Allowed Files',
770 extensions: 'jpg,jpeg,gif,png,bmp'
771 }]
772 });
773
774 imageUploader.bind('Init', function(up, params) {
775 // console.log("Current runtime environment: " + params.runtime);
776 });
777
778 imageUploader.bind('FilesAdded', function(up, files) {
779 var $container = $('#' + container);
780
781 $.each(files, function(i, file) {
782 $container.append(
783 '<div class="upload-item" id="' + file.id + '"><div class="progress progress-striped active"><div class="bar"></div></div></div>');
784 });
785
786 up.refresh();
787 up.start();
788 });
789
790 imageUploader.bind('QueueChanged', function (uploader) {
791 imageUploader.start();
792 });
793
794 imageUploader.bind('UploadProgress', function(up, file) {
795 var item = $('#' + file.id);
796
797 $('.bar', item).css({ width: file.percent + '%' });
798 $('.percent', item).html( file.percent + '%' );
799 });
800
801 imageUploader.bind('Error', function(up, error) {
802 alert('Error #' + error.code + ': ' + error.message);
803 });
804
805 imageUploader.bind('FileUploaded', function(up, file, response) {
806
807 $('#' + file.id).remove();
808
809 if ( response.response !== 'error' ) {
810 var success = false;
811
812 if ( typeof tinyMCE !== 'undefined' ) {
813
814 if ( typeof tinyMCE.execInstanceCommand !== 'function' ) {
815 // tinyMCE 4.x
816 var mce = tinyMCE.get( 'post_content_' + form_id );
817
818 if ( mce !== null ) {
819 mce.insertContent(response.response);
820 }
821 } else {
822 // tinyMCE 3.x
823 tinyMCE.execInstanceCommand( 'post_content_' + form_id, 'mceInsertContent', false, response.response);
824 }
825 }
826
827 // insert failed to the edit, perhaps insert into textarea
828 var post_content = $('#post_content_' + form_id);
829 post_content.val( post_content.val() + response.response );
830
831 } else {
832 alert('Something went wrong');
833 }
834 });
835
836 imageUploader.init();
837 },
838
839 deleteAvatar: function(e) {
840 e.preventDefault();
841
842 if ( confirm( $(this).data('confirm') ) ) {
843 $.post(wpuf_frontend.ajaxurl, {action: 'wpuf_delete_avatar', _wpnonce: wpuf_frontend.nonce}, function() {
844 $(e.target).parent().remove();
845 $('[id^=wpuf-avatar]').css("display", "");
846 });
847 }
848 },
849
850 editorLimit: {
851
852 bind: function(limit, field, type) {
853 if ( type === 'no' ) {
854 // it's a textarea
855 $('textarea#' + field).keydown( function(event) {
856 WP_User_Frontend.editorLimit.textLimit.call(this, event, limit);
857 });
858
859 $('input#' + field).keydown( function(event) {
860 WP_User_Frontend.editorLimit.textLimit.call(this, event, limit);
861 });
862
863 $('textarea#' + field).on('paste', function(event) {
864 var self = $(this);
865
866 setTimeout(function() {
867 WP_User_Frontend.editorLimit.textLimit.call(self, event, limit);
868 }, 100);
869 });
870
871 $('input#' + field).on('paste', function(event) {
872 var self = $(this);
873
874 setTimeout(function() {
875 WP_User_Frontend.editorLimit.textLimit.call(self, event, limit);
876 }, 100);
877 });
878
879 } else {
880 // it's a rich textarea
881 setTimeout(function () {
882 tinyMCE.get(field).onKeyDown.add(function(ed, event) {
883 WP_User_Frontend.editorLimit.tinymce.onKeyDown(ed, event, limit);
884 } );
885
886 tinyMCE.get(field).onPaste.add(function(ed, event) {
887 setTimeout(function() {
888 WP_User_Frontend.editorLimit.tinymce.onPaste(ed, event, limit);
889 }, 100);
890 });
891
892 }, 1000);
893 }
894 },
895
896 tinymce: {
897
898 getStats: function(ed) {
899 var body = ed.getBody(), text = tinymce.trim(body.innerText || body.textContent);
900
901 return {
902 chars: text.length,
903 words: text.split(/[\w\u2019\'-]+/).length
904 };
905 },
906
907 onKeyDown: function(ed, event, limit) {
908 var numWords = WP_User_Frontend.editorLimit.tinymce.getStats(ed).words - 1;
909
910 limit ? $('.mce-path-item.mce-last', ed.container).html('Word Limit : '+ numWords +'/'+limit):'';
911
912 if ( limit && numWords > limit ) {
913 WP_User_Frontend.editorLimit.blockTyping(event);
914 jQuery('.mce-path-item.mce-last', ed.container).html( wpuf_frontend.word_limit );
915 }
916 },
917
918 onPaste: function(ed, event, limit) {
919 var editorContent = ed.getContent().split(' ').slice(0, limit).join(' ');
920
921 // Let TinyMCE do the heavy lifting for inserting that content into the editor.
922 // ed.insertContent(content); //ed.execCommand('mceInsertContent', false, content);
923 ed.setContent(editorContent);
924
925 WP_User_Frontend.editorLimit.make_media_embed_code(editorContent, ed);
926 }
927 },
928
929 textLimit: function(event, limit) {
930 var self = $(this),
931 content = self.val().split(' ');
932
933 if ( limit && content.length > limit ) {
934 self.closest('.wpuf-fields').find('span.wpuf-wordlimit-message').html( wpuf_frontend.word_limit );
935 WP_User_Frontend.editorLimit.blockTyping(event);
936 } else {
937 self.closest('.wpuf-fields').find('span.wpuf-wordlimit-message').html('');
938 }
939
940 // handle the paste event
941 if ( event.type === 'paste' ) {
942 self.val( content.slice(0, limit).join( ' ' ) );
943 }
944 },
945
946 blockTyping: function(event) {
947 // Allow: backspace, delete, tab, escape, minus enter and . backspace = 8,delete=46,tab=9,enter=13,.=190,escape=27, minus = 189
948 if ($.inArray(event.keyCode, [46, 8, 9, 27, 13, 110, 190, 189]) !== -1 ||
949 // Allow: Ctrl+A
950 (event.keyCode == 65 && event.ctrlKey === true) ||
951 // Allow: home, end, left, right, down, up
952 (event.keyCode >= 35 && event.keyCode <= 40)) {
953 // let it happen, don't do anything
954 return;
955 }
956
957 event.preventDefault();
958 event.stopPropagation();
959 },
960
961 make_media_embed_code: function(content, editor){
962 $.post( ajaxurl, {
963 action:'make_media_embed_code',
964 content: content
965 },
966 function(data){
967 // console.log(data);
968 editor.setContent(editor.getContent() + editor.setContent(data));
969 }
970 )
971 }
972 }
973 };
974
975 $(function() {
976 WP_User_Frontend.init();
977
978 // payment gateway selection
979 $('ul.wpuf-payment-gateways').on('click', 'input[type=radio]', function(e) {
980 $('.wpuf-payment-instruction').slideUp(250);
981
982 $(this).parents('li').find('.wpuf-payment-instruction').slideDown(250);
983 });
984
985 if( !$('ul.wpuf-payment-gateways li').find('input[type=radio]').is(':checked') ) {
986 $('ul.wpuf-payment-gateways li').first().find('input[type=radio]').click()
987 } else {
988 var el = $('ul.wpuf-payment-gateways li').find('input[type=radio]:checked');
989 el.parents('li').find('.wpuf-payment-instruction').slideDown(250);
990 }
991 });
992
993 $(function() {
994 $('input[name="first_name"], input[name="last_name"]').on('change keyup', function() {
995 var myVal, newVal = $.makeArray($('input[name="first_name"], input[name="last_name"]').map(function(){
996 if (myVal = $(this).val()) {
997 return(myVal);
998 }
999 })).join(' ');
1000 $('input[name="display_name"]').val(newVal);
1001 });
1002 });
1003
1004 // script for Dokan vendor registration template
1005 $(function($) {
1006
1007 $('.wpuf-form-add input[name="dokan_store_name"]').on('focusout', function() {
1008 var value = $(this).val().toLowerCase().replace(/-+/g, '').replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
1009 $('input[name="shopurl"]').val(value);
1010 $('#url-alart').text( value );
1011 $('input[name="shopurl"]').focus();
1012 });
1013
1014 $('.wpuf-form-add input[name="shopurl"]').keydown(function(e) {
1015 var text = $(this).val();
1016
1017 // Allow: backspace, delete, tab, escape, enter and .
1018 if ($.inArray(e.keyCode, [46, 8, 9, 27, 13, 91, 109, 110, 173, 189, 190]) !== -1 ||
1019 // Allow: Ctrl+A
1020 (e.keyCode == 65 && e.ctrlKey === true) ||
1021 // Allow: home, end, left, right
1022 (e.keyCode >= 35 && e.keyCode <= 39)) {
1023 // let it happen, don't do anything
1024 return;
1025 }
1026
1027 if ((e.shiftKey || (e.keyCode < 65 || e.keyCode > 90) && (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105) ) {
1028 e.preventDefault();
1029 }
1030 });
1031
1032 $('.wpuf-form-add input[name="shopurl"]').keyup(function(e) {
1033 $('#url-alart').text( $(this).val() );
1034 });
1035
1036 $('.wpuf-form-add input[name="shopurl"]').on('focusout', function() {
1037 var self = $(this),
1038 data = {
1039 action : 'shop_url',
1040 url_slug : self.val(),
1041 _nonce : dokan.nonce,
1042 };
1043
1044 if ( self.val() === '' ) {
1045 return;
1046 }
1047
1048 $.post( dokan.ajaxurl, data, function(resp) {
1049
1050 if ( resp == 0){
1051 $('#url-alart').removeClass('text-success').addClass('text-danger');
1052 $('#url-alart-mgs').removeClass('text-success').addClass('text-danger').text(dokan.seller.notAvailable);
1053 } else {
1054 $('#url-alart').removeClass('text-danger').addClass('text-success');
1055 $('#url-alart-mgs').removeClass('text-danger').addClass('text-success').text(dokan.seller.available);
1056 }
1057
1058 } );
1059
1060 });
1061
1062 // Set name attribute for google map search field
1063 $(".wpuf-form-add #wpuf-map-add-location").attr("name", "find_address");
1064 });
1065
1066 })(jQuery, window);
1067
1068 /* assets/wpuf/vendor/sweetalert2/dist/sweetalert2.js */
1069 /*!
1070 * sweetalert2 v6.6.4
1071 * Released under the MIT License.
1072 */
1073 (function (global, factory) {
1074 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1075 typeof define === 'function' && define.amd ? define(factory) :
1076 (global.Sweetalert2 = factory());
1077 }(this, (function () { 'use strict';
1078
1079 var defaultParams = {
1080 title: '',
1081 titleText: '',
1082 text: '',
1083 html: '',
1084 type: null,
1085 customClass: '',
1086 target: 'body',
1087 animation: true,
1088 allowOutsideClick: true,
1089 allowEscapeKey: true,
1090 allowEnterKey: true,
1091 showConfirmButton: true,
1092 showCancelButton: false,
1093 preConfirm: null,
1094 confirmButtonText: 'OK',
1095 confirmButtonColor: '#3085d6',
1096 confirmButtonClass: null,
1097 cancelButtonText: 'Cancel',
1098 cancelButtonColor: '#aaa',
1099 cancelButtonClass: null,
1100 buttonsStyling: true,
1101 reverseButtons: false,
1102 focusCancel: false,
1103 showCloseButton: false,
1104 showLoaderOnConfirm: false,
1105 imageUrl: null,
1106 imageWidth: null,
1107 imageHeight: null,
1108 imageClass: null,
1109 timer: null,
1110 width: 500,
1111 padding: 20,
1112 background: '#fff',
1113 input: null,
1114 inputPlaceholder: '',
1115 inputValue: '',
1116 inputOptions: {},
1117 inputAutoTrim: true,
1118 inputClass: null,
1119 inputAttributes: {},
1120 inputValidator: null,
1121 progressSteps: [],
1122 currentProgressStep: null,
1123 progressStepsDistance: '40px',
1124 onOpen: null,
1125 onClose: null,
1126 useRejections: true
1127 };
1128
1129 var swalPrefix = 'swal2-';
1130
1131 var prefix = function prefix(items) {
1132 var result = {};
1133 for (var i in items) {
1134 result[items[i]] = swalPrefix + items[i];
1135 }
1136 return result;
1137 };
1138
1139 var swalClasses = prefix(['container', 'shown', 'iosfix', 'modal', 'overlay', 'fade', 'show', 'hide', 'noanimation', 'close', 'title', 'content', 'buttonswrapper', 'confirm', 'cancel', 'icon', 'image', 'input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea', 'inputerror', 'validationerror', 'progresssteps', 'activeprogressstep', 'progresscircle', 'progressline', 'loading', 'styled']);
1140
1141 var iconTypes = prefix(['success', 'warning', 'info', 'question', 'error']);
1142
1143 /*
1144 * Set hover, active and focus-states for buttons (source: http://www.sitepoint.com/javascript-generate-lighter-darker-color)
1145 */
1146 var colorLuminance = function colorLuminance(hex, lum) {
1147 // Validate hex string
1148 hex = String(hex).replace(/[^0-9a-f]/gi, '');
1149 if (hex.length < 6) {
1150 hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
1151 }
1152 lum = lum || 0;
1153
1154 // Convert to decimal and change luminosity
1155 var rgb = '#';
1156 for (var i = 0; i < 3; i++) {
1157 var c = parseInt(hex.substr(i * 2, 2), 16);
1158 c = Math.round(Math.min(Math.max(0, c + c * lum), 255)).toString(16);
1159 rgb += ('00' + c).substr(c.length);
1160 }
1161
1162 return rgb;
1163 };
1164
1165 var uniqueArray = function uniqueArray(arr) {
1166 var result = [];
1167 for (var i in arr) {
1168 if (result.indexOf(arr[i]) === -1) {
1169 result.push(arr[i]);
1170 }
1171 }
1172 return result;
1173 };
1174
1175 /* global MouseEvent */
1176
1177 // Remember state in cases where opening and handling a modal will fiddle with it.
1178 var states = {
1179 previousWindowKeyDown: null,
1180 previousActiveElement: null,
1181 previousBodyPadding: null
1182 };
1183
1184 /*
1185 * Add modal + overlay to DOM
1186 */
1187 var init = function init(params) {
1188 if (typeof document === 'undefined') {
1189 console.error('SweetAlert2 requires document to initialize');
1190 return;
1191 }
1192
1193 var container = document.createElement('div');
1194 container.className = swalClasses.container;
1195 container.innerHTML = sweetHTML;
1196
1197 var targetElement = document.querySelector(params.target);
1198 if (!targetElement) {
1199 console.warn('SweetAlert2: Can\'t find the target "' + params.target + '"');
1200 targetElement = document.body;
1201 }
1202 targetElement.appendChild(container);
1203
1204 var modal = getModal();
1205 var input = getChildByClass(modal, swalClasses.input);
1206 var file = getChildByClass(modal, swalClasses.file);
1207 var range = modal.querySelector('.' + swalClasses.range + ' input');
1208 var rangeOutput = modal.querySelector('.' + swalClasses.range + ' output');
1209 var select = getChildByClass(modal, swalClasses.select);
1210 var checkbox = modal.querySelector('.' + swalClasses.checkbox + ' input');
1211 var textarea = getChildByClass(modal, swalClasses.textarea);
1212
1213 input.oninput = function () {
1214 sweetAlert.resetValidationError();
1215 };
1216
1217 input.onkeydown = function (event) {
1218 setTimeout(function () {
1219 if (event.keyCode === 13 && params.allowEnterKey) {
1220 event.stopPropagation();
1221 sweetAlert.clickConfirm();
1222 }
1223 }, 0);
1224 };
1225
1226 file.onchange = function () {
1227 sweetAlert.resetValidationError();
1228 };
1229
1230 range.oninput = function () {
1231 sweetAlert.resetValidationError();
1232 rangeOutput.value = range.value;
1233 };
1234
1235 range.onchange = function () {
1236 sweetAlert.resetValidationError();
1237 range.previousSibling.value = range.value;
1238 };
1239
1240 select.onchange = function () {
1241 sweetAlert.resetValidationError();
1242 };
1243
1244 checkbox.onchange = function () {
1245 sweetAlert.resetValidationError();
1246 };
1247
1248 textarea.oninput = function () {
1249 sweetAlert.resetValidationError();
1250 };
1251
1252 return modal;
1253 };
1254
1255 /*
1256 * Manipulate DOM
1257 */
1258
1259 var sweetHTML = ('\n <div role="dialog" aria-labelledby="' + swalClasses.title + '" aria-describedby="' + swalClasses.content + '" class="' + swalClasses.modal + '" tabindex="-1">\n <ul class="' + swalClasses.progresssteps + '"></ul>\n <div class="' + swalClasses.icon + ' ' + iconTypes.error + '">\n <span class="swal2-x-mark"><span class="swal2-x-mark-line-left"></span><span class="swal2-x-mark-line-right"></span></span>\n </div>\n <div class="' + swalClasses.icon + ' ' + iconTypes.question + '">?</div>\n <div class="' + swalClasses.icon + ' ' + iconTypes.warning + '">!</div>\n <div class="' + swalClasses.icon + ' ' + iconTypes.info + '">i</div>\n <div class="' + swalClasses.icon + ' ' + iconTypes.success + '">\n <div class="swal2-success-circular-line-left"></div>\n <span class="swal2-success-line-tip"></span> <span class="swal2-success-line-long"></span>\n <div class="swal2-success-ring"></div> <div class="swal2-success-fix"></div>\n <div class="swal2-success-circular-line-right"></div>\n </div>\n <img class="' + swalClasses.image + '">\n <h2 class="' + swalClasses.title + '" id="' + swalClasses.title + '"></h2>\n <div id="' + swalClasses.content + '" class="' + swalClasses.content + '"></div>\n <input class="' + swalClasses.input + '">\n <input type="file" class="' + swalClasses.file + '">\n <div class="' + swalClasses.range + '">\n <output></output>\n <input type="range">\n </div>\n <select class="' + swalClasses.select + '"></select>\n <div class="' + swalClasses.radio + '"></div>\n <label for="' + swalClasses.checkbox + '" class="' + swalClasses.checkbox + '">\n <input type="checkbox">\n </label>\n <textarea class="' + swalClasses.textarea + '"></textarea>\n <div class="' + swalClasses.validationerror + '"></div>\n <div class="' + swalClasses.buttonswrapper + '">\n <button type="button" class="' + swalClasses.confirm + '">OK</button>\n <button type="button" class="' + swalClasses.cancel + '">Cancel</button>\n </div>\n <button type="button" class="' + swalClasses.close + '" aria-label="Close this dialog">&times;</button>\n </div>\n').replace(/(^|\n)\s*/g, '');
1260
1261 var getContainer = function getContainer() {
1262 return document.body.querySelector('.' + swalClasses.container);
1263 };
1264
1265 var getModal = function getModal() {
1266 return getContainer() ? getContainer().querySelector('.' + swalClasses.modal) : null;
1267 };
1268
1269 var getIcons = function getIcons() {
1270 var modal = getModal();
1271 return modal.querySelectorAll('.' + swalClasses.icon);
1272 };
1273
1274 var elementByClass = function elementByClass(className) {
1275 return getContainer() ? getContainer().querySelector('.' + className) : null;
1276 };
1277
1278 var getTitle = function getTitle() {
1279 return elementByClass(swalClasses.title);
1280 };
1281
1282 var getContent = function getContent() {
1283 return elementByClass(swalClasses.content);
1284 };
1285
1286 var getImage = function getImage() {
1287 return elementByClass(swalClasses.image);
1288 };
1289
1290 var getButtonsWrapper = function getButtonsWrapper() {
1291 return elementByClass(swalClasses.buttonswrapper);
1292 };
1293
1294 var getProgressSteps = function getProgressSteps() {
1295 return elementByClass(swalClasses.progresssteps);
1296 };
1297
1298 var getValidationError = function getValidationError() {
1299 return elementByClass(swalClasses.validationerror);
1300 };
1301
1302 var getConfirmButton = function getConfirmButton() {
1303 return elementByClass(swalClasses.confirm);
1304 };
1305
1306 var getCancelButton = function getCancelButton() {
1307 return elementByClass(swalClasses.cancel);
1308 };
1309
1310 var getCloseButton = function getCloseButton() {
1311 return elementByClass(swalClasses.close);
1312 };
1313
1314 var getFocusableElements = function getFocusableElements(focusCancel) {
1315 var buttons = [getConfirmButton(), getCancelButton()];
1316 if (focusCancel) {
1317 buttons.reverse();
1318 }
1319 var focusableElements = buttons.concat(Array.prototype.slice.call(getModal().querySelectorAll('button, input:not([type=hidden]), textarea, select, a, *[tabindex]:not([tabindex="-1"])')));
1320 return uniqueArray(focusableElements);
1321 };
1322
1323 var hasClass = function hasClass(elem, className) {
1324 if (elem.classList) {
1325 return elem.classList.contains(className);
1326 }
1327 return false;
1328 };
1329
1330 var focusInput = function focusInput(input) {
1331 input.focus();
1332
1333 // place cursor at end of text in text input
1334 if (input.type !== 'file') {
1335 // http://stackoverflow.com/a/2345915/1331425
1336 var val = input.value;
1337 input.value = '';
1338 input.value = val;
1339 }
1340 };
1341
1342 var addClass = function addClass(elem, className) {
1343 if (!elem || !className) {
1344 return;
1345 }
1346 var classes = className.split(/\s+/).filter(Boolean);
1347 classes.forEach(function (className) {
1348 elem.classList.add(className);
1349 });
1350 };
1351
1352 var removeClass = function removeClass(elem, className) {
1353 if (!elem || !className) {
1354 return;
1355 }
1356 var classes = className.split(/\s+/).filter(Boolean);
1357 classes.forEach(function (className) {
1358 elem.classList.remove(className);
1359 });
1360 };
1361
1362 var getChildByClass = function getChildByClass(elem, className) {
1363 for (var i = 0; i < elem.childNodes.length; i++) {
1364 if (hasClass(elem.childNodes[i], className)) {
1365 return elem.childNodes[i];
1366 }
1367 }
1368 };
1369
1370 var show = function show(elem, display) {
1371 if (!display) {
1372 display = 'block';
1373 }
1374 elem.style.opacity = '';
1375 elem.style.display = display;
1376 };
1377
1378 var hide = function hide(elem) {
1379 elem.style.opacity = '';
1380 elem.style.display = 'none';
1381 };
1382
1383 var empty = function empty(elem) {
1384 while (elem.firstChild) {
1385 elem.removeChild(elem.firstChild);
1386 }
1387 };
1388
1389 // borrowed from jqeury $(elem).is(':visible') implementation
1390 var isVisible = function isVisible(elem) {
1391 return elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length;
1392 };
1393
1394 var removeStyleProperty = function removeStyleProperty(elem, property) {
1395 if (elem.style.removeProperty) {
1396 elem.style.removeProperty(property);
1397 } else {
1398 elem.style.removeAttribute(property);
1399 }
1400 };
1401
1402 var fireClick = function fireClick(node) {
1403 if (!isVisible(node)) {
1404 return false;
1405 }
1406
1407 // Taken from http://www.nonobtrusive.com/2011/11/29/programatically-fire-crossbrowser-click-event-with-javascript/
1408 // Then fixed for today's Chrome browser.
1409 if (typeof MouseEvent === 'function') {
1410 // Up-to-date approach
1411 var mevt = new MouseEvent('click', {
1412 view: window,
1413 bubbles: false,
1414 cancelable: true
1415 });
1416 node.dispatchEvent(mevt);
1417 } else if (document.createEvent) {
1418 // Fallback
1419 var evt = document.createEvent('MouseEvents');
1420 evt.initEvent('click', false, false);
1421 node.dispatchEvent(evt);
1422 } else if (document.createEventObject) {
1423 node.fireEvent('onclick');
1424 } else if (typeof node.onclick === 'function') {
1425 node.onclick();
1426 }
1427 };
1428
1429 var animationEndEvent = function () {
1430 var testEl = document.createElement('div');
1431 var transEndEventNames = {
1432 'WebkitAnimation': 'webkitAnimationEnd',
1433 'OAnimation': 'oAnimationEnd oanimationend',
1434 'msAnimation': 'MSAnimationEnd',
1435 'animation': 'animationend'
1436 };
1437 for (var i in transEndEventNames) {
1438 if (transEndEventNames.hasOwnProperty(i) && testEl.style[i] !== undefined) {
1439 return transEndEventNames[i];
1440 }
1441 }
1442
1443 return false;
1444 }();
1445
1446 // Reset previous window keydown handler and focued element
1447 var resetPrevState = function resetPrevState() {
1448 window.onkeydown = states.previousWindowKeyDown;
1449 if (states.previousActiveElement && states.previousActiveElement.focus) {
1450 var x = window.scrollX;
1451 var y = window.scrollY;
1452 states.previousActiveElement.focus();
1453 if (x && y) {
1454 // IE has no scrollX/scrollY support
1455 window.scrollTo(x, y);
1456 }
1457 }
1458 };
1459
1460 // Measure width of scrollbar
1461 // https://github.com/twbs/bootstrap/blob/master/js/modal.js#L279-L286
1462 var measureScrollbar = function measureScrollbar() {
1463 var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;
1464 if (supportsTouch) {
1465 return 0;
1466 }
1467 var scrollDiv = document.createElement('div');
1468 scrollDiv.style.width = '50px';
1469 scrollDiv.style.height = '50px';
1470 scrollDiv.style.overflow = 'scroll';
1471 document.body.appendChild(scrollDiv);
1472 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
1473 document.body.removeChild(scrollDiv);
1474 return scrollbarWidth;
1475 };
1476
1477 // JavaScript Debounce Function
1478 // Simplivied version of https://davidwalsh.name/javascript-debounce-function
1479 var debounce = function debounce(func, wait) {
1480 var timeout = void 0;
1481 return function () {
1482 var later = function later() {
1483 timeout = null;
1484 func();
1485 };
1486 clearTimeout(timeout);
1487 timeout = setTimeout(later, wait);
1488 };
1489 };
1490
1491 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
1492 return typeof obj;
1493 } : function (obj) {
1494 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
1495 };
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517 var _extends = Object.assign || function (target) {
1518 for (var i = 1; i < arguments.length; i++) {
1519 var source = arguments[i];
1520
1521 for (var key in source) {
1522 if (Object.prototype.hasOwnProperty.call(source, key)) {
1523 target[key] = source[key];
1524 }
1525 }
1526 }
1527
1528 return target;
1529 };
1530
1531 var modalParams = _extends({}, defaultParams);
1532 var queue = [];
1533 var swal2Observer = void 0;
1534
1535 /*
1536 * Set type, text and actions on modal
1537 */
1538 var setParameters = function setParameters(params) {
1539 var modal = getModal() || init(params);
1540
1541 for (var param in params) {
1542 if (!defaultParams.hasOwnProperty(param) && param !== 'extraParams') {
1543 console.warn('SweetAlert2: Unknown parameter "' + param + '"');
1544 }
1545 }
1546
1547 // Set modal width
1548 modal.style.width = typeof params.width === 'number' ? params.width + 'px' : params.width;
1549
1550 modal.style.padding = params.padding + 'px';
1551 modal.style.background = params.background;
1552 var successIconParts = modal.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix');
1553 for (var i = 0; i < successIconParts.length; i++) {
1554 successIconParts[i].style.background = params.background;
1555 }
1556
1557 var title = getTitle();
1558 var content = getContent();
1559 var buttonsWrapper = getButtonsWrapper();
1560 var confirmButton = getConfirmButton();
1561 var cancelButton = getCancelButton();
1562 var closeButton = getCloseButton();
1563
1564 // Title
1565 if (params.titleText) {
1566 title.innerText = params.titleText;
1567 } else {
1568 title.innerHTML = params.title.split('\n').join('<br>');
1569 }
1570
1571 // Content
1572 if (params.text || params.html) {
1573 if (_typeof(params.html) === 'object') {
1574 content.innerHTML = '';
1575 if (0 in params.html) {
1576 for (var _i = 0; _i in params.html; _i++) {
1577 content.appendChild(params.html[_i].cloneNode(true));
1578 }
1579 } else {
1580 content.appendChild(params.html.cloneNode(true));
1581 }
1582 } else if (params.html) {
1583 content.innerHTML = params.html;
1584 } else if (params.text) {
1585 content.textContent = params.text;
1586 }
1587 show(content);
1588 } else {
1589 hide(content);
1590 }
1591
1592 // Close button
1593 if (params.showCloseButton) {
1594 show(closeButton);
1595 } else {
1596 hide(closeButton);
1597 }
1598
1599 // Custom Class
1600 modal.className = swalClasses.modal;
1601 if (params.customClass) {
1602 addClass(modal, params.customClass);
1603 }
1604
1605 // Progress steps
1606 var progressStepsContainer = getProgressSteps();
1607 var currentProgressStep = parseInt(params.currentProgressStep === null ? sweetAlert.getQueueStep() : params.currentProgressStep, 10);
1608 if (params.progressSteps.length) {
1609 show(progressStepsContainer);
1610 empty(progressStepsContainer);
1611 if (currentProgressStep >= params.progressSteps.length) {
1612 console.warn('SweetAlert2: Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)');
1613 }
1614 params.progressSteps.forEach(function (step, index) {
1615 var circle = document.createElement('li');
1616 addClass(circle, swalClasses.progresscircle);
1617 circle.innerHTML = step;
1618 if (index === currentProgressStep) {
1619 addClass(circle, swalClasses.activeprogressstep);
1620 }
1621 progressStepsContainer.appendChild(circle);
1622 if (index !== params.progressSteps.length - 1) {
1623 var line = document.createElement('li');
1624 addClass(line, swalClasses.progressline);
1625 line.style.width = params.progressStepsDistance;
1626 progressStepsContainer.appendChild(line);
1627 }
1628 });
1629 } else {
1630 hide(progressStepsContainer);
1631 }
1632
1633 // Icon
1634 var icons = getIcons();
1635 for (var _i2 = 0; _i2 < icons.length; _i2++) {
1636 hide(icons[_i2]);
1637 }
1638 if (params.type) {
1639 var validType = false;
1640 for (var iconType in iconTypes) {
1641 if (params.type === iconType) {
1642 validType = true;
1643 break;
1644 }
1645 }
1646 if (!validType) {
1647 console.error('SweetAlert2: Unknown alert type: ' + params.type);
1648 return false;
1649 }
1650 var icon = modal.querySelector('.' + swalClasses.icon + '.' + iconTypes[params.type]);
1651 show(icon);
1652
1653 // Animate icon
1654 if (params.animation) {
1655 switch (params.type) {
1656 case 'success':
1657 addClass(icon, 'swal2-animate-success-icon');
1658 addClass(icon.querySelector('.swal2-success-line-tip'), 'swal2-animate-success-line-tip');
1659 addClass(icon.querySelector('.swal2-success-line-long'), 'swal2-animate-success-line-long');
1660 break;
1661 case 'error':
1662 addClass(icon, 'swal2-animate-error-icon');
1663 addClass(icon.querySelector('.swal2-x-mark'), 'swal2-animate-x-mark');
1664 break;
1665 default:
1666 break;
1667 }
1668 }
1669 }
1670
1671 // Custom image
1672 var image = getImage();
1673 if (params.imageUrl) {
1674 image.setAttribute('src', params.imageUrl);
1675 show(image);
1676
1677 if (params.imageWidth) {
1678 image.setAttribute('width', params.imageWidth);
1679 } else {
1680 image.removeAttribute('width');
1681 }
1682
1683 if (params.imageHeight) {
1684 image.setAttribute('height', params.imageHeight);
1685 } else {
1686 image.removeAttribute('height');
1687 }
1688
1689 image.className = swalClasses.image;
1690 if (params.imageClass) {
1691 addClass(image, params.imageClass);
1692 }
1693 } else {
1694 hide(image);
1695 }
1696
1697 // Cancel button
1698 if (params.showCancelButton) {
1699 cancelButton.style.display = 'inline-block';
1700 } else {
1701 hide(cancelButton);
1702 }
1703
1704 // Confirm button
1705 if (params.showConfirmButton) {
1706 removeStyleProperty(confirmButton, 'display');
1707 } else {
1708 hide(confirmButton);
1709 }
1710
1711 // Buttons wrapper
1712 if (!params.showConfirmButton && !params.showCancelButton) {
1713 hide(buttonsWrapper);
1714 } else {
1715 show(buttonsWrapper);
1716 }
1717
1718 // Edit text on cancel and confirm buttons
1719 confirmButton.innerHTML = params.confirmButtonText;
1720 cancelButton.innerHTML = params.cancelButtonText;
1721
1722 // Set buttons to selected background colors
1723 if (params.buttonsStyling) {
1724 confirmButton.style.backgroundColor = params.confirmButtonColor;
1725 cancelButton.style.backgroundColor = params.cancelButtonColor;
1726 }
1727
1728 // Add buttons custom classes
1729 confirmButton.className = swalClasses.confirm;
1730 addClass(confirmButton, params.confirmButtonClass);
1731 cancelButton.className = swalClasses.cancel;
1732 addClass(cancelButton, params.cancelButtonClass);
1733
1734 // Buttons styling
1735 if (params.buttonsStyling) {
1736 addClass(confirmButton, swalClasses.styled);
1737 addClass(cancelButton, swalClasses.styled);
1738 } else {
1739 removeClass(confirmButton, swalClasses.styled);
1740 removeClass(cancelButton, swalClasses.styled);
1741
1742 confirmButton.style.backgroundColor = confirmButton.style.borderLeftColor = confirmButton.style.borderRightColor = '';
1743 cancelButton.style.backgroundColor = cancelButton.style.borderLeftColor = cancelButton.style.borderRightColor = '';
1744 }
1745
1746 // CSS animation
1747 if (params.animation === true) {
1748 removeClass(modal, swalClasses.noanimation);
1749 } else {
1750 addClass(modal, swalClasses.noanimation);
1751 }
1752 };
1753
1754 /*
1755 * Animations
1756 */
1757 var openModal = function openModal(animation, onComplete) {
1758 var container = getContainer();
1759 var modal = getModal();
1760
1761 if (animation) {
1762 addClass(modal, swalClasses.show);
1763 addClass(container, swalClasses.fade);
1764 removeClass(modal, swalClasses.hide);
1765 } else {
1766 removeClass(modal, swalClasses.fade);
1767 }
1768 show(modal);
1769
1770 // scrolling is 'hidden' until animation is done, after that 'auto'
1771 container.style.overflowY = 'hidden';
1772 if (animationEndEvent && !hasClass(modal, swalClasses.noanimation)) {
1773 modal.addEventListener(animationEndEvent, function swalCloseEventFinished() {
1774 modal.removeEventListener(animationEndEvent, swalCloseEventFinished);
1775 container.style.overflowY = 'auto';
1776 });
1777 } else {
1778 container.style.overflowY = 'auto';
1779 }
1780
1781 addClass(document.documentElement, swalClasses.shown);
1782 addClass(document.body, swalClasses.shown);
1783 addClass(container, swalClasses.shown);
1784 fixScrollbar();
1785 iOSfix();
1786 states.previousActiveElement = document.activeElement;
1787 if (onComplete !== null && typeof onComplete === 'function') {
1788 setTimeout(function () {
1789 onComplete(modal);
1790 });
1791 }
1792 };
1793
1794 var fixScrollbar = function fixScrollbar() {
1795 // for queues, do not do this more than once
1796 if (states.previousBodyPadding !== null) {
1797 return;
1798 }
1799 // if the body has overflow
1800 if (document.body.scrollHeight > window.innerHeight) {
1801 // add padding so the content doesn't shift after removal of scrollbar
1802 states.previousBodyPadding = document.body.style.paddingRight;
1803 document.body.style.paddingRight = measureScrollbar() + 'px';
1804 }
1805 };
1806
1807 var undoScrollbar = function undoScrollbar() {
1808 if (states.previousBodyPadding !== null) {
1809 document.body.style.paddingRight = states.previousBodyPadding;
1810 states.previousBodyPadding = null;
1811 }
1812 };
1813
1814 // Fix iOS scrolling http://stackoverflow.com/q/39626302/1331425
1815 var iOSfix = function iOSfix() {
1816 var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
1817 if (iOS && !hasClass(document.body, swalClasses.iosfix)) {
1818 var offset = document.body.scrollTop;
1819 document.body.style.top = offset * -1 + 'px';
1820 addClass(document.body, swalClasses.iosfix);
1821 }
1822 };
1823
1824 var undoIOSfix = function undoIOSfix() {
1825 if (hasClass(document.body, swalClasses.iosfix)) {
1826 var offset = parseInt(document.body.style.top, 10);
1827 removeClass(document.body, swalClasses.iosfix);
1828 document.body.style.top = '';
1829 document.body.scrollTop = offset * -1;
1830 }
1831 };
1832
1833 // SweetAlert entry point
1834 var sweetAlert = function sweetAlert() {
1835 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
1836 args[_key] = arguments[_key];
1837 }
1838
1839 if (args[0] === undefined) {
1840 console.error('SweetAlert2 expects at least 1 attribute!');
1841 return false;
1842 }
1843
1844 var params = _extends({}, modalParams);
1845
1846 switch (_typeof(args[0])) {
1847 case 'string':
1848 params.title = args[0];
1849 params.html = args[1];
1850 params.type = args[2];
1851
1852 break;
1853
1854 case 'object':
1855 _extends(params, args[0]);
1856 params.extraParams = args[0].extraParams;
1857
1858 if (params.input === 'email' && params.inputValidator === null) {
1859 params.inputValidator = function (email) {
1860 return new Promise(function (resolve, reject) {
1861 var emailRegex = /^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
1862 if (emailRegex.test(email)) {
1863 resolve();
1864 } else {
1865 reject('Invalid email address');
1866 }
1867 });
1868 };
1869 }
1870
1871 if (params.input === 'url' && params.inputValidator === null) {
1872 params.inputValidator = function (url) {
1873 return new Promise(function (resolve, reject) {
1874 var urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;
1875 if (urlRegex.test(url)) {
1876 resolve();
1877 } else {
1878 reject('Invalid URL');
1879 }
1880 });
1881 };
1882 }
1883 break;
1884
1885 default:
1886 console.error('SweetAlert2: Unexpected type of argument! Expected "string" or "object", got ' + _typeof(args[0]));
1887 return false;
1888 }
1889
1890 setParameters(params);
1891
1892 var container = getContainer();
1893 var modal = getModal();
1894
1895 return new Promise(function (resolve, reject) {
1896 // Close on timer
1897 if (params.timer) {
1898 modal.timeout = setTimeout(function () {
1899 sweetAlert.closeModal(params.onClose);
1900 if (params.useRejections) {
1901 reject('timer');
1902 } else {
1903 resolve({ dismiss: 'timer' });
1904 }
1905 }, params.timer);
1906 }
1907
1908 // Get input element by specified type or, if type isn't specified, by params.input
1909 var getInput = function getInput(inputType) {
1910 inputType = inputType || params.input;
1911 if (!inputType) {
1912 return null;
1913 }
1914 switch (inputType) {
1915 case 'select':
1916 case 'textarea':
1917 case 'file':
1918 return getChildByClass(modal, swalClasses[inputType]);
1919 case 'checkbox':
1920 return modal.querySelector('.' + swalClasses.checkbox + ' input');
1921 case 'radio':
1922 return modal.querySelector('.' + swalClasses.radio + ' input:checked') || modal.querySelector('.' + swalClasses.radio + ' input:first-child');
1923 case 'range':
1924 return modal.querySelector('.' + swalClasses.range + ' input');
1925 default:
1926 return getChildByClass(modal, swalClasses.input);
1927 }
1928 };
1929
1930 // Get the value of the modal input
1931 var getInputValue = function getInputValue() {
1932 var input = getInput();
1933 if (!input) {
1934 return null;
1935 }
1936 switch (params.input) {
1937 case 'checkbox':
1938 return input.checked ? 1 : 0;
1939 case 'radio':
1940 return input.checked ? input.value : null;
1941 case 'file':
1942 return input.files.length ? input.files[0] : null;
1943 default:
1944 return params.inputAutoTrim ? input.value.trim() : input.value;
1945 }
1946 };
1947
1948 // input autofocus
1949 if (params.input) {
1950 setTimeout(function () {
1951 var input = getInput();
1952 if (input) {
1953 focusInput(input);
1954 }
1955 }, 0);
1956 }
1957
1958 var confirm = function confirm(value) {
1959 if (params.showLoaderOnConfirm) {
1960 sweetAlert.showLoading();
1961 }
1962
1963 if (params.preConfirm) {
1964 params.preConfirm(value, params.extraParams).then(function (preConfirmValue) {
1965 sweetAlert.closeModal(params.onClose);
1966 resolve(preConfirmValue || value);
1967 }, function (error) {
1968 sweetAlert.hideLoading();
1969 if (error) {
1970 sweetAlert.showValidationError(error);
1971 }
1972 });
1973 } else {
1974 sweetAlert.closeModal(params.onClose);
1975 if (params.useRejections) {
1976 resolve(value);
1977 } else {
1978 resolve({ value: value });
1979 }
1980 }
1981 };
1982
1983 // Mouse interactions
1984 var onButtonEvent = function onButtonEvent(event) {
1985 var e = event || window.event;
1986 var target = e.target || e.srcElement;
1987 var confirmButton = getConfirmButton();
1988 var cancelButton = getCancelButton();
1989 var targetedConfirm = confirmButton && (confirmButton === target || confirmButton.contains(target));
1990 var targetedCancel = cancelButton && (cancelButton === target || cancelButton.contains(target));
1991
1992 switch (e.type) {
1993 case 'mouseover':
1994 case 'mouseup':
1995 if (params.buttonsStyling) {
1996 if (targetedConfirm) {
1997 confirmButton.style.backgroundColor = colorLuminance(params.confirmButtonColor, -0.1);
1998 } else if (targetedCancel) {
1999 cancelButton.style.backgroundColor = colorLuminance(params.cancelButtonColor, -0.1);
2000 }
2001 }
2002 break;
2003 case 'mouseout':
2004 if (params.buttonsStyling) {
2005 if (targetedConfirm) {
2006 confirmButton.style.backgroundColor = params.confirmButtonColor;
2007 } else if (targetedCancel) {
2008 cancelButton.style.backgroundColor = params.cancelButtonColor;
2009 }
2010 }
2011 break;
2012 case 'mousedown':
2013 if (params.buttonsStyling) {
2014 if (targetedConfirm) {
2015 confirmButton.style.backgroundColor = colorLuminance(params.confirmButtonColor, -0.2);
2016 } else if (targetedCancel) {
2017 cancelButton.style.backgroundColor = colorLuminance(params.cancelButtonColor, -0.2);
2018 }
2019 }
2020 break;
2021 case 'click':
2022 // Clicked 'confirm'
2023 if (targetedConfirm && sweetAlert.isVisible()) {
2024 sweetAlert.disableButtons();
2025 if (params.input) {
2026 var inputValue = getInputValue();
2027
2028 if (params.inputValidator) {
2029 sweetAlert.disableInput();
2030 params.inputValidator(inputValue, params.extraParams).then(function () {
2031 sweetAlert.enableButtons();
2032 sweetAlert.enableInput();
2033 confirm(inputValue);
2034 }, function (error) {
2035 sweetAlert.enableButtons();
2036 sweetAlert.enableInput();
2037 if (error) {
2038 sweetAlert.showValidationError(error);
2039 }
2040 });
2041 } else {
2042 confirm(inputValue);
2043 }
2044 } else {
2045 confirm(true);
2046 }
2047
2048 // Clicked 'cancel'
2049 } else if (targetedCancel && sweetAlert.isVisible()) {
2050 sweetAlert.disableButtons();
2051 sweetAlert.closeModal(params.onClose);
2052 if (params.useRejections) {
2053 reject('cancel');
2054 } else {
2055 resolve({ dismiss: 'cancel' });
2056 }
2057 }
2058 break;
2059 default:
2060 }
2061 };
2062
2063 var buttons = modal.querySelectorAll('button');
2064 for (var i = 0; i < buttons.length; i++) {
2065 buttons[i].onclick = onButtonEvent;
2066 buttons[i].onmouseover = onButtonEvent;
2067 buttons[i].onmouseout = onButtonEvent;
2068 buttons[i].onmousedown = onButtonEvent;
2069 }
2070
2071 // Closing modal by close button
2072 getCloseButton().onclick = function () {
2073 sweetAlert.closeModal(params.onClose);
2074 if (params.useRejections) {
2075 reject('close');
2076 } else {
2077 resolve({ dismiss: 'close' });
2078 }
2079 };
2080
2081 // Closing modal by overlay click
2082 container.onclick = function (e) {
2083 if (e.target !== container) {
2084 return;
2085 }
2086 if (params.allowOutsideClick) {
2087 sweetAlert.closeModal(params.onClose);
2088 if (params.useRejections) {
2089 reject('overlay');
2090 } else {
2091 resolve({ dismiss: 'overlay' });
2092 }
2093 }
2094 };
2095
2096 var buttonsWrapper = getButtonsWrapper();
2097 var confirmButton = getConfirmButton();
2098 var cancelButton = getCancelButton();
2099
2100 // Reverse buttons (Confirm on the right side)
2101 if (params.reverseButtons) {
2102 confirmButton.parentNode.insertBefore(cancelButton, confirmButton);
2103 } else {
2104 confirmButton.parentNode.insertBefore(confirmButton, cancelButton);
2105 }
2106
2107 // Focus handling
2108 var setFocus = function setFocus(index, increment) {
2109 var focusableElements = getFocusableElements(params.focusCancel);
2110 // search for visible elements and select the next possible match
2111 for (var _i3 = 0; _i3 < focusableElements.length; _i3++) {
2112 index = index + increment;
2113
2114 // rollover to first item
2115 if (index === focusableElements.length) {
2116 index = 0;
2117
2118 // go to last item
2119 } else if (index === -1) {
2120 index = focusableElements.length - 1;
2121 }
2122
2123 // determine if element is visible
2124 var el = focusableElements[index];
2125 if (isVisible(el)) {
2126 return el.focus();
2127 }
2128 }
2129 };
2130
2131 var handleKeyDown = function handleKeyDown(event) {
2132 var e = event || window.event;
2133 var keyCode = e.keyCode || e.which;
2134
2135 if ([9, 13, 32, 27, 37, 38, 39, 40].indexOf(keyCode) === -1) {
2136 // Don't do work on keys we don't care about.
2137 return;
2138 }
2139
2140 var targetElement = e.target || e.srcElement;
2141
2142 var focusableElements = getFocusableElements(params.focusCancel);
2143 var btnIndex = -1; // Find the button - note, this is a nodelist, not an array.
2144 for (var _i4 = 0; _i4 < focusableElements.length; _i4++) {
2145 if (targetElement === focusableElements[_i4]) {
2146 btnIndex = _i4;
2147 break;
2148 }
2149 }
2150
2151 // TAB
2152 if (keyCode === 9) {
2153 if (!e.shiftKey) {
2154 // Cycle to the next button
2155 setFocus(btnIndex, 1);
2156 } else {
2157 // Cycle to the prev button
2158 setFocus(btnIndex, -1);
2159 }
2160 e.stopPropagation();
2161 e.preventDefault();
2162
2163 // ARROWS - switch focus between buttons
2164 } else if (keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40) {
2165 // focus Cancel button if Confirm button is currently focused
2166 if (document.activeElement === confirmButton && isVisible(cancelButton)) {
2167 cancelButton.focus();
2168 // and vice versa
2169 } else if (document.activeElement === cancelButton && isVisible(confirmButton)) {
2170 confirmButton.focus();
2171 }
2172
2173 // ENTER/SPACE
2174 } else if (keyCode === 13 || keyCode === 32) {
2175 if (btnIndex === -1 && params.allowEnterKey) {
2176 // ENTER/SPACE clicked outside of a button.
2177 if (params.focusCancel) {
2178 fireClick(cancelButton, e);
2179 } else {
2180 fireClick(confirmButton, e);
2181 }
2182 e.stopPropagation();
2183 e.preventDefault();
2184 }
2185
2186 // ESC
2187 } else if (keyCode === 27 && params.allowEscapeKey === true) {
2188 sweetAlert.closeModal(params.onClose);
2189 if (params.useRejections) {
2190 reject('esc');
2191 } else {
2192 resolve({ dismiss: 'esc' });
2193 }
2194 }
2195 };
2196
2197 if (!window.onkeydown || window.onkeydown.toString() !== handleKeyDown.toString()) {
2198 states.previousWindowKeyDown = window.onkeydown;
2199 window.onkeydown = handleKeyDown;
2200 }
2201
2202 // Loading state
2203 if (params.buttonsStyling) {
2204 confirmButton.style.borderLeftColor = params.confirmButtonColor;
2205 confirmButton.style.borderRightColor = params.confirmButtonColor;
2206 }
2207
2208 /**
2209 * Show spinner instead of Confirm button and disable Cancel button
2210 */
2211 sweetAlert.hideLoading = sweetAlert.disableLoading = function () {
2212 if (!params.showConfirmButton) {
2213 hide(confirmButton);
2214 if (!params.showCancelButton) {
2215 hide(getButtonsWrapper());
2216 }
2217 }
2218 removeClass(buttonsWrapper, swalClasses.loading);
2219 removeClass(modal, swalClasses.loading);
2220 confirmButton.disabled = false;
2221 cancelButton.disabled = false;
2222 };
2223
2224 sweetAlert.getTitle = function () {
2225 return getTitle();
2226 };
2227 sweetAlert.getContent = function () {
2228 return getContent();
2229 };
2230 sweetAlert.getInput = function () {
2231 return getInput();
2232 };
2233 sweetAlert.getImage = function () {
2234 return getImage();
2235 };
2236 sweetAlert.getButtonsWrapper = function () {
2237 return getButtonsWrapper();
2238 };
2239 sweetAlert.getConfirmButton = function () {
2240 return getConfirmButton();
2241 };
2242 sweetAlert.getCancelButton = function () {
2243 return getCancelButton();
2244 };
2245
2246 sweetAlert.enableButtons = function () {
2247 confirmButton.disabled = false;
2248 cancelButton.disabled = false;
2249 };
2250
2251 sweetAlert.disableButtons = function () {
2252 confirmButton.disabled = true;
2253 cancelButton.disabled = true;
2254 };
2255
2256 sweetAlert.enableConfirmButton = function () {
2257 confirmButton.disabled = false;
2258 };
2259
2260 sweetAlert.disableConfirmButton = function () {
2261 confirmButton.disabled = true;
2262 };
2263
2264 sweetAlert.enableInput = function () {
2265 var input = getInput();
2266 if (!input) {
2267 return false;
2268 }
2269 if (input.type === 'radio') {
2270 var radiosContainer = input.parentNode.parentNode;
2271 var radios = radiosContainer.querySelectorAll('input');
2272 for (var _i5 = 0; _i5 < radios.length; _i5++) {
2273 radios[_i5].disabled = false;
2274 }
2275 } else {
2276 input.disabled = false;
2277 }
2278 };
2279
2280 sweetAlert.disableInput = function () {
2281 var input = getInput();
2282 if (!input) {
2283 return false;
2284 }
2285 if (input && input.type === 'radio') {
2286 var radiosContainer = input.parentNode.parentNode;
2287 var radios = radiosContainer.querySelectorAll('input');
2288 for (var _i6 = 0; _i6 < radios.length; _i6++) {
2289 radios[_i6].disabled = true;
2290 }
2291 } else {
2292 input.disabled = true;
2293 }
2294 };
2295
2296 // Set modal min-height to disable scrolling inside the modal
2297 sweetAlert.recalculateHeight = debounce(function () {
2298 var modal = getModal();
2299 if (!modal) {
2300 return;
2301 }
2302 var prevState = modal.style.display;
2303 modal.style.minHeight = '';
2304 show(modal);
2305 modal.style.minHeight = modal.scrollHeight + 1 + 'px';
2306 modal.style.display = prevState;
2307 }, 50);
2308
2309 // Show block with validation error
2310 sweetAlert.showValidationError = function (error) {
2311 var validationError = getValidationError();
2312 validationError.innerHTML = error;
2313 show(validationError);
2314
2315 var input = getInput();
2316 if (input) {
2317 focusInput(input);
2318 addClass(input, swalClasses.inputerror);
2319 }
2320 };
2321
2322 // Hide block with validation error
2323 sweetAlert.resetValidationError = function () {
2324 var validationError = getValidationError();
2325 hide(validationError);
2326 sweetAlert.recalculateHeight();
2327
2328 var input = getInput();
2329 if (input) {
2330 removeClass(input, swalClasses.inputerror);
2331 }
2332 };
2333
2334 sweetAlert.getProgressSteps = function () {
2335 return params.progressSteps;
2336 };
2337
2338 sweetAlert.setProgressSteps = function (progressSteps) {
2339 params.progressSteps = progressSteps;
2340 setParameters(params);
2341 };
2342
2343 sweetAlert.showProgressSteps = function () {
2344 show(getProgressSteps());
2345 };
2346
2347 sweetAlert.hideProgressSteps = function () {
2348 hide(getProgressSteps());
2349 };
2350
2351 sweetAlert.enableButtons();
2352 sweetAlert.hideLoading();
2353 sweetAlert.resetValidationError();
2354
2355 // inputs
2356 var inputTypes = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea'];
2357 var input = void 0;
2358 for (var _i7 = 0; _i7 < inputTypes.length; _i7++) {
2359 var inputClass = swalClasses[inputTypes[_i7]];
2360 var inputContainer = getChildByClass(modal, inputClass);
2361 input = getInput(inputTypes[_i7]);
2362
2363 // set attributes
2364 if (input) {
2365 for (var j in input.attributes) {
2366 if (input.attributes.hasOwnProperty(j)) {
2367 var attrName = input.attributes[j].name;
2368 if (attrName !== 'type' && attrName !== 'value') {
2369 input.removeAttribute(attrName);
2370 }
2371 }
2372 }
2373 for (var attr in params.inputAttributes) {
2374 input.setAttribute(attr, params.inputAttributes[attr]);
2375 }
2376 }
2377
2378 // set class
2379 inputContainer.className = inputClass;
2380 if (params.inputClass) {
2381 addClass(inputContainer, params.inputClass);
2382 }
2383
2384 hide(inputContainer);
2385 }
2386
2387 var populateInputOptions = void 0;
2388 switch (params.input) {
2389 case 'text':
2390 case 'email':
2391 case 'password':
2392 case 'number':
2393 case 'tel':
2394 case 'url':
2395 input = getChildByClass(modal, swalClasses.input);
2396 input.value = params.inputValue;
2397 input.placeholder = params.inputPlaceholder;
2398 input.type = params.input;
2399 show(input);
2400 break;
2401 case 'file':
2402 input = getChildByClass(modal, swalClasses.file);
2403 input.placeholder = params.inputPlaceholder;
2404 input.type = params.input;
2405 show(input);
2406 break;
2407 case 'range':
2408 var range = getChildByClass(modal, swalClasses.range);
2409 var rangeInput = range.querySelector('input');
2410 var rangeOutput = range.querySelector('output');
2411 rangeInput.value = params.inputValue;
2412 rangeInput.type = params.input;
2413 rangeOutput.value = params.inputValue;
2414 show(range);
2415 break;
2416 case 'select':
2417 var select = getChildByClass(modal, swalClasses.select);
2418 select.innerHTML = '';
2419 if (params.inputPlaceholder) {
2420 var placeholder = document.createElement('option');
2421 placeholder.innerHTML = params.inputPlaceholder;
2422 placeholder.value = '';
2423 placeholder.disabled = true;
2424 placeholder.selected = true;
2425 select.appendChild(placeholder);
2426 }
2427 populateInputOptions = function populateInputOptions(inputOptions) {
2428 for (var optionValue in inputOptions) {
2429 var option = document.createElement('option');
2430 option.value = optionValue;
2431 option.innerHTML = inputOptions[optionValue];
2432 if (params.inputValue === optionValue) {
2433 option.selected = true;
2434 }
2435 select.appendChild(option);
2436 }
2437 show(select);
2438 select.focus();
2439 };
2440 break;
2441 case 'radio':
2442 var radio = getChildByClass(modal, swalClasses.radio);
2443 radio.innerHTML = '';
2444 populateInputOptions = function populateInputOptions(inputOptions) {
2445 for (var radioValue in inputOptions) {
2446 var radioInput = document.createElement('input');
2447 var radioLabel = document.createElement('label');
2448 var radioLabelSpan = document.createElement('span');
2449 radioInput.type = 'radio';
2450 radioInput.name = swalClasses.radio;
2451 radioInput.value = radioValue;
2452 if (params.inputValue === radioValue) {
2453 radioInput.checked = true;
2454 }
2455 radioLabelSpan.innerHTML = inputOptions[radioValue];
2456 radioLabel.appendChild(radioInput);
2457 radioLabel.appendChild(radioLabelSpan);
2458 radioLabel.for = radioInput.id;
2459 radio.appendChild(radioLabel);
2460 }
2461 show(radio);
2462 var radios = radio.querySelectorAll('input');
2463 if (radios.length) {
2464 radios[0].focus();
2465 }
2466 };
2467 break;
2468 case 'checkbox':
2469 var checkbox = getChildByClass(modal, swalClasses.checkbox);
2470 var checkboxInput = getInput('checkbox');
2471 checkboxInput.type = 'checkbox';
2472 checkboxInput.value = 1;
2473 checkboxInput.id = swalClasses.checkbox;
2474 checkboxInput.checked = Boolean(params.inputValue);
2475 var label = checkbox.getElementsByTagName('span');
2476 if (label.length) {
2477 checkbox.removeChild(label[0]);
2478 }
2479 label = document.createElement('span');
2480 label.innerHTML = params.inputPlaceholder;
2481 checkbox.appendChild(label);
2482 show(checkbox);
2483 break;
2484 case 'textarea':
2485 var textarea = getChildByClass(modal, swalClasses.textarea);
2486 textarea.value = params.inputValue;
2487 textarea.placeholder = params.inputPlaceholder;
2488 show(textarea);
2489 break;
2490 case null:
2491 break;
2492 default:
2493 console.error('SweetAlert2: Unexpected type of input! Expected "text", "email", "password", "number", "tel", "select", "radio", "checkbox", "textarea", "file" or "url", got "' + params.input + '"');
2494 break;
2495 }
2496
2497 if (params.input === 'select' || params.input === 'radio') {
2498 if (params.inputOptions instanceof Promise) {
2499 sweetAlert.showLoading();
2500 params.inputOptions.then(function (inputOptions) {
2501 sweetAlert.hideLoading();
2502 populateInputOptions(inputOptions);
2503 });
2504 } else if (_typeof(params.inputOptions) === 'object') {
2505 populateInputOptions(params.inputOptions);
2506 } else {
2507 console.error('SweetAlert2: Unexpected type of inputOptions! Expected object or Promise, got ' + _typeof(params.inputOptions));
2508 }
2509 }
2510
2511 openModal(params.animation, params.onOpen);
2512
2513 // Focus the first element (input or button)
2514 if (params.allowEnterKey) {
2515 setFocus(-1, 1);
2516 } else {
2517 if (document.activeElement) {
2518 document.activeElement.blur();
2519 }
2520 }
2521
2522 // fix scroll
2523 getContainer().scrollTop = 0;
2524
2525 // Observe changes inside the modal and adjust height
2526 if (typeof MutationObserver !== 'undefined' && !swal2Observer) {
2527 swal2Observer = new MutationObserver(sweetAlert.recalculateHeight);
2528 swal2Observer.observe(modal, { childList: true, characterData: true, subtree: true });
2529 }
2530 });
2531 };
2532
2533 /*
2534 * Global function to determine if swal2 modal is shown
2535 */
2536 sweetAlert.isVisible = function () {
2537 return !!getModal();
2538 };
2539
2540 /*
2541 * Global function for chaining sweetAlert modals
2542 */
2543 sweetAlert.queue = function (steps) {
2544 queue = steps;
2545 var resetQueue = function resetQueue() {
2546 queue = [];
2547 document.body.removeAttribute('data-swal2-queue-step');
2548 };
2549 var queueResult = [];
2550 return new Promise(function (resolve, reject) {
2551 (function step(i, callback) {
2552 if (i < queue.length) {
2553 document.body.setAttribute('data-swal2-queue-step', i);
2554
2555 sweetAlert(queue[i]).then(function (result) {
2556 queueResult.push(result);
2557 step(i + 1, callback);
2558 }, function (dismiss) {
2559 resetQueue();
2560 reject(dismiss);
2561 });
2562 } else {
2563 resetQueue();
2564 resolve(queueResult);
2565 }
2566 })(0);
2567 });
2568 };
2569
2570 /*
2571 * Global function for getting the index of current modal in queue
2572 */
2573 sweetAlert.getQueueStep = function () {
2574 return document.body.getAttribute('data-swal2-queue-step');
2575 };
2576
2577 /*
2578 * Global function for inserting a modal to the queue
2579 */
2580 sweetAlert.insertQueueStep = function (step, index) {
2581 if (index && index < queue.length) {
2582 return queue.splice(index, 0, step);
2583 }
2584 return queue.push(step);
2585 };
2586
2587 /*
2588 * Global function for deleting a modal from the queue
2589 */
2590 sweetAlert.deleteQueueStep = function (index) {
2591 if (typeof queue[index] !== 'undefined') {
2592 queue.splice(index, 1);
2593 }
2594 };
2595
2596 /*
2597 * Global function to close sweetAlert
2598 */
2599 sweetAlert.close = sweetAlert.closeModal = function (onComplete) {
2600 var container = getContainer();
2601 var modal = getModal();
2602 if (!modal) {
2603 return;
2604 }
2605 removeClass(modal, swalClasses.show);
2606 addClass(modal, swalClasses.hide);
2607 clearTimeout(modal.timeout);
2608
2609 resetPrevState();
2610
2611 var removeModalAndResetState = function removeModalAndResetState() {
2612 if (container.parentNode) {
2613 container.parentNode.removeChild(container);
2614 }
2615 removeClass(document.documentElement, swalClasses.shown);
2616 removeClass(document.body, swalClasses.shown);
2617 undoScrollbar();
2618 undoIOSfix();
2619 };
2620
2621 // If animation is supported, animate
2622 if (animationEndEvent && !hasClass(modal, swalClasses.noanimation)) {
2623 modal.addEventListener(animationEndEvent, function swalCloseEventFinished() {
2624 modal.removeEventListener(animationEndEvent, swalCloseEventFinished);
2625 if (hasClass(modal, swalClasses.hide)) {
2626 removeModalAndResetState();
2627 }
2628 });
2629 } else {
2630 // Otherwise, remove immediately
2631 removeModalAndResetState();
2632 }
2633 if (onComplete !== null && typeof onComplete === 'function') {
2634 setTimeout(function () {
2635 onComplete(modal);
2636 });
2637 }
2638 };
2639
2640 /*
2641 * Global function to click 'Confirm' button
2642 */
2643 sweetAlert.clickConfirm = function () {
2644 return getConfirmButton().click();
2645 };
2646
2647 /*
2648 * Global function to click 'Cancel' button
2649 */
2650 sweetAlert.clickCancel = function () {
2651 return getCancelButton().click();
2652 };
2653
2654 /**
2655 * Show spinner instead of Confirm button and disable Cancel button
2656 */
2657 sweetAlert.showLoading = sweetAlert.enableLoading = function () {
2658 var modal = getModal();
2659 if (!modal) {
2660 sweetAlert('');
2661 }
2662 var buttonsWrapper = getButtonsWrapper();
2663 var confirmButton = getConfirmButton();
2664 var cancelButton = getCancelButton();
2665
2666 show(buttonsWrapper);
2667 show(confirmButton, 'inline-block');
2668 addClass(buttonsWrapper, swalClasses.loading);
2669 addClass(modal, swalClasses.loading);
2670 confirmButton.disabled = true;
2671 cancelButton.disabled = true;
2672 };
2673
2674 /**
2675 * Set default params for each popup
2676 * @param {Object} userParams
2677 */
2678 sweetAlert.setDefaults = function (userParams) {
2679 if (!userParams || (typeof userParams === 'undefined' ? 'undefined' : _typeof(userParams)) !== 'object') {
2680 return console.error('SweetAlert2: the argument for setDefaults() is required and has to be a object');
2681 }
2682
2683 for (var param in userParams) {
2684 if (!defaultParams.hasOwnProperty(param) && param !== 'extraParams') {
2685 console.warn('SweetAlert2: Unknown parameter "' + param + '"');
2686 delete userParams[param];
2687 }
2688 }
2689
2690 _extends(modalParams, userParams);
2691 };
2692
2693 /**
2694 * Reset default params for each popup
2695 */
2696 sweetAlert.resetDefaults = function () {
2697 modalParams = _extends({}, defaultParams);
2698 };
2699
2700 sweetAlert.noop = function () {};
2701
2702 sweetAlert.version = '6.6.4';
2703
2704 sweetAlert.default = sweetAlert;
2705
2706 return sweetAlert;
2707
2708 })));
2709 if (window.Sweetalert2) window.sweetAlert = window.swal = window.Sweetalert2;
2710
2711 /* assets/wpuf/js/jquery-ui-timepicker-addon.js */
2712 /*
2713 * jQuery timepicker addon
2714 * By: Trent Richardson [http://trentrichardson.com]
2715 * Version 1.2
2716 * Last Modified: 02/02/2013
2717 *
2718 * Copyright 2013 Trent Richardson
2719 * You may use this project under MIT or GPL licenses.
2720 * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
2721 * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
2722 */
2723
2724 /*jslint evil: true, white: false, undef: false, nomen: false */
2725
2726 (function($) {
2727
2728 /*
2729 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
2730 */
2731 $.ui.timepicker = $.ui.timepicker || {};
2732 if ($.ui.timepicker.version) {
2733 return;
2734 }
2735
2736 /*
2737 * Extend jQueryUI, get it started with our version number
2738 */
2739 $.extend($.ui, {
2740 timepicker: {
2741 version: "1.2"
2742 }
2743 });
2744
2745 /*
2746 * Timepicker manager.
2747 * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
2748 * Settings for (groups of) time pickers are maintained in an instance object,
2749 * allowing multiple different settings on the same page.
2750 */
2751 var Timepicker = function() {
2752 this.regional = []; // Available regional settings, indexed by language code
2753 this.regional[''] = { // Default regional settings
2754 currentText: 'Now',
2755 closeText: 'Done',
2756 amNames: ['AM', 'A'],
2757 pmNames: ['PM', 'P'],
2758 timeFormat: 'HH:mm',
2759 timeSuffix: '',
2760 timeOnlyTitle: 'Choose Time',
2761 timeText: 'Time',
2762 hourText: 'Hour',
2763 minuteText: 'Minute',
2764 secondText: 'Second',
2765 millisecText: 'Millisecond',
2766 timezoneText: 'Time Zone',
2767 isRTL: false
2768 };
2769 this._defaults = { // Global defaults for all the datetime picker instances
2770 showButtonPanel: true,
2771 timeOnly: false,
2772 showHour: true,
2773 showMinute: true,
2774 showSecond: false,
2775 showMillisec: false,
2776 showTimezone: false,
2777 showTime: true,
2778 stepHour: 1,
2779 stepMinute: 1,
2780 stepSecond: 1,
2781 stepMillisec: 1,
2782 hour: 0,
2783 minute: 0,
2784 second: 0,
2785 millisec: 0,
2786 timezone: null,
2787 useLocalTimezone: false,
2788 defaultTimezone: "+0000",
2789 hourMin: 0,
2790 minuteMin: 0,
2791 secondMin: 0,
2792 millisecMin: 0,
2793 hourMax: 23,
2794 minuteMax: 59,
2795 secondMax: 59,
2796 millisecMax: 999,
2797 minDateTime: null,
2798 maxDateTime: null,
2799 onSelect: null,
2800 hourGrid: 0,
2801 minuteGrid: 0,
2802 secondGrid: 0,
2803 millisecGrid: 0,
2804 alwaysSetTime: true,
2805 separator: ' ',
2806 altFieldTimeOnly: true,
2807 altTimeFormat: null,
2808 altSeparator: null,
2809 altTimeSuffix: null,
2810 pickerTimeFormat: null,
2811 pickerTimeSuffix: null,
2812 showTimepicker: true,
2813 timezoneIso8601: false,
2814 timezoneList: null,
2815 addSliderAccess: false,
2816 sliderAccessArgs: null,
2817 controlType: 'slider',
2818 defaultValue: null,
2819 parse: 'strict'
2820 };
2821 $.extend(this._defaults, this.regional['']);
2822 };
2823
2824 $.extend(Timepicker.prototype, {
2825 $input: null,
2826 $altInput: null,
2827 $timeObj: null,
2828 inst: null,
2829 hour_slider: null,
2830 minute_slider: null,
2831 second_slider: null,
2832 millisec_slider: null,
2833 timezone_select: null,
2834 hour: 0,
2835 minute: 0,
2836 second: 0,
2837 millisec: 0,
2838 timezone: null,
2839 defaultTimezone: "+0000",
2840 hourMinOriginal: null,
2841 minuteMinOriginal: null,
2842 secondMinOriginal: null,
2843 millisecMinOriginal: null,
2844 hourMaxOriginal: null,
2845 minuteMaxOriginal: null,
2846 secondMaxOriginal: null,
2847 millisecMaxOriginal: null,
2848 ampm: '',
2849 formattedDate: '',
2850 formattedTime: '',
2851 formattedDateTime: '',
2852 timezoneList: null,
2853 units: ['hour','minute','second','millisec'],
2854 control: null,
2855
2856 /*
2857 * Override the default settings for all instances of the time picker.
2858 * @param settings object - the new settings to use as defaults (anonymous object)
2859 * @return the manager object
2860 */
2861 setDefaults: function(settings) {
2862 extendRemove(this._defaults, settings || {});
2863 return this;
2864 },
2865
2866 /*
2867 * Create a new Timepicker instance
2868 */
2869 _newInst: function($input, o) {
2870 var tp_inst = new Timepicker(),
2871 inlineSettings = {},
2872 fns = {},
2873 overrides, i;
2874
2875 for (var attrName in this._defaults) {
2876 if(this._defaults.hasOwnProperty(attrName)){
2877 var attrValue = $input.attr('time:' + attrName);
2878 if (attrValue) {
2879 try {
2880 inlineSettings[attrName] = eval(attrValue);
2881 } catch (err) {
2882 inlineSettings[attrName] = attrValue;
2883 }
2884 }
2885 }
2886 }
2887 overrides = {
2888 beforeShow: function (input, dp_inst) {
2889 if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
2890 return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
2891 }
2892 },
2893 onChangeMonthYear: function (year, month, dp_inst) {
2894 // Update the time as well : this prevents the time from disappearing from the $input field.
2895 tp_inst._updateDateTime(dp_inst);
2896 if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
2897 tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
2898 }
2899 },
2900 onClose: function (dateText, dp_inst) {
2901 if (tp_inst.timeDefined === true && $input.val() !== '') {
2902 tp_inst._updateDateTime(dp_inst);
2903 }
2904 if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
2905 tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
2906 }
2907 }
2908 };
2909 for (i in overrides) {
2910 if (overrides.hasOwnProperty(i)) {
2911 fns[i] = o[i] || null;
2912 }
2913 }
2914 tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, {
2915 evnts:fns,
2916 timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
2917 });
2918 tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) {
2919 return val.toUpperCase();
2920 });
2921 tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) {
2922 return val.toUpperCase();
2923 });
2924
2925 // controlType is string - key to our this._controls
2926 if(typeof(tp_inst._defaults.controlType) === 'string'){
2927 if($.fn[tp_inst._defaults.controlType] === undefined){
2928 tp_inst._defaults.controlType = 'select';
2929 }
2930 tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
2931 }
2932 // controlType is an object and must implement create, options, value methods
2933 else{
2934 tp_inst.control = tp_inst._defaults.controlType;
2935 }
2936
2937 if (tp_inst._defaults.timezoneList === null) {
2938 var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000',
2939 '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930',
2940 '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400'];
2941
2942 if (tp_inst._defaults.timezoneIso8601) {
2943 timezoneList = $.map(timezoneList, function(val) {
2944 return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
2945 });
2946 }
2947 tp_inst._defaults.timezoneList = timezoneList;
2948 }
2949
2950 tp_inst.timezone = tp_inst._defaults.timezone;
2951 tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin? tp_inst._defaults.hourMin :
2952 tp_inst._defaults.hour > tp_inst._defaults.hourMax? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
2953 tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin? tp_inst._defaults.minuteMin :
2954 tp_inst._defaults.minute > tp_inst._defaults.minuteMax? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
2955 tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin? tp_inst._defaults.secondMin :
2956 tp_inst._defaults.second > tp_inst._defaults.secondMax? tp_inst._defaults.secondMax : tp_inst._defaults.second;
2957 tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin? tp_inst._defaults.millisecMin :
2958 tp_inst._defaults.millisec > tp_inst._defaults.millisecMax? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
2959 tp_inst.ampm = '';
2960 tp_inst.$input = $input;
2961
2962 if (o.altField) {
2963 tp_inst.$altInput = $(o.altField).css({
2964 cursor: 'pointer'
2965 }).focus(function() {
2966 $input.trigger("focus");
2967 });
2968 }
2969
2970 if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
2971 tp_inst._defaults.minDate = new Date();
2972 }
2973 if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
2974 tp_inst._defaults.maxDate = new Date();
2975 }
2976
2977 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
2978 if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
2979 tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
2980 }
2981 if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
2982 tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
2983 }
2984 if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
2985 tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
2986 }
2987 if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
2988 tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
2989 }
2990 tp_inst.$input.bind('focus', function() {
2991 tp_inst._onFocus();
2992 });
2993
2994 return tp_inst;
2995 },
2996
2997 /*
2998 * add our sliders to the calendar
2999 */
3000 _addTimePicker: function(dp_inst) {
3001 var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
3002
3003 this.timeDefined = this._parseTime(currDT);
3004 this._limitMinMaxDateTime(dp_inst, false);
3005 this._injectTimePicker();
3006 },
3007
3008 /*
3009 * parse the time string from input value or _setTime
3010 */
3011 _parseTime: function(timeString, withDate) {
3012 if (!this.inst) {
3013 this.inst = $.datepicker._getInst(this.$input[0]);
3014 }
3015
3016 if (withDate || !this._defaults.timeOnly) {
3017 var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
3018 try {
3019 var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
3020 if (!parseRes.timeObj) {
3021 return false;
3022 }
3023 $.extend(this, parseRes.timeObj);
3024 } catch (err) {
3025 $.timepicker.log("Error parsing the date/time string: " + err +
3026 "\ndate/time string = " + timeString +
3027 "\ntimeFormat = " + this._defaults.timeFormat +
3028 "\ndateFormat = " + dp_dateFormat);
3029 return false;
3030 }
3031 return true;
3032 } else {
3033 var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
3034 if (!timeObj) {
3035 return false;
3036 }
3037 $.extend(this, timeObj);
3038 return true;
3039 }
3040 },
3041
3042 /*
3043 * generate and inject html for timepicker into ui datepicker
3044 */
3045 _injectTimePicker: function() {
3046 var $dp = this.inst.dpDiv,
3047 o = this.inst.settings,
3048 tp_inst = this,
3049 litem = '',
3050 uitem = '',
3051 max = {},
3052 gridSize = {},
3053 size = null;
3054
3055 // Prevent displaying twice
3056 if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
3057 var noDisplay = ' style="display:none;"',
3058 html = '<div class="ui-timepicker-div'+ (o.isRTL? ' ui-timepicker-rtl' : '') +'"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
3059 '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
3060
3061 // Create the markup
3062 for(var i=0,l=this.units.length; i<l; i++){
3063 litem = this.units[i];
3064 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1);
3065 // Added by Peter Medeiros:
3066 // - Figure out what the hour/minute/second max should be based on the step values.
3067 // - Example: if stepMinute is 15, then minMax is 45.
3068 max[litem] = parseInt((o[litem+'Max'] - ((o[litem+'Max'] - o[litem+'Min']) % o['step'+uitem])), 10);
3069 gridSize[litem] = 0;
3070
3071 html += '<dt class="ui_tpicker_'+ litem +'_label"' + ((o['show'+uitem]) ? '' : noDisplay) + '>' + o[litem +'Text'] + '</dt>' +
3072 '<dd class="ui_tpicker_'+ litem +'"><div class="ui_tpicker_'+ litem +'_slider"' + ((o['show'+uitem]) ? '' : noDisplay) + '></div>';
3073
3074 if (o['show'+uitem] && o[litem+'Grid'] > 0) {
3075 html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
3076
3077 if(litem == 'hour'){
3078 for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) {
3079 gridSize[litem]++;
3080 var tmph = $.datepicker.formatTime(useAmpm(o.pickerTimeFormat || o.timeFormat)? 'hht':'HH', {hour:h}, o);
3081 html += '<td data-for="'+litem+'">' + tmph + '</td>';
3082 }
3083 }
3084 else{
3085 for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) {
3086 gridSize[litem]++;
3087 html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>';
3088 }
3089 }
3090
3091 html += '</tr></table></div>';
3092 }
3093 html += '</dd>';
3094 }
3095
3096 // Timezone
3097 html += '<dt class="ui_tpicker_timezone_label"' + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
3098 html += '<dd class="ui_tpicker_timezone" ' + ((o.showTimezone) ? '' : noDisplay) + '></dd>';
3099
3100 // Create the elements from string
3101 html += '</dl></div>';
3102 var $tp = $(html);
3103
3104 // if we only want time picker...
3105 if (o.timeOnly === true) {
3106 $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
3107 $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
3108 }
3109
3110 // add sliders, adjust grids, add events
3111 for(var i=0,l=tp_inst.units.length; i<l; i++){
3112 litem = tp_inst.units[i];
3113 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1);
3114
3115 // add the slider
3116 tp_inst[litem+'_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_'+litem+'_slider'), litem, tp_inst[litem], o[litem+'Min'], max[litem], o['step'+uitem]);
3117
3118 // adjust the grid and add click event
3119 if (o['show'+uitem] && o[litem+'Grid'] > 0) {
3120 size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']);
3121 $tp.find('.ui_tpicker_'+litem+' table').css({
3122 width: size + "%",
3123 marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"),
3124 marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0',
3125 borderCollapse: 'collapse'
3126 }).find("td").click(function(e){
3127 var $t = $(this),
3128 h = $t.html(),
3129 n = parseInt(h.replace(/[^0-9]/g),10),
3130 ap = h.replace(/[^apm]/ig),
3131 f = $t.data('for'); // loses scope, so we use data-for
3132
3133 if(f == 'hour'){
3134 if(ap.indexOf('p') !== -1 && n < 12){
3135 n += 12;
3136 }
3137 else{
3138 if(ap.indexOf('a') !== -1 && n === 12){
3139 n = 0;
3140 }
3141 }
3142 }
3143
3144 tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n);
3145
3146 tp_inst._onTimeChange();
3147 tp_inst._onSelectHandler();
3148 })
3149 .css({
3150 cursor: 'pointer',
3151 width: (100 / gridSize[litem]) + '%',
3152 textAlign: 'center',
3153 overflow: 'hidden'
3154 });
3155 } // end if grid > 0
3156 } // end for loop
3157
3158 // Add timezone options
3159 this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
3160 $.fn.append.apply(this.timezone_select,
3161 $.map(o.timezoneList, function(val, idx) {
3162 return $("<option />").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val);
3163 }));
3164 if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") {
3165 var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12);
3166 var local_timezone = $.timepicker.timeZoneOffsetString(local_date);
3167 if (local_timezone == this.timezone) {
3168 selectLocalTimeZone(tp_inst);
3169 } else {
3170 this.timezone_select.val(this.timezone);
3171 }
3172 } else {
3173 if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") {
3174 this.timezone_select.val(o.defaultTimezone);
3175 } else {
3176 selectLocalTimeZone(tp_inst);
3177 }
3178 }
3179 this.timezone_select.change(function() {
3180 tp_inst._defaults.useLocalTimezone = false;
3181 tp_inst._onTimeChange();
3182 tp_inst._onSelectHandler();
3183 });
3184 // End timezone options
3185
3186 // inject timepicker into datepicker
3187 var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
3188 if ($buttonPanel.length) {
3189 $buttonPanel.before($tp);
3190 } else {
3191 $dp.append($tp);
3192 }
3193
3194 this.$timeObj = $tp.find('.ui_tpicker_time');
3195
3196 if (this.inst !== null) {
3197 var timeDefined = this.timeDefined;
3198 this._onTimeChange();
3199 this.timeDefined = timeDefined;
3200 }
3201
3202 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
3203 if (this._defaults.addSliderAccess) {
3204 var sliderAccessArgs = this._defaults.sliderAccessArgs,
3205 rtl = this._defaults.isRTL;
3206 sliderAccessArgs.isRTL = rtl;
3207
3208 setTimeout(function() { // fix for inline mode
3209 if ($tp.find('.ui-slider-access').length === 0) {
3210 $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
3211
3212 // fix any grids since sliders are shorter
3213 var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
3214 if (sliderAccessWidth) {
3215 $tp.find('table:visible').each(function() {
3216 var $g = $(this),
3217 oldWidth = $g.outerWidth(),
3218 oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''),
3219 newWidth = oldWidth - sliderAccessWidth,
3220 newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
3221 css = { width: newWidth, marginRight: 0, marginLeft: 0 };
3222 css[rtl? 'marginRight':'marginLeft'] = newMarginLeft;
3223 $g.css(css);
3224 });
3225 }
3226 }
3227 }, 10);
3228 }
3229 // end slideAccess integration
3230
3231 }
3232 },
3233
3234 /*
3235 * This function tries to limit the ability to go outside the
3236 * min/max date range
3237 */
3238 _limitMinMaxDateTime: function(dp_inst, adjustSliders) {
3239 var o = this._defaults,
3240 dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
3241
3242 if (!this._defaults.showTimepicker) {
3243 return;
3244 } // No time so nothing to check here
3245
3246 if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
3247 var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
3248 minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
3249
3250 if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) {
3251 this.hourMinOriginal = o.hourMin;
3252 this.minuteMinOriginal = o.minuteMin;
3253 this.secondMinOriginal = o.secondMin;
3254 this.millisecMinOriginal = o.millisecMin;
3255 }
3256
3257 if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
3258 this._defaults.hourMin = minDateTime.getHours();
3259 if (this.hour <= this._defaults.hourMin) {
3260 this.hour = this._defaults.hourMin;
3261 this._defaults.minuteMin = minDateTime.getMinutes();
3262 if (this.minute <= this._defaults.minuteMin) {
3263 this.minute = this._defaults.minuteMin;
3264 this._defaults.secondMin = minDateTime.getSeconds();
3265 if (this.second <= this._defaults.secondMin) {
3266 this.second = this._defaults.secondMin;
3267 this._defaults.millisecMin = minDateTime.getMilliseconds();
3268 } else {
3269 if (this.millisec < this._defaults.millisecMin) {
3270 this.millisec = this._defaults.millisecMin;
3271 }
3272 this._defaults.millisecMin = this.millisecMinOriginal;
3273 }
3274 } else {
3275 this._defaults.secondMin = this.secondMinOriginal;
3276 this._defaults.millisecMin = this.millisecMinOriginal;
3277 }
3278 } else {
3279 this._defaults.minuteMin = this.minuteMinOriginal;
3280 this._defaults.secondMin = this.secondMinOriginal;
3281 this._defaults.millisecMin = this.millisecMinOriginal;
3282 }
3283 } else {
3284 this._defaults.hourMin = this.hourMinOriginal;
3285 this._defaults.minuteMin = this.minuteMinOriginal;
3286 this._defaults.secondMin = this.secondMinOriginal;
3287 this._defaults.millisecMin = this.millisecMinOriginal;
3288 }
3289 }
3290
3291 if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
3292 var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
3293 maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
3294
3295 if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) {
3296 this.hourMaxOriginal = o.hourMax;
3297 this.minuteMaxOriginal = o.minuteMax;
3298 this.secondMaxOriginal = o.secondMax;
3299 this.millisecMaxOriginal = o.millisecMax;
3300 }
3301
3302 if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) {
3303 this._defaults.hourMax = maxDateTime.getHours();
3304 if (this.hour >= this._defaults.hourMax) {
3305 this.hour = this._defaults.hourMax;
3306 this._defaults.minuteMax = maxDateTime.getMinutes();
3307 if (this.minute >= this._defaults.minuteMax) {
3308 this.minute = this._defaults.minuteMax;
3309 this._defaults.secondMax = maxDateTime.getSeconds();
3310 if (this.second >= this._defaults.secondMax) {
3311 this.second = this._defaults.secondMax;
3312 this._defaults.millisecMax = maxDateTime.getMilliseconds();
3313 } else {
3314 if (this.millisec > this._defaults.millisecMax) {
3315 this.millisec = this._defaults.millisecMax;
3316 }
3317 this._defaults.millisecMax = this.millisecMaxOriginal;
3318 }
3319 } else {
3320 this._defaults.secondMax = this.secondMaxOriginal;
3321 this._defaults.millisecMax = this.millisecMaxOriginal;
3322 }
3323 } else {
3324 this._defaults.minuteMax = this.minuteMaxOriginal;
3325 this._defaults.secondMax = this.secondMaxOriginal;
3326 this._defaults.millisecMax = this.millisecMaxOriginal;
3327 }
3328 } else {
3329 this._defaults.hourMax = this.hourMaxOriginal;
3330 this._defaults.minuteMax = this.minuteMaxOriginal;
3331 this._defaults.secondMax = this.secondMaxOriginal;
3332 this._defaults.millisecMax = this.millisecMaxOriginal;
3333 }
3334 }
3335
3336 if (adjustSliders !== undefined && adjustSliders === true) {
3337 var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
3338 minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
3339 secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
3340 millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10);
3341
3342 if (this.hour_slider) {
3343 this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax });
3344 this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
3345 }
3346 if (this.minute_slider) {
3347 this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax });
3348 this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
3349 }
3350 if (this.second_slider) {
3351 this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax });
3352 this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
3353 }
3354 if (this.millisec_slider) {
3355 this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax });
3356 this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
3357 }
3358 }
3359
3360 },
3361
3362 /*
3363 * when a slider moves, set the internal time...
3364 * on time change is also called when the time is updated in the text field
3365 */
3366 _onTimeChange: function() {
3367 var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
3368 minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
3369 second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
3370 millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
3371 timezone = (this.timezone_select) ? this.timezone_select.val() : false,
3372 o = this._defaults,
3373 pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
3374 pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
3375
3376 if (typeof(hour) == 'object') {
3377 hour = false;
3378 }
3379 if (typeof(minute) == 'object') {
3380 minute = false;
3381 }
3382 if (typeof(second) == 'object') {
3383 second = false;
3384 }
3385 if (typeof(millisec) == 'object') {
3386 millisec = false;
3387 }
3388 if (typeof(timezone) == 'object') {
3389 timezone = false;
3390 }
3391
3392 if (hour !== false) {
3393 hour = parseInt(hour, 10);
3394 }
3395 if (minute !== false) {
3396 minute = parseInt(minute, 10);
3397 }
3398 if (second !== false) {
3399 second = parseInt(second, 10);
3400 }
3401 if (millisec !== false) {
3402 millisec = parseInt(millisec, 10);
3403 }
3404
3405 var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
3406
3407 // If the update was done in the input field, the input field should not be updated.
3408 // If the update was done using the sliders, update the input field.
3409 var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec
3410 || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
3411 || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone)));
3412
3413 if (hasChanged) {
3414
3415 if (hour !== false) {
3416 this.hour = hour;
3417 }
3418 if (minute !== false) {
3419 this.minute = minute;
3420 }
3421 if (second !== false) {
3422 this.second = second;
3423 }
3424 if (millisec !== false) {
3425 this.millisec = millisec;
3426 }
3427 if (timezone !== false) {
3428 this.timezone = timezone;
3429 }
3430
3431 if (!this.inst) {
3432 this.inst = $.datepicker._getInst(this.$input[0]);
3433 }
3434
3435 this._limitMinMaxDateTime(this.inst, true);
3436 }
3437 if (useAmpm(o.timeFormat)) {
3438 this.ampm = ampm;
3439 }
3440
3441 // Updates the time within the timepicker
3442 this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
3443 if (this.$timeObj) {
3444 if(pickerTimeFormat === o.timeFormat){
3445 this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
3446 }
3447 else{
3448 this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
3449 }
3450 }
3451
3452 this.timeDefined = true;
3453 if (hasChanged) {
3454 this._updateDateTime();
3455 }
3456 },
3457
3458 /*
3459 * call custom onSelect.
3460 * bind to sliders slidestop, and grid click.
3461 */
3462 _onSelectHandler: function() {
3463 var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
3464 var inputEl = this.$input ? this.$input[0] : null;
3465 if (onSelect && inputEl) {
3466 onSelect.apply(inputEl, [this.formattedDateTime, this]);
3467 }
3468 },
3469
3470 /*
3471 * update our input with the new date time..
3472 */
3473 _updateDateTime: function(dp_inst) {
3474 dp_inst = this.inst || dp_inst;
3475 var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
3476 dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
3477 formatCfg = $.datepicker._getFormatConfig(dp_inst),
3478 timeAvailable = dt !== null && this.timeDefined;
3479 this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
3480 var formattedDateTime = this.formattedDate;
3481
3482 // if a slider was changed but datepicker doesn't have a value yet, set it
3483 if(dp_inst.lastVal==""){
3484 dp_inst.currentYear=dp_inst.selectedYear;
3485 dp_inst.currentMonth=dp_inst.selectedMonth;
3486 dp_inst.currentDay=dp_inst.selectedDay;
3487 }
3488
3489 /*
3490 * remove following lines to force every changes in date picker to change the input value
3491 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
3492 * If the user manually empty the value in the input field, the date picker will never change selected value.
3493 */
3494 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
3495 // return;
3496 //}
3497
3498 if (this._defaults.timeOnly === true) {
3499 formattedDateTime = this.formattedTime;
3500 } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
3501 formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
3502 }
3503
3504 this.formattedDateTime = formattedDateTime;
3505
3506 if (!this._defaults.showTimepicker) {
3507 this.$input.val(this.formattedDate);
3508 } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
3509 this.$altInput.val(this.formattedTime);
3510 this.$input.val(this.formattedDate);
3511 } else if (this.$altInput) {
3512 this.$input.val(formattedDateTime);
3513 var altFormattedDateTime = '',
3514 altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator,
3515 altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
3516
3517 if (this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
3518 else altFormattedDateTime = this.formattedDate;
3519 if (altFormattedDateTime) altFormattedDateTime += altSeparator;
3520 if (this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
3521 else altFormattedDateTime += this.formattedTime + altTimeSuffix;
3522 this.$altInput.val(altFormattedDateTime);
3523 } else {
3524 this.$input.val(formattedDateTime);
3525 }
3526
3527 this.$input.trigger("change");
3528 },
3529
3530 _onFocus: function() {
3531 if (!this.$input.val() && this._defaults.defaultValue) {
3532 this.$input.val(this._defaults.defaultValue);
3533 var inst = $.datepicker._getInst(this.$input.get(0)),
3534 tp_inst = $.datepicker._get(inst, 'timepicker');
3535 if (tp_inst) {
3536 if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
3537 try {
3538 $.datepicker._updateDatepicker(inst);
3539 } catch (err) {
3540 $.timepicker.log(err);
3541 }
3542 }
3543 }
3544 }
3545 },
3546
3547 /*
3548 * Small abstraction to control types
3549 * We can add more, just be sure to follow the pattern: create, options, value
3550 */
3551 _controls: {
3552 // slider methods
3553 slider: {
3554 create: function(tp_inst, obj, unit, val, min, max, step){
3555 var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
3556 return obj.prop('slide', null).slider({
3557 orientation: "horizontal",
3558 value: rtl? val*-1 : val,
3559 min: rtl? max*-1 : min,
3560 max: rtl? min*-1 : max,
3561 step: step,
3562 slide: function(event, ui) {
3563 tp_inst.control.value(tp_inst, $(this), unit, rtl? ui.value*-1:ui.value);
3564 tp_inst._onTimeChange();
3565 },
3566 stop: function(event, ui) {
3567 tp_inst._onSelectHandler();
3568 }
3569 });
3570 },
3571 options: function(tp_inst, obj, unit, opts, val){
3572 if(tp_inst._defaults.isRTL){
3573 if(typeof(opts) == 'string'){
3574 if(opts == 'min' || opts == 'max'){
3575 if(val !== undefined)
3576 return obj.slider(opts, val*-1);
3577 return Math.abs(obj.slider(opts));
3578 }
3579 return obj.slider(opts);
3580 }
3581 var min = opts.min,
3582 max = opts.max;
3583 opts.min = opts.max = null;
3584 if(min !== undefined)
3585 opts.max = min * -1;
3586 if(max !== undefined)
3587 opts.min = max * -1;
3588 return obj.slider(opts);
3589 }
3590 if(typeof(opts) == 'string' && val !== undefined)
3591 return obj.slider(opts, val);
3592 return obj.slider(opts);
3593 },
3594 value: function(tp_inst, obj, unit, val){
3595 if(tp_inst._defaults.isRTL){
3596 if(val !== undefined)
3597 return obj.slider('value', val*-1);
3598 return Math.abs(obj.slider('value'));
3599 }
3600 if(val !== undefined)
3601 return obj.slider('value', val);
3602 return obj.slider('value');
3603 }
3604 },
3605 // select methods
3606 select: {
3607 create: function(tp_inst, obj, unit, val, min, max, step){
3608 var sel = '<select class="ui-timepicker-select" data-unit="'+ unit +'" data-min="'+ min +'" data-max="'+ max +'" data-step="'+ step +'">',
3609 ul = tp_inst._defaults.timeFormat.indexOf('t') !== -1? 'toLowerCase':'toUpperCase',
3610 m = 0;
3611
3612 for(var i=min; i<=max; i+=step){
3613 sel += '<option value="'+ i +'"'+ (i==val? ' selected':'') +'>';
3614 if(unit == 'hour' && useAmpm(tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat))
3615 sel += $.datepicker.formatTime("hh TT", {hour:i}, tp_inst._defaults);
3616 else if(unit == 'millisec' || i >= 10) sel += i;
3617 else sel += '0'+ i.toString();
3618 sel += '</option>';
3619 }
3620 sel += '</select>';
3621
3622 obj.children('select').remove();
3623
3624 $(sel).appendTo(obj).change(function(e){
3625 tp_inst._onTimeChange();
3626 tp_inst._onSelectHandler();
3627 });
3628
3629 return obj;
3630 },
3631 options: function(tp_inst, obj, unit, opts, val){
3632 var o = {},
3633 $t = obj.children('select');
3634 if(typeof(opts) == 'string'){
3635 if(val === undefined)
3636 return $t.data(opts);
3637 o[opts] = val;
3638 }
3639 else o = opts;
3640 return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
3641 },
3642 value: function(tp_inst, obj, unit, val){
3643 var $t = obj.children('select');
3644 if(val !== undefined)
3645 return $t.val(val);
3646 return $t.val();
3647 }
3648 }
3649 } // end _controls
3650
3651 });
3652
3653 $.fn.extend({
3654 /*
3655 * shorthand just to use timepicker..
3656 */
3657 timepicker: function(o) {
3658 o = o || {};
3659 var tmp_args = Array.prototype.slice.call(arguments);
3660
3661 if (typeof o == 'object') {
3662 tmp_args[0] = $.extend(o, {
3663 timeOnly: true
3664 });
3665 }
3666
3667 return $(this).each(function() {
3668 $.fn.datetimepicker.apply($(this), tmp_args);
3669 });
3670 },
3671
3672 /*
3673 * extend timepicker to datepicker
3674 */
3675 datetimepicker: function(o) {
3676 o = o || {};
3677 var tmp_args = arguments;
3678
3679 if (typeof(o) == 'string') {
3680 if (o == 'getDate') {
3681 return $.fn.datepicker.apply($(this[0]), tmp_args);
3682 } else {
3683 return this.each(function() {
3684 var $t = $(this);
3685 $t.datepicker.apply($t, tmp_args);
3686 });
3687 }
3688 } else {
3689 return this.each(function() {
3690 var $t = $(this);
3691 $t.datepicker($.timepicker._newInst($t, o)._defaults);
3692 });
3693 }
3694 }
3695 });
3696
3697 /*
3698 * Public Utility to parse date and time
3699 */
3700 $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
3701 var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
3702 if (parseRes.timeObj) {
3703 var t = parseRes.timeObj;
3704 parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
3705 }
3706
3707 return parseRes.date;
3708 };
3709
3710 /*
3711 * Public utility to parse time
3712 */
3713 $.datepicker.parseTime = function(timeFormat, timeString, options) {
3714 var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {});
3715
3716 // Strict parse requires the timeString to match the timeFormat exactly
3717 var strictParse = function(f, s, o){
3718
3719 // pattern for standard and localized AM/PM markers
3720 var getPatternAmpm = function(amNames, pmNames) {
3721 var markers = [];
3722 if (amNames) {
3723 $.merge(markers, amNames);
3724 }
3725 if (pmNames) {
3726 $.merge(markers, pmNames);
3727 }
3728 markers = $.map(markers, function(val) {
3729 return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
3730 });
3731 return '(' + markers.join('|') + ')?';
3732 };
3733
3734 // figure out position of time elements.. cause js cant do named captures
3735 var getFormatPositions = function(timeFormat) {
3736 var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g),
3737 orders = {
3738 h: -1,
3739 m: -1,
3740 s: -1,
3741 l: -1,
3742 t: -1,
3743 z: -1
3744 };
3745
3746 if (finds) {
3747 for (var i = 0; i < finds.length; i++) {
3748 if (orders[finds[i].toString().charAt(0)] == -1) {
3749 orders[finds[i].toString().charAt(0)] = i + 1;
3750 }
3751 }
3752 }
3753 return orders;
3754 };
3755
3756 var regstr = '^' + f.toString()
3757 .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) {
3758 var ml = match.length;
3759 switch (match.charAt(0).toLowerCase()) {
3760 case 'h': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
3761 case 'm': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
3762 case 's': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
3763 case 'l': return '(\\d?\\d?\\d)';
3764 case 'z': return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
3765 case 't': return getPatternAmpm(o.amNames, o.pmNames);
3766 default: // literal escaped in quotes
3767 return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
3768 }
3769 })
3770 .replace(/\s/g, '\\s?') +
3771 o.timeSuffix + '$',
3772 order = getFormatPositions(f),
3773 ampm = '',
3774 treg;
3775
3776 treg = s.match(new RegExp(regstr, 'i'));
3777
3778 var resTime = {
3779 hour: 0,
3780 minute: 0,
3781 second: 0,
3782 millisec: 0
3783 };
3784
3785 if (treg) {
3786 if (order.t !== -1) {
3787 if (treg[order.t] === undefined || treg[order.t].length === 0) {
3788 ampm = '';
3789 resTime.ampm = '';
3790 } else {
3791 ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
3792 resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
3793 }
3794 }
3795
3796 if (order.h !== -1) {
3797 if (ampm == 'AM' && treg[order.h] == '12') {
3798 resTime.hour = 0; // 12am = 0 hour
3799 } else {
3800 if (ampm == 'PM' && treg[order.h] != '12') {
3801 resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
3802 } else {
3803 resTime.hour = Number(treg[order.h]);
3804 }
3805 }
3806 }
3807
3808 if (order.m !== -1) {
3809 resTime.minute = Number(treg[order.m]);
3810 }
3811 if (order.s !== -1) {
3812 resTime.second = Number(treg[order.s]);
3813 }
3814 if (order.l !== -1) {
3815 resTime.millisec = Number(treg[order.l]);
3816 }
3817 if (order.z !== -1 && treg[order.z] !== undefined) {
3818 var tz = treg[order.z].toUpperCase();
3819 switch (tz.length) {
3820 case 1:
3821 // Z
3822 tz = o.timezoneIso8601 ? 'Z' : '+0000';
3823 break;
3824 case 5:
3825 // +hhmm
3826 if (o.timezoneIso8601) {
3827 tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3);
3828 }
3829 break;
3830 case 6:
3831 // +hh:mm
3832 if (!o.timezoneIso8601) {
3833 tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, '');
3834 } else {
3835 if (tz.substring(1) == '00:00') {
3836 tz = 'Z';
3837 }
3838 }
3839 break;
3840 }
3841 resTime.timezone = tz;
3842 }
3843
3844
3845 return resTime;
3846 }
3847 return false;
3848 };// end strictParse
3849
3850 // First try JS Date, if that fails, use strictParse
3851 var looseParse = function(f,s,o){
3852 try{
3853 var d = new Date('2012-01-01 '+ s);
3854 if(isNaN(d.getTime())){
3855 d = new Date('2012-01-01T'+ s);
3856 if(isNaN(d.getTime())){
3857 d = new Date('01/01/2012 '+ s);
3858 if(isNaN(d.getTime())){
3859 throw "Unable to parse time with native Date: "+ s;
3860 }
3861 }
3862 }
3863
3864 return {
3865 hour: d.getHours(),
3866 minute: d.getMinutes(),
3867 second: d.getSeconds(),
3868 millisec: d.getMilliseconds(),
3869 timezone: $.timepicker.timeZoneOffsetString(d)
3870 };
3871 }
3872 catch(err){
3873 try{
3874 return strictParse(f,s,o);
3875 }
3876 catch(err2){
3877 $.timepicker.log("Unable to parse \ntimeString: "+ s +"\ntimeFormat: "+ f);
3878 }
3879 }
3880 return false;
3881 }; // end looseParse
3882
3883 if(typeof o.parse === "function"){
3884 return o.parse(timeFormat, timeString, o)
3885 }
3886 if(o.parse === 'loose'){
3887 return looseParse(timeFormat, timeString, o);
3888 }
3889 return strictParse(timeFormat, timeString, o);
3890 };
3891
3892 /*
3893 * Public utility to format the time
3894 * format = string format of the time
3895 * time = a {}, not a Date() for timezones
3896 * options = essentially the regional[].. amNames, pmNames, ampm
3897 */
3898 $.datepicker.formatTime = function(format, time, options) {
3899 options = options || {};
3900 options = $.extend({}, $.timepicker._defaults, options);
3901 time = $.extend({
3902 hour: 0,
3903 minute: 0,
3904 second: 0,
3905 millisec: 0,
3906 timezone: '+0000'
3907 }, time);
3908
3909 var tmptime = format,
3910 ampmName = options.amNames[0],
3911 hour = parseInt(time.hour, 10);
3912
3913 if (hour > 11) {
3914 ampmName = options.pmNames[0];
3915 }
3916
3917 tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) {
3918 switch (match) {
3919 case 'HH':
3920 return ('0' + hour).slice(-2);
3921 case 'H':
3922 return hour;
3923 case 'hh':
3924 return ('0' + convert24to12(hour)).slice(-2);
3925 case 'h':
3926 return convert24to12(hour);
3927 case 'mm':
3928 return ('0' + time.minute).slice(-2);
3929 case 'm':
3930 return time.minute;
3931 case 'ss':
3932 return ('0' + time.second).slice(-2);
3933 case 's':
3934 return time.second;
3935 case 'l':
3936 return ('00' + time.millisec).slice(-3);
3937 case 'z':
3938 return time.timezone === null? options.defaultTimezone : time.timezone;
3939 case 'T':
3940 return ampmName.charAt(0).toUpperCase();
3941 case 'TT':
3942 return ampmName.toUpperCase();
3943 case 't':
3944 return ampmName.charAt(0).toLowerCase();
3945 case 'tt':
3946 return ampmName.toLowerCase();
3947 default:
3948 return match.replace(/\'/g, "") || "'";
3949 }
3950 });
3951
3952 tmptime = $.trim(tmptime);
3953 return tmptime;
3954 };
3955
3956 /*
3957 * the bad hack :/ override datepicker so it doesnt close on select
3958 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
3959 */
3960 $.datepicker._base_selectDate = $.datepicker._selectDate;
3961 $.datepicker._selectDate = function(id, dateStr) {
3962 var inst = this._getInst($(id)[0]),
3963 tp_inst = this._get(inst, 'timepicker');
3964
3965 if (tp_inst) {
3966 tp_inst._limitMinMaxDateTime(inst, true);
3967 inst.inline = inst.stay_open = true;
3968 //This way the onSelect handler called from calendarpicker get the full dateTime
3969 this._base_selectDate(id, dateStr);
3970 inst.inline = inst.stay_open = false;
3971 this._notifyChange(inst);
3972 this._updateDatepicker(inst);
3973 } else {
3974 this._base_selectDate(id, dateStr);
3975 }
3976 };
3977
3978 /*
3979 * second bad hack :/ override datepicker so it triggers an event when changing the input field
3980 * and does not redraw the datepicker on every selectDate event
3981 */
3982 $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
3983 $.datepicker._updateDatepicker = function(inst) {
3984
3985 // don't popup the datepicker if there is another instance already opened
3986 var input = inst.input[0];
3987 if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) {
3988 return;
3989 }
3990
3991 if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
3992
3993 this._base_updateDatepicker(inst);
3994
3995 // Reload the time control when changing something in the input text field.
3996 var tp_inst = this._get(inst, 'timepicker');
3997 if (tp_inst) {
3998 tp_inst._addTimePicker(inst);
3999
4000 // if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date.
4001 // var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12);
4002 // selectLocalTimeZone(tp_inst, date);
4003 // tp_inst._onTimeChange();
4004 // }
4005 }
4006 }
4007 };
4008
4009 /*
4010 * third bad hack :/ override datepicker so it allows spaces and colon in the input field
4011 */
4012 $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
4013 $.datepicker._doKeyPress = function(event) {
4014 var inst = $.datepicker._getInst(event.target),
4015 tp_inst = $.datepicker._get(inst, 'timepicker');
4016
4017 if (tp_inst) {
4018 if ($.datepicker._get(inst, 'constrainInput')) {
4019 var ampm = useAmpm(tp_inst._defaults.timeFormat),
4020 dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
4021 datetimeChars = tp_inst._defaults.timeFormat.toString()
4022 .replace(/[hms]/g, '')
4023 .replace(/TT/g, ampm ? 'APM' : '')
4024 .replace(/Tt/g, ampm ? 'AaPpMm' : '')
4025 .replace(/tT/g, ampm ? 'AaPpMm' : '')
4026 .replace(/T/g, ampm ? 'AP' : '')
4027 .replace(/tt/g, ampm ? 'apm' : '')
4028 .replace(/t/g, ampm ? 'ap' : '') +
4029 " " + tp_inst._defaults.separator +
4030 tp_inst._defaults.timeSuffix +
4031 (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
4032 (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
4033 dateChars,
4034 chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
4035 return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
4036 }
4037 }
4038
4039 return $.datepicker._base_doKeyPress(event);
4040 };
4041
4042 /*
4043 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
4044 */
4045 $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
4046 /* Update any alternate field to synchronise with the main field. */
4047 $.datepicker._updateAlternate = function(inst) {
4048 var tp_inst = this._get(inst, 'timepicker');
4049 if(tp_inst){
4050 var altField = tp_inst._defaults.altField;
4051 if (altField) { // update alternate field too
4052 var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
4053 date = this._getDate(inst),
4054 formatCfg = $.datepicker._getFormatConfig(inst),
4055 altFormattedDateTime = '',
4056 altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
4057 altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
4058 altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
4059
4060 altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
4061 if(!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null){
4062 if(tp_inst._defaults.altFormat)
4063 altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
4064 else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
4065 }
4066 $(altField).val(altFormattedDateTime);
4067 }
4068 }
4069 else{
4070 $.datepicker._base_updateAlternate(inst);
4071 }
4072 };
4073
4074 /*
4075 * Override key up event to sync manual input changes.
4076 */
4077 $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
4078 $.datepicker._doKeyUp = function(event) {
4079 var inst = $.datepicker._getInst(event.target),
4080 tp_inst = $.datepicker._get(inst, 'timepicker');
4081
4082 if (tp_inst) {
4083 if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
4084 try {
4085 $.datepicker._updateDatepicker(inst);
4086 } catch (err) {
4087 $.timepicker.log(err);
4088 }
4089 }
4090 }
4091
4092 return $.datepicker._base_doKeyUp(event);
4093 };
4094
4095 /*
4096 * override "Today" button to also grab the time.
4097 */
4098 $.datepicker._base_gotoToday = $.datepicker._gotoToday;
4099 $.datepicker._gotoToday = function(id) {
4100 var inst = this._getInst($(id)[0]),
4101 $dp = inst.dpDiv;
4102 this._base_gotoToday(id);
4103 var tp_inst = this._get(inst, 'timepicker');
4104 selectLocalTimeZone(tp_inst);
4105 var now = new Date();
4106 this._setTime(inst, now);
4107 $('.ui-datepicker-today', $dp).click();
4108 };
4109
4110 /*
4111 * Disable & enable the Time in the datetimepicker
4112 */
4113 $.datepicker._disableTimepickerDatepicker = function(target) {
4114 var inst = this._getInst(target);
4115 if (!inst) {
4116 return;
4117 }
4118
4119 var tp_inst = this._get(inst, 'timepicker');
4120 $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
4121 if (tp_inst) {
4122 tp_inst._defaults.showTimepicker = false;
4123 tp_inst._updateDateTime(inst);
4124 }
4125 };
4126
4127 $.datepicker._enableTimepickerDatepicker = function(target) {
4128 var inst = this._getInst(target);
4129 if (!inst) {
4130 return;
4131 }
4132
4133 var tp_inst = this._get(inst, 'timepicker');
4134 $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
4135 if (tp_inst) {
4136 tp_inst._defaults.showTimepicker = true;
4137 tp_inst._addTimePicker(inst); // Could be disabled on page load
4138 tp_inst._updateDateTime(inst);
4139 }
4140 };
4141
4142 /*
4143 * Create our own set time function
4144 */
4145 $.datepicker._setTime = function(inst, date) {
4146 var tp_inst = this._get(inst, 'timepicker');
4147 if (tp_inst) {
4148 var defaults = tp_inst._defaults;
4149
4150 // calling _setTime with no date sets time to defaults
4151 tp_inst.hour = date ? date.getHours() : defaults.hour;
4152 tp_inst.minute = date ? date.getMinutes() : defaults.minute;
4153 tp_inst.second = date ? date.getSeconds() : defaults.second;
4154 tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
4155
4156 //check if within min/max times..
4157 tp_inst._limitMinMaxDateTime(inst, true);
4158
4159 tp_inst._onTimeChange();
4160 tp_inst._updateDateTime(inst);
4161 }
4162 };
4163
4164 /*
4165 * Create new public method to set only time, callable as $().datepicker('setTime', date)
4166 */
4167 $.datepicker._setTimeDatepicker = function(target, date, withDate) {
4168 var inst = this._getInst(target);
4169 if (!inst) {
4170 return;
4171 }
4172
4173 var tp_inst = this._get(inst, 'timepicker');
4174
4175 if (tp_inst) {
4176 this._setDateFromField(inst);
4177 var tp_date;
4178 if (date) {
4179 if (typeof date == "string") {
4180 tp_inst._parseTime(date, withDate);
4181 tp_date = new Date();
4182 tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
4183 } else {
4184 tp_date = new Date(date.getTime());
4185 }
4186 if (tp_date.toString() == 'Invalid Date') {
4187 tp_date = undefined;
4188 }
4189 this._setTime(inst, tp_date);
4190 }
4191 }
4192
4193 };
4194
4195 /*
4196 * override setDate() to allow setting time too within Date object
4197 */
4198 $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
4199 $.datepicker._setDateDatepicker = function(target, date) {
4200 var inst = this._getInst(target);
4201 if (!inst) {
4202 return;
4203 }
4204
4205 var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
4206
4207 this._updateDatepicker(inst);
4208 this._base_setDateDatepicker.apply(this, arguments);
4209 this._setTimeDatepicker(target, tp_date, true);
4210 };
4211
4212 /*
4213 * override getDate() to allow getting time too within Date object
4214 */
4215 $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
4216 $.datepicker._getDateDatepicker = function(target, noDefault) {
4217 var inst = this._getInst(target);
4218 if (!inst) {
4219 return;
4220 }
4221
4222 var tp_inst = this._get(inst, 'timepicker');
4223
4224 if (tp_inst) {
4225 // if it hasn't yet been defined, grab from field
4226 if(inst.lastVal === undefined){
4227 this._setDateFromField(inst, noDefault);
4228 }
4229
4230 var date = this._getDate(inst);
4231 if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
4232 date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
4233 }
4234 return date;
4235 }
4236 return this._base_getDateDatepicker(target, noDefault);
4237 };
4238
4239 /*
4240 * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
4241 * An option in datapicker to ignore extra format characters would be nicer.
4242 */
4243 $.datepicker._base_parseDate = $.datepicker.parseDate;
4244 $.datepicker.parseDate = function(format, value, settings) {
4245 var date;
4246 try {
4247 date = this._base_parseDate(format, value, settings);
4248 } catch (err) {
4249 // Hack! The error message ends with a colon, a space, and
4250 // the "extra" characters. We rely on that instead of
4251 // attempting to perfectly reproduce the parsing algorithm.
4252 date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
4253 $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
4254 }
4255 return date;
4256 };
4257
4258 /*
4259 * override formatDate to set date with time to the input
4260 */
4261 $.datepicker._base_formatDate = $.datepicker._formatDate;
4262 $.datepicker._formatDate = function(inst, day, month, year) {
4263 var tp_inst = this._get(inst, 'timepicker');
4264 if (tp_inst) {
4265 tp_inst._updateDateTime(inst);
4266 return tp_inst.$input.val();
4267 }
4268 return this._base_formatDate(inst);
4269 };
4270
4271 /*
4272 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
4273 */
4274 $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
4275 $.datepicker._optionDatepicker = function(target, name, value) {
4276 var inst = this._getInst(target),
4277 name_clone;
4278 if (!inst) {
4279 return null;
4280 }
4281
4282 var tp_inst = this._get(inst, 'timepicker');
4283 if (tp_inst) {
4284 var min = null,
4285 max = null,
4286 onselect = null,
4287 overrides = tp_inst._defaults.evnts,
4288 fns = {},
4289 prop;
4290 if (typeof name == 'string') { // if min/max was set with the string
4291 if (name === 'minDate' || name === 'minDateTime') {
4292 min = value;
4293 } else if (name === 'maxDate' || name === 'maxDateTime') {
4294 max = value;
4295 } else if (name === 'onSelect') {
4296 onselect = value;
4297 } else if (overrides.hasOwnProperty(name)) {
4298 if (typeof (value) === 'undefined') {
4299 return overrides[name];
4300 }
4301 fns[name] = value;
4302 name_clone = {}; //empty results in exiting function after overrides updated
4303 }
4304 } else if (typeof name == 'object') { //if min/max was set with the JSON
4305 if (name.minDate) {
4306 min = name.minDate;
4307 } else if (name.minDateTime) {
4308 min = name.minDateTime;
4309 } else if (name.maxDate) {
4310 max = name.maxDate;
4311 } else if (name.maxDateTime) {
4312 max = name.maxDateTime;
4313 }
4314 for (prop in overrides) {
4315 if (overrides.hasOwnProperty(prop) && name[prop]) {
4316 fns[prop] = name[prop];
4317 }
4318 }
4319 }
4320 for (prop in fns) {
4321 if (fns.hasOwnProperty(prop)) {
4322 overrides[prop] = fns[prop];
4323 if (!name_clone) { name_clone = $.extend({}, name);}
4324 delete name_clone[prop];
4325 }
4326 }
4327 if (name_clone && isEmptyObject(name_clone)) { return; }
4328 if (min) { //if min was set
4329 if (min === 0) {
4330 min = new Date();
4331 } else {
4332 min = new Date(min);
4333 }
4334 tp_inst._defaults.minDate = min;
4335 tp_inst._defaults.minDateTime = min;
4336 } else if (max) { //if max was set
4337 if (max === 0) {
4338 max = new Date();
4339 } else {
4340 max = new Date(max);
4341 }
4342 tp_inst._defaults.maxDate = max;
4343 tp_inst._defaults.maxDateTime = max;
4344 } else if (onselect) {
4345 tp_inst._defaults.onSelect = onselect;
4346 }
4347 }
4348 if (value === undefined) {
4349 return this._base_optionDatepicker.call($.datepicker, target, name);
4350 }
4351 return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
4352 };
4353 /*
4354 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
4355 * it will return false for all objects
4356 */
4357 var isEmptyObject = function(obj) {
4358 var prop;
4359 for (prop in obj) {
4360 if (obj.hasOwnProperty(obj)) {
4361 return false;
4362 }
4363 }
4364 return true;
4365 };
4366
4367 /*
4368 * jQuery extend now ignores nulls!
4369 */
4370 var extendRemove = function(target, props) {
4371 $.extend(target, props);
4372 for (var name in props) {
4373 if (props[name] === null || props[name] === undefined) {
4374 target[name] = props[name];
4375 }
4376 }
4377 return target;
4378 };
4379
4380 /*
4381 * Determine by the time format if should use ampm
4382 * Returns true if should use ampm, false if not
4383 */
4384 var useAmpm = function(timeFormat){
4385 return (timeFormat.indexOf('t') !== -1 && timeFormat.indexOf('h') !== -1);
4386 };
4387
4388 /*
4389 * Converts 24 hour format into 12 hour
4390 * Returns 12 hour without leading 0
4391 */
4392 var convert24to12 = function(hour) {
4393 if (hour > 12) {
4394 hour = hour - 12;
4395 }
4396
4397 if (hour == 0) {
4398 hour = 12;
4399 }
4400
4401 return String(hour);
4402 };
4403
4404 /*
4405 * Splits datetime string into date ans time substrings.
4406 * Throws exception when date can't be parsed
4407 * Returns [dateString, timeString]
4408 */
4409 var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) {
4410 try {
4411 // The idea is to get the number separator occurances in datetime and the time format requested (since time has
4412 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
4413 var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator,
4414 format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat,
4415 timeParts = format.split(separator), // how many occurances of separator may be in our format?
4416 timePartsLen = timeParts.length,
4417 allParts = dateTimeString.split(separator),
4418 allPartsLen = allParts.length;
4419
4420 if (allPartsLen > 1) {
4421 return [
4422 allParts.splice(0,allPartsLen-timePartsLen).join(separator),
4423 allParts.splice(0,timePartsLen).join(separator)
4424 ];
4425 }
4426
4427 } catch (err) {
4428 $.timepicker.log('Could not split the date from the time. Please check the following datetimepicker options' +
4429 "\nthrown error: " + err +
4430 "\ndateTimeString" + dateTimeString +
4431 "\ndateFormat = " + dateFormat +
4432 "\nseparator = " + timeSettings.separator +
4433 "\ntimeFormat = " + timeSettings.timeFormat);
4434
4435 if (err.indexOf(":") >= 0) {
4436 // Hack! The error message ends with a colon, a space, and
4437 // the "extra" characters. We rely on that instead of
4438 // attempting to perfectly reproduce the parsing algorithm.
4439 var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2),
4440 timeString = dateTimeString.substring(dateStringLength);
4441
4442 return [$.trim(dateTimeString.substring(0, dateStringLength)), $.trim(dateTimeString.substring(dateStringLength))];
4443
4444 } else {
4445 throw err;
4446 }
4447 }
4448 return [dateTimeString, ''];
4449 };
4450
4451 /*
4452 * Internal function to parse datetime interval
4453 * Returns: {date: Date, timeObj: Object}, where
4454 * date - parsed date without time (type Date)
4455 * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional
4456 */
4457 var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
4458 var date;
4459 var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings);
4460 date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings);
4461 if (splitRes[1] !== '') {
4462 var timeString = splitRes[1],
4463 parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings);
4464
4465 if (parsedTime === null) {
4466 throw 'Wrong time format';
4467 }
4468 return {
4469 date: date,
4470 timeObj: parsedTime
4471 };
4472 } else {
4473 return {
4474 date: date
4475 };
4476 }
4477 };
4478
4479 /*
4480 * Internal function to set timezone_select to the local timezone
4481 */
4482 var selectLocalTimeZone = function(tp_inst, date) {
4483 if (tp_inst && tp_inst.timezone_select) {
4484 tp_inst._defaults.useLocalTimezone = true;
4485 var now = typeof date !== 'undefined' ? date : new Date();
4486 var tzoffset = $.timepicker.timeZoneOffsetString(now);
4487 if (tp_inst._defaults.timezoneIso8601) {
4488 tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
4489 }
4490 tp_inst.timezone_select.val(tzoffset);
4491 }
4492 };
4493
4494 /*
4495 * Create a Singleton Insance
4496 */
4497 $.timepicker = new Timepicker();
4498
4499 /**
4500 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
4501 * @param date
4502 * @return string
4503 */
4504 $.timepicker.timeZoneOffsetString = function(date) {
4505 var off = date.getTimezoneOffset() * -1,
4506 minutes = off % 60,
4507 hours = (off - minutes) / 60;
4508 return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).slice(-2) + ('0' + (minutes * 101).toString()).slice(-2);
4509 };
4510
4511 /**
4512 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
4513 * enforce date range limits.
4514 * n.b. The input value must be correctly formatted (reformatting is not supported)
4515 * @param Element startTime
4516 * @param Element endTime
4517 * @param obj options Options for the timepicker() call
4518 * @return jQuery
4519 */
4520 $.timepicker.timeRange = function(startTime, endTime, options) {
4521 return $.timepicker.handleRange('timepicker', startTime, endTime, options);
4522 };
4523
4524 /**
4525 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
4526 * enforce date range limits.
4527 * @param Element startTime
4528 * @param Element endTime
4529 * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
4530 * a boolean value that can be used to reformat the input values to the `dateFormat`.
4531 * @param string method Can be used to specify the type of picker to be added
4532 * @return jQuery
4533 */
4534 $.timepicker.dateTimeRange = function(startTime, endTime, options) {
4535 $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker');
4536 };
4537
4538 /**
4539 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
4540 * enforce date range limits.
4541 * @param Element startTime
4542 * @param Element endTime
4543 * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
4544 * a boolean value that can be used to reformat the input values to the `dateFormat`.
4545 * @param string method Can be used to specify the type of picker to be added
4546 * @return jQuery
4547 */
4548 $.timepicker.dateRange = function(startTime, endTime, options, method) {
4549 method = method || 'datepicker';
4550 $.timepicker.handleRange(method, startTime, endTime, options);
4551 };
4552
4553 /**
4554 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
4555 * enforce date range limits.
4556 * @param string method Can be used to specify the type of picker to be added
4557 * @param Element startTime
4558 * @param Element endTime
4559 * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
4560 * a boolean value that can be used to reformat the input values to the `dateFormat`.
4561 * @return jQuery
4562 */
4563 $.timepicker.handleRange = function(method, startTime, endTime, options) {
4564 $.fn[method].call(startTime, $.extend({
4565 onClose: function(dateText, inst) {
4566 checkDates(this, endTime, dateText);
4567 },
4568 onSelect: function(selectedDateTime) {
4569 selected(this, endTime, 'minDate');
4570 }
4571 }, options, options.start));
4572 $.fn[method].call(endTime, $.extend({
4573 onClose: function(dateText, inst) {
4574 checkDates(this, startTime, dateText);
4575 },
4576 onSelect: function(selectedDateTime) {
4577 selected(this, startTime, 'maxDate');
4578 }
4579 }, options, options.end));
4580 // timepicker doesn't provide access to its 'timeFormat' option,
4581 // nor could I get datepicker.formatTime() to behave with times, so I
4582 // have disabled reformatting for timepicker
4583 if (method != 'timepicker' && options.reformat) {
4584 $([startTime, endTime]).each(function() {
4585 var format = $(this)[method].call($(this), 'option', 'dateFormat'),
4586 date = new Date($(this).val());
4587 if ($(this).val() && date) {
4588 $(this).val($.datepicker.formatDate(format, date));
4589 }
4590 });
4591 }
4592 checkDates(startTime, endTime, startTime.val());
4593
4594 function checkDates(changed, other, dateText) {
4595 if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) {
4596 other.val(dateText);
4597 }
4598 }
4599 selected(startTime, endTime, 'minDate');
4600 selected(endTime, startTime, 'maxDate');
4601
4602 function selected(changed, other, option) {
4603 if (!$(changed).val()) {
4604 return;
4605 }
4606 var date = $(changed)[method].call($(changed), 'getDate');
4607 // timepicker doesn't implement 'getDate' and returns a jQuery
4608 if (date.getTime) {
4609 $(other)[method].call($(other), 'option', option, date);
4610 }
4611 }
4612 return $([startTime.get(0), endTime.get(0)]);
4613 };
4614
4615 /**
4616 * Log error or data to the console during error or debugging
4617 * @param Object err pass any type object to log to the console during error or debugging
4618 * @return void
4619 */
4620 $.timepicker.log = function(err){
4621 if(window.console)
4622 console.log(err);
4623 };
4624
4625 /*
4626 * Keep up with the version
4627 */
4628 $.timepicker.version = "1.2";
4629
4630 })(jQuery);
4631
4632 /* assets/wpuf/js/upload.js */
4633 ;(function($) {
4634
4635 /**
4636 * Upload handler helper
4637 *
4638 * @param string {browse_button} browse_button ID of the pickfile
4639 * @param string {container} container ID of the wrapper
4640 * @param int {max} maximum number of file uplaods
4641 * @param string {type}
4642 */
4643 window.WPUF_Uploader = function (browse_button, container, max, type, allowed_type, max_file_size) {
4644 this.removed_files = [];
4645 this.container = container;
4646 this.browse_button = browse_button;
4647 this.max = max || 1;
4648 this.count = $('#' + container).find('.wpuf-attachment-list > li').length; //count how many items are there
4649 this.perFileCount = 0; //file count on each upload
4650 this.UploadedFiles = 0; //file count on each upload
4651
4652 //if no element found on the page, bail out
4653 if( !$('#'+browse_button).length ) {
4654 return;
4655 }
4656
4657 // enable drag option for ordering
4658 $( "ul.wpuf-attachment-list" ).sortable({
4659 placeholder: "highlight"
4660 });
4661 $( "ul.wpuf-attachment-list" ).disableSelection();
4662
4663 //instantiate the uploader
4664 this.uploader = new plupload.Uploader({
4665 runtimes: 'html5,html4',
4666 browse_button: browse_button,
4667 container: container,
4668 multipart: true,
4669 multipart_params: {
4670 action: 'wpuf_upload_file',
4671 form_id: $( '#' + browse_button ).data('form_id')
4672 },
4673 max_file_count : 2,
4674 multiple_queues: false,
4675 multi_selection: ( ( browse_button == 'wpuf-avatar-pickfiles' || browse_button == 'wpuf-featured_image-pickfiles' ) ? false : true ),
4676 urlstream_upload: true,
4677 file_data_name: 'wpuf_file',
4678 max_file_size: max_file_size + 'kb',
4679 url: wpuf_frontend_upload.plupload.url + '&type=' + type,
4680 flash_swf_url: wpuf_frontend_upload.flash_swf_url,
4681 filters: [{
4682 title: 'Allowed Files',
4683 extensions: allowed_type
4684 }]
4685 });
4686
4687 //attach event handlers
4688 this.uploader.bind('Init', $.proxy(this, 'init'));
4689 this.uploader.bind('FilesAdded', $.proxy(this, 'added'));
4690 this.uploader.bind('QueueChanged', $.proxy(this, 'upload'));
4691 this.uploader.bind('UploadProgress', $.proxy(this, 'progress'));
4692 this.uploader.bind('Error', $.proxy(this, 'error'));
4693 this.uploader.bind('FileUploaded', $.proxy(this, 'uploaded'));
4694
4695 this.uploader.init();
4696
4697 $('#' + container).on('click', 'a.attachment-delete', $.proxy(this.removeAttachment, this));
4698
4699 return this.uploader;
4700 };
4701
4702 WPUF_Uploader.prototype = {
4703
4704 init: function (up, params) {
4705 this.showHide();
4706 $('#' + this.container).prepend('<div class="wpuf-file-warning"></div>');
4707 },
4708
4709 showHide: function () {
4710
4711 if ( this.count >= this.max) {
4712
4713 if ( this.count > this.max ) {
4714 $('#' + this.container + ' .wpuf-file-warning').html( wpuf_frontend_upload.warning );
4715 } else {
4716 $('#' + this.container + ' .wpuf-file-warning').html( wpuf_frontend_upload.warning );
4717 }
4718
4719 $('#' + this.container).find('.file-selector').hide();
4720
4721 return;
4722 };
4723 $('#' + this.container + ' .wpuf-file-warning').html( '' );
4724 $('#' + this.container).find('.file-selector').show();
4725 },
4726
4727 added: function (up, files) {
4728 var $container = $('#' + this.container).find('.wpuf-attachment-upload-filelist');
4729
4730 this.showHide();
4731
4732 $.each(files, function(i, file) {
4733 $(".wpuf-submit-button").attr("disabled", "disabled");
4734
4735 $container.append(
4736 '<div class="upload-item" id="' + file.id + '"><div class="progress progress-striped active"><div class="bar"></div></div><div class="filename original">' +
4737 file.name + ' (' + plupload.formatSize(file.size) + ') <b></b>' +
4738 '</div></div>');
4739 });
4740
4741 up.refresh(); // Reposition Flash/Silverlight
4742 up.start();
4743 },
4744
4745 upload: function (uploader) {
4746 this.count = uploader.files.length - this.removed_files.length ;
4747 this.showHide();
4748 },
4749
4750 progress: function (up, file) {
4751 var item = $('#' + file.id);
4752
4753 $('.bar', item).css({ width: file.percent + '%' });
4754 $('.percent', item).html( file.percent + '%' );
4755 },
4756
4757 error: function (up, error) {
4758 $('#' + this.container).find('#' + error.file.id).remove();
4759
4760 var msg = '';
4761 switch (error.code) {
4762 case -600:
4763 msg = wpuf_frontend_upload.plupload.size_error;
4764 break;
4765
4766 case -601:
4767 msg = wpuf_frontend_upload.plupload.type_error;
4768 break;
4769
4770 default:
4771 msg = 'Error #' + error.code + ': ' + error.message;
4772 break;
4773 }
4774
4775 alert(msg);
4776
4777 this.count -= 1;
4778 this.showHide();
4779 this.uploader.refresh();
4780 },
4781
4782 uploaded: function (up, file, response) {
4783 // var res = $.parseJSON(response.response);
4784 var self = this;
4785
4786 $('#' + file.id + " b").html("100%");
4787 $('#' + file.id).remove();
4788
4789 if(response.response !== 'error') {
4790
4791 this.perFileCount++;
4792 this.UploadedFiles++;
4793 var $container = $('#' + this.container).find('.wpuf-attachment-list');
4794 $container.append(response.response);
4795
4796 if ( this.perFileCount > this.max ) {
4797 var attach_id = $('.wpuf-image-wrap:last a.attachment-delete',$container).data('attach_id');
4798 self.removeExtraAttachment(attach_id);
4799 $('.wpuf-image-wrap',$container).last().remove();
4800 this.perFileCount--;
4801 }
4802
4803 } else {
4804 alert(response.error);
4805
4806 this.count -= 1;
4807 this.showHide();
4808 }
4809
4810 var uploaded = this.UploadedFiles,
4811 FileProgress = up.files.length,
4812 imageCount = $('ul.wpuf-attachment-list > li').length;
4813
4814 if ( imageCount >= this.max ) {
4815 $('#' + this.container).find('.file-selector').hide();
4816 }
4817
4818 if ( FileProgress === uploaded ) {
4819 if ( typeof grecaptcha !== 'undefined' && !grecaptcha.getResponse().length ) {
4820 return;
4821 }
4822 $(".wpuf-submit-button").removeAttr("disabled");
4823 }
4824 },
4825
4826 removeAttachment: function(e) {
4827 e.preventDefault();
4828
4829 var self = this,
4830 el = $(e.currentTarget);
4831
4832 swal({
4833 text: wpuf_frontend_upload.confirmMsg,
4834 type: 'warning',
4835 showCancelButton: true,
4836 confirmButtonColor: '#d54e21',
4837 confirmButtonText: wpuf_frontend_upload.delete_it,
4838 cancelButtonText: wpuf_frontend_upload.cancel_it,
4839 confirmButtonClass: 'btn btn-success',
4840 cancelButtonClass: 'btn btn-danger',
4841 }).then(function () {
4842 var data = {
4843 'attach_id' : el.data('attach_id'),
4844 'nonce' : wpuf_frontend_upload.nonce,
4845 'action' : 'wpuf_file_del'
4846 };
4847 self.removed_files.push(data);
4848 jQuery('#del_attach').val(el.data('attach_id'));
4849 jQuery.post(wpuf_frontend_upload.ajaxurl, data, function() {
4850 self.perFileCount--;
4851 el.parent().parent().remove();
4852
4853 self.count -= 1;
4854 self.showHide();
4855 self.uploader.refresh();
4856 });
4857 });
4858 },
4859
4860 removeExtraAttachment : function( attach_id ) {
4861
4862
4863 var self = this;
4864
4865 var data = {
4866 'attach_id' : attach_id,
4867 'nonce' : wpuf_frontend_upload.nonce,
4868 'action' : 'wpuf_file_del'
4869 };
4870 this.removed_files.push(data);
4871 jQuery.post(wpuf_frontend_upload.ajaxurl, data, function() {
4872 self.count -= 1;
4873 self.showHide();
4874 self.uploader.refresh();
4875 });
4876 }
4877
4878 };
4879 })(jQuery);
4880