PageSourceSearch

https://www.mantrasouthbankbrisbane.com.au/my-bookings/WebResource…ZEInPqBRLhDhIJDGKYVxQ2&t=639259441440000000

js mantrasouthbankbrisbane.com.au collected 2026-10-05 03:19:02 UTC 23,210 bytes, 491 lines download raw bytes

1/**
2 * The client-side representation of the DateSelectorControl class.
3 * Implemented as a JS object to encapsulate all client-side functionality required 
4 * by the custom control.
5 * A new parameter exists now that associates a departure date custom control to an arrival
6 * date custom control, which is updated on arrival change to arrival + 3 days.
7 * validateDateFormat is a function type parameter to do validation on the 'FreeFormat' selection Mode
8 */
9function DateSelectorControl(controlID, dateFormat, selectionMode, validateDateFormat)
10{
11
12    // =======================================================================
13    // Attributes
14    // =======================================================================
15    var _ddlDay = ((selectionMode=="FreeFormat") ? null : document.getElementById(controlID + "_ddlDay"));
16    var _ddlMonthYear = ((selectionMode=="FreeFormat") ? null : document.getElementById(controlID + "_ddlMonthYear"));
17    var _ddlDayParent = ((selectionMode=="FreeFormat") ? null : document.getElementById(controlID + "lblDayContainer"));
18    var _txtCurrentDate = document.getElementById(controlID + "_txtCurrentDate");
19    var _txtPeriodStart = document.getElementById(controlID + "_txtPeriodStart");
20    var _txtPeriodEnd = document.getElementById(controlID + "_txtPeriodEnd");
21    var _hdnStayLength = document.getElementById(controlID + "_hdnStayLength");
22    var _localInstance = this;
23    var _dateFormat = dateFormat;
24    var oneDay = 86400000;//24*60*60*1000; hours*minutes*seconds*milliseconds
25
26    var _associatedDepartureControlInstance;
27    
28   // =======================================================================
29    // Methods
30    // =======================================================================
31    /**
32     * Used to help ensure that the drop-down lists work as expected. If, for example,
33     * the user has a current selection of 31 August, and changes the month to June,
34     * the display will revert to 01 July, since this is, effectively, 31 June. This
35     * method, then, will make sure that any such dates are properly rounded down to
36     * the maximum day for the new month.
37     * @param   newDay         the new date to be tested
38     * @param   newMonth       the new month to be tested
39     * @param   newYear        the new year to be tested
40     * @return                 the newDate, truncated if required
41     */
42    var createDate = function(newDay, newMonth, newYear) {
43        var maxDay = new Date(newYear, newMonth + 1, 0).getDate();
44        return new Date(newYear, newMonth, Math.min(newDay, maxDay));
45    };
46
47    /**
48     * Basic event handler that is called when the day drop-down changes.
49     */
50    var ddlDayOnChange = function () {
51        var originalDate = _localInstance.getDate();  //This variable was renamed because it actually held the original date value, not what was selected in the DDL
52        if (originalDate != null) {
53            dateSelection(originalDate); //
54            setDateSelectorAttributes(originalDate);
55
56            var selectedDate = _localInstance.getDate();
57
58            //Sync associated departure control if defined
59            if (_associatedDepartureControlInstance != null) {
60                syncDeparture(selectedDate);
61            }
62        }
63    };
64    
65    /**
66     * Basic event handler that is called when the month/year drop-down changes.
67     */
68    var ddlMonthYearOnChange = function () {
69        var originalDate = _localInstance.getDate();
70        if (originalDate != null) {
71            monthYearSelection(originalDate, _localInstance.getPeriodStart(), _localInstance.getPeriodEnd());
72            setDateSelectorAttributes(originalDate);
73
74            var selectedDate = _localInstance.getDate();
75
76            //Sync associated departure control if defined
77            if (_associatedDepartureControlInstance != null) {
78                syncDeparture(selectedDate);
79            }
80        }
81    };
82    
83    
84    /**
85     * When a value is chosen from the date drop-down list, create a new date with
86     * the old month/year and the new day, and update the date field.
87     * The function will bypass if the new date selection equals the old.
88     * @param   selectedDate   the last selected date - taken from the calendar
89     */
90    var dateSelection = function (selectedDate) {
91        if (_ddlDay != null) {
92            var newSelectionValue = parseInt(_ddlDay.value, 10);
93
94            if (newSelectionValue != selectedDate.getDate()) {
95                var newSelectionDate = createDate(newSelectionValue, selectedDate.getMonth(), selectedDate.getFullYear());
96                $('#' + controlID + '_txtCurrentDate').val(newSelectionDate.format(_dateFormat));
97            }
98        }
99    };
100
101    /**
102    * This method syncs all associated controls with the calendar - dropdownlists and, if defined,
103    * the departure date control.
104    */
105    this.syncAll = function () {
106        var selectedDate = this.getDate();
107        if (selectedDate != null) {
108            setSelectedMonthYear(selectedDate);
109            setSelectedDate(selectedDate, _localInstance.getPeriodStart(), _localInstance.getPeriodEnd());
110
111            //Sync associated departure control if defined - the rule is current date plus 1 day (in milliseconds)
112            if (_associatedDepartureControlInstance != null) {
113                syncDeparture(this.getDate());
114                setTimeout(function () { _associatedDepartureControlInstance.showCalander(); }, 200);
115            }
116        }
117    };
118
119    /**
120    * This method shows the datepicker control associated with the date selector control.
121    */
122    this.showCalander = function () {
123        $('#' + controlID + '_txtCurrentDate').datepicker("refresh");
124        $('#' + controlID + '_txtCurrentDate').datepicker("show");
125    };
126
127
128    /**
129     * this to maintain the difference between the arrive/depart dates
130     * @param   numberOfNights   the number of nights
131     */
132    this.setStayLength = function (numberOfNights) {
133        $(_hdnStayLength).val(numberOfNights);
134        onChangeHandler();
135    };
136
137    this.getStayLength = function() {
138        return $(_hdnStayLength).val();
139    };
140
141    var syncDeparture = function (selectedDate) {
142        //Calculate 3 days after the arrival date (this instance), 
143        //set the Departure control's new date and invoke its syncAll()
144        var newDepartureTime = selectedDate.getTime() + parseInt($('#' + controlID + '_hdnStayLength').val()) * oneDay;
145        var newDepartureDate = new Date(newDepartureTime);
146        _associatedDepartureControlInstance.setDate(newDepartureDate);
147        _associatedDepartureControlInstance.syncAll();
148    };
149
150    /**
151     * Allows clients to retrieve the curent date in this date selector.
152     * Null is returned if the calendar can't be retrieved, or doesn't
153     * have a value and finally, if the value is matched the place holder.
154     * @return   the currently selected date
155     */
156    this.getDate = function() {
157        var result = null;
158        if ((_txtCurrentDate.value != null) && (_txtCurrentDate.value != "") && (_txtCurrentDate.value !== _txtCurrentDate.getAttribute("placeholder"))) {
159            result = parseDate(_txtCurrentDate.value, dateFormat);
160        }
161        return result;
162    };
163
164    /**
165     * Allows clients to retrieve the period end of this date selector,
166     * Null is returned if the calendar can't be retrieved, or doesn't have a value.
167     * @return   the current end date of the valid date range
168     */
169    this.getPeriodEnd = function () {
170        var result = null;
171        if (_txtPeriodEnd != null) {
172            result = parseDate(_txtPeriodEnd.value, dateFormat);
173        }
174        return result;
175    };
176
177    /**
178     * Allows clients to retrieve the period start of this date selector,
179     * Null is returned if the calendar can't be retrieved, or doesn't have a value.
180     * @return   the current start date of the valid date range
181     */
182    this.getPeriodStart = function () {
183        var result = null;
184        if (_txtPeriodStart != null) {
185            result = parseDate(_txtPeriodStart.value, dateFormat);
186        }
187        return result;
188    };
189
190    /**
191     * This function should be called immediately after creation to ensure that
192     * all appropriate listeners, etc., are properly initialised.
193     */
194    this.initialise = function () {
195        // Do all of this the long-winded way, otherwise ASP.Net's validators
196        // can come along and screw up our scoping.
197        if (typeof _txtCurrentDate.attachEvent != 'undefined') {
198            _txtCurrentDate.detachEvent('onchange', onCalendarDateChange);
199            _txtCurrentDate.attachEvent('onchange', onCalendarDateChange);
200        }
201        else if (typeof _txtCurrentDate.addEventListener != 'undefined') {
202            _txtCurrentDate.removeEventListener('change', onCalendarDateChange, false);
203            _txtCurrentDate.addEventListener('change', onCalendarDateChange, false);
204        }
205        //Use JQuery change handler for hidden Calendar Date field.
206        //Update : was not firing when external source changed date, so also added to setDate() function
207        $('#' + controlID + '_txtCurrentDate').change(onChangeHandler);
208
209        if (_ddlMonthYear != null) {
210            if (typeof _ddlMonthYear.attachEvent != 'undefined') {
211                _ddlMonthYear.detachEvent('onchange', ddlMonthYearOnChange);
212                _ddlMonthYear.attachEvent('onchange', ddlMonthYearOnChange);
213            }
214            else if (typeof _ddlMonthYear.addEventListener != 'undefined') {
215                _ddlMonthYear.removeEventListener('change', ddlMonthYearOnChange, false);
216                _ddlMonthYear.addEventListener('change', ddlMonthYearOnChange, false);
217            }
218        }
219        initialiseDateListeners();
220
221        // Initialisation has to happen after everything loads, but ONLY for IE.
222        // All other browsers work fine otherwise; IE has issues with DOM loading
223        // and the order in which things are initialised.
224        Sys.Application.add_load(onLoadHandler);
225
226        // Make the text box to be read only when the device is a touch device and the format is Free Format
227        if (selectionMode === "FreeFormat" && typeof Modernizr === 'object') {
228            if (Modernizr.touch) {
229                _txtCurrentDate.setAttribute("readonly","true");
230            }
231        }
232
233
234    };
235
236    /**
237    * Used just after control initialisation, on the body loaded event to associate the instance of the departure control.
238    */
239    this.setAssociatedDepartureControl = function (associatedDepartureControlInstance) {
240        _associatedDepartureControlInstance = associatedDepartureControlInstance;
241    };
242
243    var onChangeHandler = function () {
244        if (selectionMode !== "FreeFormat") {
245            //The following syncs DDL's with the hidden text box.
246            var selectedDate = parseDate(_txtCurrentDate.value, dateFormat);
247
248            setSelectedMonthYear(selectedDate);
249            setSelectedDate(selectedDate, _localInstance.getPeriodStart(), _localInstance.getPeriodEnd());
250        }
251    };
252
253    var onLoadHandler = function () {
254        // The following will force the various parts of this control (dropdowns,
255        // calendar extenders, text fields, etc., to align. It comes into play on
256        // back-button navigation.
257        if (selectionMode !== "FreeFormat" && _txtCurrentDate.value !== "") {
258            var selectedDate = parseDate(_txtCurrentDate.value, dateFormat);
259
260            setSelectedMonthYear(selectedDate);
261            setSelectedDate(selectedDate, _localInstance.getPeriodStart(), _localInstance.getPeriodEnd());
262        }
263
264        // Make sure that the event isn't re-fired on async postback.
265        Sys.Application.remove_load(onLoadHandler);
266    };
267
268    /**
269     * Due to bugs in safari, the date drop-down list must be re-created
270     * whenever it is updated dynamically. This includes the listeners
271     * applied to it by this class, and so this method is called from two
272     * places: initialise() and setSelectedDate().
273     */
274    var initialiseDateListeners = function () {
275        if (_ddlDay != null) {
276            if (typeof _ddlDay.attachEvent != 'undefined') {
277                _ddlDay.detachEvent('onchange', ddlDayOnChange);
278                _ddlDay.attachEvent('onchange', ddlDayOnChange);
279            }
280            else if (typeof _ddlDay.addEventListener != 'undefined') {
281                _ddlDay.removeEventListener('change', ddlDayOnChange, false);
282                _ddlDay.addEventListener('change', ddlDayOnChange, false);
283            }
284        }
285    };
286    
287    /**
288     * When a value is chosen from the month/year drop-down list, create a new
289     * date that combines this new month/year with the current date selection.
290     * Ensure that this new date is properly rounded to within the current
291     * period start and end dates, set the date text field & trigger update events. 
292     * The function will bypass if the new date selection equals the old. The values of all items
293     * in the month/year drop-down are in the form MMyyyy, and are used to extract 
294     * the appropriate values for the new date.
295     * @param   selectedDate        the last selected date - taken from the calendar
296     * @param   periodStart         the period start date set against this control
297     * @param   periodEnd           the period end date set against this control
298     */
299    var monthYearSelection = function (selectedDate, periodStart, periodEnd) {
300        if (_ddlMonthYear != null) {
301            var newSelectionValue = _ddlMonthYear.value;
302            var newSelectionDate = createDate(selectedDate.getDate(), parseInt(newSelectionValue.substring(0, 2), 10) - 1, parseInt(newSelectionValue.substring(2), 10));
303            if (newSelectionDate != selectedDate) {
304                newSelectionDate = validateDateAgainstRange(newSelectionDate, periodStart, periodEnd);
305                $('#' + controlID + '_txtCurrentDate').val(newSelectionDate.format(_dateFormat));
306                setSelectedDate(newSelectionDate, periodStart, periodEnd);
307            }
308        }
309    };
310    
311    /**
312     * An event handler that is tied to the onchange event of the hidden text
313     * field in this control that contains the current date selection. The value
314     * may be changed from a variety of sources, both inside and outside this 
315     * object, and any change will cause the related controls here to change.
316     */
317    var onCalendarDateChange = function () {
318        var selectedDate = _localInstance.getDate();
319        if (selectedDate != null) {
320            setSelectedMonthYear(selectedDate);
321            setSelectedDate(selectedDate, _localInstance.getPeriodStart(), _localInstance.getPeriodEnd());
322
323            // The calendar date should have been updated by the lines above.
324            setDateSelectorAttributes(_localInstance.getDate());
325
326            if (selectionMode == "FreeFormat" && selectedDate != "Invalid Date" && _txtCurrentDate.value !== selectedDate.format(_dateFormat) && typeof (validateDateFormat) !== "undefined" && validateDateFormat(this)) {
327                _txtCurrentDate.value = selectedDate.format(_dateFormat);
328            }
329
330            // The custom date change handler used to be added to the corresponding
331            // field during initialise, AFTER the local listener. However, IE has a 
332            // problem with guaranteeing the order of event listeners, so the handler
333            // is invoked here, AFTER all local changes have been made.
334            if ((typeof (customDateChangeHandler) !== "undefined") && (typeof (customDateChangeHandler) == "function")) {
335                customDateChangeHandler();
336            }
337        }
338    };
339    
340    /**
341     * Used to get around various cross-browser date-parsing issues. The format
342     * provided here is generally supplied as the dateFormat attribute of this
343     * class. If no format is provided, a default of "yyyy-MM-dd" is assumed.
344     * In any case, it depends on 4-digits years (yyyy), 2-digit months (dd),
345     * and 2-digit days (dd).
346     * @param   stringValue   the value to be parsed
347     * @param   format        the date format to be applied
348     */
349    var parseDate = function (stringValue, format) {
350        
351        format = format.toLowerCase() || 'yyyy-mm-dd';
352        //if the date string includes mmm or mmmm, it's ok to convert from string to Date
353        if (format.search("mmm") > 0 || format.search("mmmm") > 0) {
354            return new Date(stringValue);
355        }
356
357       var parts = stringValue.match(/(\d+)/g),
358            i = 0,
359            fmt = {};
360
361        format.replace(/(yyyy|dd|mm)/g, function (part) { fmt[part] = i++; }); 
362        return new Date(parts[fmt['yyyy']], parts[fmt['mm']] - 1, parts[fmt['dd']]);
363  
364    };
365
366    /**
367     * Allows clients to set the date of this date selector. The calendar 
368     * and all associated controls within this selector has its date set 
369     * to the given value.
370     * @param   selectedDate   the new date value for this control
371     */
372    this.setDate = function (selectedDate) {
373        $('#' + controlID + '_txtCurrentDate').val(selectedDate.format(_dateFormat));
374        onChangeHandler();
375    };
376
377    /**
378     * A function that updates the date-specific attributes of this date
379     * selector with the values of the given date. The value may be stored
380     * in more than one format against this control.
381     * @param   selectedDate   the new date to update local attributes with
382     */
383    var setDateSelectorAttributes = function(selectedDate)
384    {
385        document.getElementById(controlID).setAttribute("selecteddate", selectedDate.format("yyyy-MM-dd"));
386    };
387
388    /**
389     * Forces an update on the date drop-down list, typically as the result of a
390     * selection made in the associated calendar. The start and end dates for the 
391     * period defined against this control are also passed in, since the new date
392     * may require som truncation to fit within this period. The current contents 
393     * of the drop-down are cleared, and replaced with all dates in the month of
394     * the given selectedDate.
395     * @param   selectedDate   the date that has been selected, typically in the calendar
396     * @param   periodStart    the start date of the period defined in this control
397     * @param   periodEnd      the end date of the period defined in this control
398     */
399    var setSelectedDate = function (selectedDate, periodStart, periodEnd) {
400        if (_ddlDay != null) {
401            var minDay = 1;
402            var maxDay = new Date(selectedDate.getFullYear(), selectedDate.getMonth() + 1, 0).getDate();
403            if ((periodStart != null) && (selectedDate.getMonth() == periodStart.getMonth()) && (selectedDate.getFullYear() == periodStart.getFullYear())) {
404                minDay = Math.max(minDay, periodStart.getDate());
405            }
406            if ((periodEnd != null) && (selectedDate.getMonth() == periodEnd.getMonth()) && (selectedDate.getFullYear() == periodEnd.getFullYear())) {
407                maxDay = Math.min(maxDay, periodEnd.getDate());
408            }
409
410            var updateSelector = _ddlDay;
411            var sBrowser = navigator.userAgent;
412
413            // The following workaround addresses a Safari bug, in which dynamically
414            // updates SELECTs are not repainted properly. The select is basically removed
415            // from memory and recreated before being filled.
416            if ((sBrowser.toLowerCase().indexOf('webkit') > -1) || (sBrowser.toLowerCase().indexOf('safari') > -1)) {
417                var dateSelectorID = updateSelector.id;
418                var dateSelectorName = updateSelector.name;
419                var dateSelectorOnChange = updateSelector.onchange;
420
421                if (_ddlDayParent != null) {
422                    _ddlDayParent.innerHTML = "";
423
424                    updateSelector = document.createElement("SELECT");
425                    updateSelector.id = dateSelectorID;
426                    updateSelector.name = dateSelectorName;
427                    updateSelector.onchange = dateSelectorOnChange;
428                    _ddlDayParent.appendChild(updateSelector);
429
430                    _ddlDay = updateSelector;
431                    initialiseDateListeners();
432                }
433            }
434            var selectedOption = null;
435            updateSelector.options.length = 0;
436            var baseDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1);
437            for (var i = minDay; i <= maxDay; i++) {
438                baseDate.setDate(i);
439                var dateValue = ((i < 10) ? "0" : "") + i;
440                var dateString = baseDate.format("d (ddd)");
441
442                var option = document.createElement("OPTION");
443                option.text = dateString;
444                option.value = dateValue;
445                updateSelector.options.add(option);
446
447                if (i == selectedDate.getDate()) {
448                    option.setAttribute('selected', true);
449                    selectedOption = option;
450                }
451            }
452            if (selectedOption != null) {
453                updateSelector.selectedIndex = selectedOption.index;
454            }
455        }
456    };
457
458    /**
459     * Forces an update to the selected month and year drop-down list. The given
460     * date is generally taken from the associated calendar after a selection. The
461     * format of all values in the month/year drop-down - MMyyyy - is used to specify
462     * the new selection.
463     * @param   selectedDate        the date that has been selected, typically in the calendar
464     */
465    var setSelectedMonthYear = function (selectedDate) {
466        if (_ddlMonthYear != null) {
467            _ddlMonthYear.value = selectedDate.format("MMyyyy");
468        }
469    };
470
471    /**
472     * A utility function that will round the given date to within the boundaries
473     * imposed by the given period start and end dates. Either of these range values
474     * can be null, indicating an "open" set of dates.
475     * @param   selectedDate   the date to be converted
476     * @param   periodStart    the start date of the period
477     * @param   periodEnd      the end date of the period
478     * @return                 the given selectedDate, possibly altered to fit within the range
479     */
480    var validateDateAgainstRange = function (selectedDate, periodStart, periodEnd) {
481        var result = selectedDate;
482
483        if ((periodStart != null) && (result < periodStart)) {
484            result = new Date(periodStart.getTime());
485        }
486        if ((periodEnd != null) && (result > periodEnd)) {
487            result = new Date(periodEnd.getTime());
488        }
489        return result;
490    };
491}

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