/** * Add appointment date selection from calendar handling for input elements. * * The `.productUiAppointmentpicker()` method add validate handling to a input elements. * * The `.productUiAppointmentpicker()` method is a validation input also and using the validation type ''date'' from * the ep.validate module. Have a look at the additional options, some options are only available for * a special validation types. * * ### Examples * Apply .productUiAppointmentpicker() to input element named date. * * JavaScript: * * de_epages(':input[name=date]') * .productUiAppointmentpicker({ * showOn: 'focus', * appointment: { * id: 8930, * quantityMin: 1, * quantityRequested: 1, * quantityAvailable: 5, * minutesRequested: 60 * } * }); * * HTML: * * <form> * <input type="text" name="date" /> * </form> * * * @class jQuery.ui.productUiAppointmentpicker * @extends jQuery.ui.uiDatepicker * * @uses de_epages * @uses ep.ui.datepicker * @uses ep.alert * @uses ep.ajax * @since 6.11.0 */ /** * @cfg {Object} appointment A map of options like the ObjectID for the current appointment. */ /** * See `jQuery.ui.productUiAppointmentpicker` for details. * * @param {Object} [options] A map of additional options pass to the method. * @param {Object} appointment A map of options like the ObjectID for the current appointment. * * @method productUiAppointmentpicker * @member jQuery * * @since 6.11.0 */ /* * @copyright © Copyright 2006-2010, epages GmbH, All Rights Reserved. * * @module de_epages/product/ui/appointmentpicker * * @revision $Revision: 1.12 $ */ define("de_epages/product/ui/appointmentpicker", [ "jquery", "ep", "de_epages", "$dict!../dictionary", "ep/alert", "ep/ajax", "ep/ui/datepicker" ], function ($, ep, de_epages, dict) { /* * @dictionary de_epages.product.dictionary * * @translation {Loading} * {BookedUp} {CALENDAR_DATA_NOT_LOAD} */ var tLoading = dict.translate('Loading')+'...', tBookedOut = dict.translate('BookedUp'), tDataNotLoad = dict.translate('CALENDAR_DATA_NOT_LOAD'); $.widget('ui.productUiAppointmentpicker',$.ui.uiDatepicker,{ options: { // ep.ui.Input // big: true, // autofocus: false, // placeholder: 'text', // ep.ui.Validate // accept: '', // min: 1, // max: 20, // minlength: 1, // maxlength: 4, // pattern: [\w]+, // required: true, // tooltipOffset: [0,-7], // valid: true, // type: 'basic', // format: '', // ep.ui.Datepicker // type: 'date', // format: 'l', // showOn: 'both', // duration: 'normal', // show: 'fadeIn', // hide: 'fadeOut', // weekDaysAvailable: [0,0,1,1,1,1,1], // numberOfMonths: 1, // showOtherMonth: true, // selectOtherMonth: false, // changeMonth: true, // changeYear: true, // positionAdjust: [-1,2], // region: ep.config.region, // time: true, // timeStep: 15, // ep.ui.DatepickerApp time: true, currentDate: undefined, appointment: { // hash to perform appointment available id: 0, quantityMin: 1, quantityRequested: 1, quantityAvailable: 1, minutesRequested: 60 } }, _create: function(){ this._superApply(arguments); this._appointmentSort = {}; this._appointmentStack = {}; this._loadDayList( this._date.clone().addDate(-7), true ); }, _createTimeSelect: function(){ this.timeSelect = ep('<select>') .attr({ 'class': 'epWidth100' }) .appendTo( this.timeBar ) .uiInput() .uiInput('addClass','ep-uiDatepicker-time') .on( 'changeValue.uiAppointmentpicker', $.proxy(this, '_changeTimeVal') ); this.stack.push( this.timeSelect[0] ); }, _createCalendars: function(){ this._superApply(arguments); this._createTimeSelectData(); }, _calendarData: function(){ var self = this, o = this.options, opt = o.appointment, calendarsData = this._superApply(arguments), appData = $.scope( opt.minutesRequested+'', this._appointmentStack ), load = false; $.each( calendarsData, function( i, calendarData ){ $.each( calendarData.days, function( j, day ){ if( this.clickable ){ var date = day.date, dateString = date.getFormat('S'), dayObj = appData[ dateString ]; if( !dayObj && !load ){ appData = self._loadDayList( date.clone() ); dayObj = appData[ dateString ]; load = true; } this.clickable = !!(dayObj && dayObj.IsAvailable); } }); }); return calendarsData; }, _createTimeSelectData: function(){ var self = this, opt = this.options.appointment, dateString = this._dateSelected.getFormat('S'), appStack = $.scope( opt.minutesRequested+'', this._appointmentStack ), dayObj = appStack[ dateString ], placeholder = $('<option/>') .prop('disabled', true) .text(tLoading); self.timeSelect .empty() .append(placeholder); if( dayObj ){ // load TimeList for selected day if not cached if( !dayObj.DayList ){ self._loadTimeList(self._dateSelected); return; } var region = {region: self.options.region}; // add TimeList to select field if( dayObj.DayList && dayObj.DayList.length ){ self.timeSelect.empty(); $.each( dayObj.DayList, function( i, data ){ if( (opt.quantityAvailable-data[1]) >= opt.quantityRequested ){ var date = new ep.Date(data[0]); $('<option>') .val(date.setFullYear(0,0,0).getTime()) .text( date.getFormat( 't', region ) ) .appendTo( self.timeSelect ); } }); } // show times are booked out else{ placeholder.text(tBookedOut); } } else{ placeholder.text(tBookedOut); self.elem.trigger('focus'); } self._setTimeVal(); }, _setTimeVal: function(){ var self = this, selectedTime = this._timeSelected.getTime()+'', selectedNode, selectedIndex; $.each( this.timeSelect[0].options, function( i, node ){ if( node.value === selectedTime ){ node.selected = true; selectedNode = node; selectedIndex = i; return false; } }); if( !selectedNode ){ selectedNode = $(this.timeSelect[0].options).not(':disabled').get(0); if( selectedNode ){ selectedNode.selected = true; selectedTime = selectedNode.value; selectedIndex = 0; } } if( selectedTime ){ this._timeSelected = new ep.Date(selectedTime); } if( !this.elem.is(':focus') ){ this._setElemVal(true); } }, _getTimeVal: function(){ var opt = this.timeSelect[0].selectedIndex >= 0 ? this.timeSelect[0].options[ this.timeSelect[0].selectedIndex ] : null, date = opt ? new ep.Date(opt.value) : new ep.Date(); return date.setFullYear(0,0,0); }, // attention the date object will be modified, be sure to use an cloned date object _loadDayList: function( date, preload ){ var self = this, o = this.options, opt = o.appointment, dateStart = date, dateEnd = dateStart.clone().addMonth( o.numberOfMonths + 2 ), ret; ep.ajax({ data: { 'ViewAction': 'JSON-AppointmentCalendar', 'ObjectID': opt.id, 'StartDate': dateStart.getFormat('S'), 'EndDate': dateEnd.getFormat('S'), 'RequestedMinutes': opt.minutesRequested, 'Available': opt.quantityAvailable, 'UseTimestamps': 1, 'IsAvailableOnly': 1 }, async: !!preload, dataType: 'json' }) .done(function( data ){ ret = data; }) .fail(function( xhr, status, error ){ if( !preload ){ self.hide(); ep.alert({ type: 'error', content: tDataNotLoad }); } }); ret = $.extend( true, $.scope( opt.minutesRequested+'', this._appointmentStack ), ret ); return ret; }, // attention the date object will be modified, be sure to use an cloned date object _loadTimeList: function( date ){ var self = this, o = this.options, opt = o.appointment, dateStart = date, dateEnd = dateStart.clone().addDate(1), ret; ep.ajax({ data: { 'ViewAction': 'JSON-AppointmentCalendar', 'ObjectID': opt.id, 'StartDate': dateStart.getFormat('S'), 'EndDate': dateEnd.getFormat('S'), 'RequestedMinutes': opt.minutesRequested, 'Available': opt.quantityAvailable, 'UseTimestamps': 1 }, // async: false, dataType: 'json' }) .done(function( data ){ ret = $.extend( true, $.scope( opt.minutesRequested+'', self._appointmentStack ), data ); self._createTimeSelectData(); }) .fail(function( xhr, status, error ){ self.hide(); ep.alert({ type: 'error', content: tDataNotLoad }); }); }, /** * Updates the appointment option and refresh the availability. * * @param {Object} appointment A map of options like the ObjectID for the current appointment. * * @method updateAppointment * @member jQuery.ui.productUiAppointmentpicker * * @since 6.11.0 */ updateAppointment: function( options ){ $.extend( this.options.appointment, options ); // preload data // this._loadDayList( this._date.clone().addDate(-7), true ); } }); return de_epages; });