| 1 |
<?php |
| 2 |
/** |
| 3 |
* @package VikBooking |
| 4 |
* @subpackage com_vikbooking |
| 5 |
* @author Alessio Gaggii - e4j - Extensionsforjoomla.com |
| 6 |
* @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved. |
| 7 |
* @license GNU General Public License version 2 or later; see LICENSE |
| 8 |
* @link https://vikwp.com |
| 9 |
*/ |
| 10 |
|
| 11 |
defined('ABSPATH') or die('No script kiddies please!'); |
| 12 |
|
| 13 |
$document = JFactory::getDocument(); |
| 14 |
// load jQuery lib e jQuery UI |
| 15 |
if (VikBooking::loadJquery()) { |
| 16 |
JHtml::fetch('jquery.framework', true, true); |
| 17 |
} |
| 18 |
$document->addStyleSheet(VBO_SITE_URI.'resources/jquery-ui.min.css'); |
| 19 |
JHtml::fetch('script', VBO_SITE_URI.'resources/jquery-ui.min.js'); |
| 20 |
|
| 21 |
$currencysymb = VikBooking::getCurrencySymb(); |
| 22 |
$datesep = VikBooking::getDateSeparator(); |
| 23 |
$nowdf = VikBooking::getDateFormat(); |
| 24 |
if ($nowdf == "%d/%m/%Y") { |
| 25 |
$df = 'd/m/Y'; |
| 26 |
$juidf = 'dd/mm/yy'; |
| 27 |
} elseif ($nowdf == "%m/%d/%Y") { |
| 28 |
$df = 'm/d/Y'; |
| 29 |
$juidf = 'mm/dd/yy'; |
| 30 |
} else { |
| 31 |
$df = 'Y/m/d'; |
| 32 |
$juidf = 'yy/mm/dd'; |
| 33 |
} |
| 34 |
$wdays_map = array( |
| 35 |
JText::translate('VBWEEKDAYZERO'), |
| 36 |
JText::translate('VBWEEKDAYONE'), |
| 37 |
JText::translate('VBWEEKDAYTWO'), |
| 38 |
JText::translate('VBWEEKDAYTHREE'), |
| 39 |
JText::translate('VBWEEKDAYFOUR'), |
| 40 |
JText::translate('VBWEEKDAYFIVE'), |
| 41 |
JText::translate('VBWEEKDAYSIX') |
| 42 |
); |
| 43 |
$ts_info = getdate($this->order['ts']); |
| 44 |
$checkin_info = getdate($this->order['checkin']); |
| 45 |
$checkout_info = getdate($this->order['checkout']); |
| 46 |
$pitemid = VikRequest::getInt('Itemid', 0, 'request'); |
| 47 |
|
| 48 |
// compose the calculation for pax_data |
| 49 |
list($pax_fields, $pax_fields_attributes) = VikBooking::getPaxFields(true); |
| 50 |
$pax_data = array(); |
| 51 |
$count_pax_data = 1; |
| 52 |
if (!empty($this->customer['pax_data'])) { |
| 53 |
$pax_data = json_decode($this->customer['pax_data'], true); |
| 54 |
} |
| 55 |
|
| 56 |
$arrpeople = array(); |
| 57 |
foreach ($this->orderrooms as $ind => $or) { |
| 58 |
$num = $ind + 1; |
| 59 |
$arrpeople[$num]['adults'] = $or['adults']; |
| 60 |
$arrpeople[$num]['children'] = $or['children']; |
| 61 |
$arrpeople[$num]['children_age'] = $or['childrenage']; |
| 62 |
$arrpeople[$num]['t_first_name'] = $or['t_first_name']; |
| 63 |
$arrpeople[$num]['t_last_name'] = $or['t_last_name']; |
| 64 |
} |
| 65 |
|
| 66 |
// countries list |
| 67 |
$all_countries = VikBooking::getCountriesArray(); |
| 68 |
|
| 69 |
// access the active back-end driver instance also for pre-checkin |
| 70 |
$pax_fields_obj = VBOCheckinPax::getInstance(); |
| 71 |
|
| 72 |
// load langs for JS |
| 73 |
JText::script('VBO_UPLOAD_FAILED'); |
| 74 |
JText::script('VBO_REMOVEF_CONFIRM'); |
| 75 |
JText::script('VBO_PRECHECKIN_TOAST_HELP'); |
| 76 |
?> |
| 77 |
|
| 78 |
<h3 class="vbo-booking-details-intro"><?php echo JText::sprintf('VBOYOURBOOKCONFAT', VikBooking::getFrontTitle()); ?></h3> |
| 79 |
|
| 80 |
<div class="vbo-booking-details-topcontainer vbo-booking-details-precheckin"> |
| 81 |
|
| 82 |
<div class="vbo-booking-details-head vbo-booking-details-head-confirmed"> |
| 83 |
<h4><?php echo JText::translate('VBOPRECHECKIN'); ?></h4> |
| 84 |
</div> |
| 85 |
|
| 86 |
<div class="vbo-booking-details-midcontainer"> |
| 87 |
<div class="vbo-booking-details-bookinfos"> |
| 88 |
<span class="vbvordudatatitle"><?php echo JText::translate('VBORDERDETAILS'); ?></span> |
| 89 |
<div class="vbo-booking-details-bookinfo"> |
| 90 |
<span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBORDEREDON'); ?></span> |
| 91 |
<span class="vbo-booking-details-bookinfo-val"><?php echo $wdays_map[$ts_info['wday']].', '.date(str_replace("/", $datesep, $df).' H:i', $this->order['ts']); ?></span> |
| 92 |
</div> |
| 93 |
<div class="vbo-booking-details-bookinfo"> |
| 94 |
<span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBCONFIRMNUMB'); ?></span> |
| 95 |
<span class="vbo-booking-details-bookinfo-val"><?php echo $this->order['confirmnumber']; ?></span> |
| 96 |
</div> |
| 97 |
<div class="vbo-booking-details-bookinfo"> |
| 98 |
<span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBDAL'); ?></span> |
| 99 |
<span class="vbo-booking-details-bookinfo-val"><?php echo $wdays_map[$checkin_info['wday']].', '.date(str_replace("/", $datesep, $df).' H:i', $this->order['checkin']); ?></span> |
| 100 |
</div> |
| 101 |
<div class="vbo-booking-details-bookinfo"> |
| 102 |
<span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBAL'); ?></span> |
| 103 |
<span class="vbo-booking-details-bookinfo-val"><?php echo $wdays_map[$checkout_info['wday']].', '.date(str_replace("/", $datesep, $df).' H:i', $this->order['checkout']); ?></span> |
| 104 |
</div> |
| 105 |
<div class="vbo-booking-details-bookinfo"> |
| 106 |
<span class="vbo-booking-details-bookinfo-lbl"><?php echo JText::translate('VBDAYS'); ?></span> |
| 107 |
<span class="vbo-booking-details-bookinfo-val"><?php echo $this->order['days']; ?></span> |
| 108 |
</div> |
| 109 |
</div> |
| 110 |
</div> |
| 111 |
|
| 112 |
<div class="vbo-precheckin-container"> |
| 113 |
<div class="info vbo-precheckin-disclaimer"><?php echo JText::translate('VBO_PRECHECKIN_DISCLAIMER'); ?></div> |
| 114 |
<form action="<?php echo JRoute::rewrite('index.php?option=com_vikbooking'.(!empty($pitemid) ? '&Itemid='.$pitemid : '')); ?>" method="post"> |
| 115 |
<input type="hidden" name="option" value="com_vikbooking" /> |
| 116 |
<input type="hidden" name="task" value="storeprecheckin" /> |
| 117 |
<input type="hidden" name="sid" value="<?php echo empty($this->order['sid']) && !empty($this->order['idorderota']) ? $this->order['idorderota'] : $this->order['sid']; ?>" /> |
| 118 |
<input type="hidden" name="ts" value="<?php echo $this->order['ts']; ?>" /> |
| 119 |
<input type="hidden" name="Itemid" value="<?php echo $pitemid; ?>" /> |
| 120 |
<?php |
| 121 |
foreach ($this->orderrooms as $ind => $or) { |
| 122 |
$num = $ind + 1; |
| 123 |
// total guests details available |
| 124 |
$count_pax_data = $num < 2 ? $count_pax_data : 0; |
| 125 |
if (isset($pax_data[$ind])) { |
| 126 |
$count_pax_data = count($pax_data[$ind]); |
| 127 |
} |
| 128 |
|
| 129 |
// calculate the number of guests to register depending on current driver settings for pre-checkin (plugin only) |
| 130 |
$guests_to_register = $pax_fields_obj->registerChildren($precheckin = true) ? ($arrpeople[$num]['adults'] + $arrpeople[$num]['children']) : $arrpeople[$num]['adults']; |
| 131 |
?> |
| 132 |
<div class="vbo-precheckin-room-wrapper"> |
| 133 |
<div class="vbo-precheckin-room-wrap <?php echo $count_pax_data >= $guests_to_register ? 'vbo-precheckin-guestscount-complete' : 'vbo-precheckin-guestscount-incomplete'; ?>"> |
| 134 |
<div class="vbo-precheckin-room-head"> |
| 135 |
<span><?php echo $or['name']; ?></span> |
| 136 |
</div> |
| 137 |
<div class="vbo-precheckin-adults-cont"> |
| 138 |
<?php |
| 139 |
for ($g = 1; $g <= $guests_to_register; $g++) { |
| 140 |
$current_guest = array(); |
| 141 |
if (count($pax_data) && isset($pax_data[$ind]) && isset($pax_data[$ind][$g])) { |
| 142 |
$current_guest = $pax_data[$ind][$g]; |
| 143 |
} elseif ($ind < 1 && $g == 1) { |
| 144 |
$current_guest = $this->customer; |
| 145 |
} |
| 146 |
?> |
| 147 |
<div class="vbo-precheckin-adult-wrap"> |
| 148 |
<div class="vbo-precheckin-adult-num"> |
| 149 |
<span><?php echo JText::sprintf('VBOGUESTNUM', $g); ?></span> |
| 150 |
</div> |
| 151 |
<?php |
| 152 |
/** |
| 153 |
* Overrides tip: to add and collect custom details from each guest it is possible to push more |
| 154 |
* pairs of key-values to $pax_fields. For example, a custom value could be pushed like this: |
| 155 |
* |
| 156 |
* $pax_fields['custom_field_key'] = 'Custom Field Name'; |
| 157 |
* $pax_fields_attributes['custom_field_key'] = 'text'; |
| 158 |
* |
| 159 |
* @see the best way to customize the guest fields is to use the apposite plugin hooks/events. |
| 160 |
*/ |
| 161 |
$pax_field_ind = 1; |
| 162 |
foreach ($pax_fields as $paxk => $paxv) { |
| 163 |
// determine the pax field rendering type |
| 164 |
|
| 165 |
if (isset($pax_fields_attributes[$paxk]) && is_array($pax_fields_attributes[$paxk])) { |
| 166 |
// select with choices |
| 167 |
$field_rendering_type = 'select'; |
| 168 |
} elseif (isset($pax_fields_attributes[$paxk]) && $pax_fields_attributes[$paxk] == 'country') { |
| 169 |
// field of type country |
| 170 |
$field_rendering_type = 'country'; |
| 171 |
} elseif (isset($pax_fields_attributes[$paxk]) && $pax_fields_attributes[$paxk] == 'calendar') { |
| 172 |
// datepicker calendar |
| 173 |
$field_rendering_type = 'calendar'; |
| 174 |
} elseif (isset($pax_fields_attributes[$paxk]) && $pax_fields_attributes[$paxk] == 'file') { |
| 175 |
// file upload (multiple files allowed) |
| 176 |
$field_rendering_type = 'file'; |
| 177 |
} elseif (isset($pax_fields_attributes[$paxk]) && $pax_fields_attributes[$paxk] == 'text') { |
| 178 |
// text |
| 179 |
$field_rendering_type = 'text'; |
| 180 |
} else { |
| 181 |
// custom pax-field type |
| 182 |
$field_rendering_type = 'paxfield'; |
| 183 |
} |
| 184 |
|
| 185 |
// the pax-field HTML string, if any |
| 186 |
$pax_field_html = ''; |
| 187 |
|
| 188 |
// run pre-flight check to ensure the paxfield is compatible with the current guest |
| 189 |
if ($field_rendering_type === 'paxfield') { |
| 190 |
/** |
| 191 |
* Attempt to render a custom field previously installed through a third party plugin. |
| 192 |
* If no such field type is found, the object will default to the "text" type. |
| 193 |
* |
| 194 |
* @since 1.16.3 (J) - 1.6.3 (WP) |
| 195 |
*/ |
| 196 |
|
| 197 |
// get an instance of the VBOCheckinPaxfield object |
| 198 |
$pax_field_obj = $pax_fields_obj->getField($paxk); |
| 199 |
|
| 200 |
// detect the current type of guest |
| 201 |
$guest_type = $g > $arrpeople[$num]['adults'] ? 'child' : 'adult'; |
| 202 |
|
| 203 |
// set object data |
| 204 |
$pax_field_obj->setGuestType($guest_type) |
| 205 |
->setFieldNumber($pax_field_ind) |
| 206 |
->setGuestNumber($g) |
| 207 |
->setGuestData($current_guest) |
| 208 |
->setRoomIndex($ind) |
| 209 |
->setRoomGuests($arrpeople[$num]['adults'], $arrpeople[$num]['children']) |
| 210 |
->setTotalRooms(count($arrpeople)); |
| 211 |
|
| 212 |
// render input field |
| 213 |
$pax_field_html = $pax_fields_obj->render($pax_field_obj); |
| 214 |
if (empty($pax_field_html)) { |
| 215 |
// nothing to display, increase the counter and continue |
| 216 |
$pax_field_ind++; |
| 217 |
continue; |
| 218 |
} |
| 219 |
} |
| 220 |
|
| 221 |
// open field container |
| 222 |
?> |
| 223 |
<div class="vbo-precheckin-guest-detail<?php echo isset($pax_fields_attributes[$paxk]) && $pax_fields_attributes[$paxk] == 'file' ? ' vbo-precheckin-guest-detail-files' : ''; ?>"> |
| 224 |
<label for="pax-field-<?php echo $paxv . '-' . $ind . '-' . $g . '-' . $paxk; ?>"><?php echo $paxv; ?></label> |
| 225 |
<?php |
| 226 |
|
| 227 |
if ($field_rendering_type === 'paxfield') { |
| 228 |
// render the custom pax-field input element |
| 229 |
|
| 230 |
// access the implementor object |
| 231 |
$implementor = $pax_fields_obj->getFieldTypeImplementor($pax_field_obj); |
| 232 |
|
| 233 |
// check if a particular CSS class has been defined |
| 234 |
$field_container_class = $implementor->getContainerClassAttr(); |
| 235 |
$field_container_class = !empty($field_container_class) ? " $field_container_class" : ''; |
| 236 |
|
| 237 |
// display the custom field type |
| 238 |
?> |
| 239 |
<div class="vbo-precheckin-custom-field<?php echo $field_container_class; ?>"> |
| 240 |
<?php echo $pax_field_html; ?> |
| 241 |
</div> |
| 242 |
<?php |
| 243 |
} elseif ($field_rendering_type === 'select') { |
| 244 |
// select with choices |
| 245 |
?> |
| 246 |
<select name="guests[<?php echo $ind; ?>][<?php echo $g; ?>][<?php echo $paxk; ?>]"> |
| 247 |
<option></option> |
| 248 |
<?php |
| 249 |
$opt_ind = 1; |
| 250 |
foreach ($pax_fields_attributes[$paxk] as $attrk => $attrv) { |
| 251 |
$paxv_selected = isset($current_guest[$paxk]) && ($current_guest[$paxk] == $attrv || (!is_numeric($attrk) && $current_guest[$paxk] == $attrk)); |
| 252 |
if (!$paxv_selected && isset($current_guest[$paxk]) && is_numeric($current_guest[$paxk])) { |
| 253 |
/** |
| 254 |
* It is safe to compare such select tags, which usually refer to "gender", |
| 255 |
* to even numeric values in order to attempt to pre-select the current value. |
| 256 |
*/ |
| 257 |
$paxv_selected = ($opt_ind == $current_guest[$paxk]); |
| 258 |
} |
| 259 |
?> |
| 260 |
<option value="<?php echo !is_numeric($attrk) ? $attrk : $attrv; ?>"<?php echo ($paxv_selected ? ' selected="selected"' : ''); ?>><?php echo $attrv; ?></option> |
| 261 |
<?php |
| 262 |
$opt_ind++; |
| 263 |
} |
| 264 |
?> |
| 265 |
</select> |
| 266 |
<?php |
| 267 |
} elseif ($field_rendering_type === 'country') { |
| 268 |
// field of type country |
| 269 |
echo VikBooking::getCountriesSelect('guests['.$ind.']['.$g.']['.$paxk.']', $all_countries, (isset($current_guest[$paxk]) ? $current_guest[$paxk] : ''), $paxv); |
| 270 |
} elseif ($field_rendering_type === 'calendar') { |
| 271 |
// datepicker calendar |
| 272 |
?> |
| 273 |
<input type="text" autocomplete="off" data-gind="<?php echo $g; ?>" class="vbo-paxfield vbo-paxfield-datepicker" name="guests[<?php echo $ind; ?>][<?php echo $g; ?>][<?php echo $paxk; ?>]" value="<?php echo (isset($current_guest[$paxk]) ? $this->escape($current_guest[$paxk]) : ''); ?>" /> |
| 274 |
<?php |
| 275 |
} elseif ($field_rendering_type === 'file') { |
| 276 |
// file upload (multiple files allowed) |
| 277 |
?> |
| 278 |
<input type="hidden" id="vbo-paxfield-curfiles-<?php echo $ind . '-' . $g . '-' . $paxk; ?>" name="guests[<?php echo $ind; ?>][<?php echo $g; ?>][<?php echo $paxk; ?>]" value="<?php echo (isset($current_guest[$paxk]) ? $this->escape($current_guest[$paxk]) : ''); ?>" /> |
| 279 |
|
| 280 |
<div class="vbo-paxfield-upload-container"> |
| 281 |
<button type="button" class="btn vbo-pref-color-btn-secondary vbo-precheckin-uploadfile" data-roomi="<?php echo $ind; ?>" data-guesti="<?php echo $g; ?>" data-paxk="<?php echo $paxk; ?>"><?php VikBookingIcons::e('camera'); ?> <?php echo JText::translate('VBOUPSELLADD'); ?></button> |
| 282 |
<div class="vbo-paxfield-upload-progress-wrap" id="vbo-paxfield-upload-progress-<?php echo $ind . '-' . $g . '-' . $paxk; ?>" style="display: none;"> |
| 283 |
<div class="vbo-paxfield-upload-progress"> </div> |
| 284 |
</div> |
| 285 |
</div> |
| 286 |
|
| 287 |
<div class="vbo-paxfield vbo-paxfield-files" id="vbo-paxfield-files-<?php echo $ind . '-' . $g . '-' . $paxk; ?>" data-gselector="<?php echo $ind . '-' . $g . '-' . $paxk; ?>"> |
| 288 |
<?php |
| 289 |
if (isset($current_guest[$paxk]) && !empty($current_guest[$paxk])) { |
| 290 |
$guest_files = explode('|', $current_guest[$paxk]); |
| 291 |
foreach ($guest_files as $gfk => $guest_file) { |
| 292 |
if (empty($guest_file) || strpos($guest_file, 'http') !== 0) { |
| 293 |
continue; |
| 294 |
} |
| 295 |
$furl_segments = explode('/', $guest_file); |
| 296 |
$guest_fname = $furl_segments[(count($furl_segments) - 1)]; |
| 297 |
$read_fname = substr($guest_fname, (strpos($guest_fname, '_') + 1)); |
| 298 |
?> |
| 299 |
<div class="vbo-paxfield-file-uploaded"> |
| 300 |
<span class="vbo-paxfield-file-uploaded-rm"><?php VikBookingIcons::e('times-circle'); ?></span> |
| 301 |
<a href="<?php echo $guest_file; ?>" target="_blank"> |
| 302 |
<?php VikBookingIcons::e('image'); ?> |
| 303 |
<span><?php echo $read_fname; ?></span> |
| 304 |
</a> |
| 305 |
</div> |
| 306 |
<?php |
| 307 |
} |
| 308 |
} |
| 309 |
?> |
| 310 |
</div> |
| 311 |
<?php |
| 312 |
} else { |
| 313 |
// text |
| 314 |
?> |
| 315 |
<input type="text" autocomplete="off" data-gind="<?php echo $g; ?>" class="vbo-paxfield" name="guests[<?php echo $ind; ?>][<?php echo $g; ?>][<?php echo $paxk; ?>]" value="<?php echo (isset($current_guest[$paxk]) ? $this->escape($current_guest[$paxk]) : ''); ?>" /> |
| 316 |
<?php |
| 317 |
} |
| 318 |
|
| 319 |
// close field container |
| 320 |
?> |
| 321 |
</div> |
| 322 |
<?php |
| 323 |
|
| 324 |
// increase field counter |
| 325 |
$pax_field_ind++; |
| 326 |
} |
| 327 |
?> |
| 328 |
</div> |
| 329 |
<?php |
| 330 |
} |
| 331 |
?> |
| 332 |
</div> |
| 333 |
</div> |
| 334 |
</div> |
| 335 |
<?php |
| 336 |
} |
| 337 |
?> |
| 338 |
<div class="vbo-precheckin-submit"> |
| 339 |
<button type="submit" class="btn btn-large vbo-pref-color-btn"><?php echo JText::translate('VBOSUBMITPRECHECKIN'); ?></button> |
| 340 |
</div> |
| 341 |
</form> |
| 342 |
</div> |
| 343 |
|
| 344 |
</div> |
| 345 |
|
| 346 |
<input type="file" id="vbo-precheckin-upload-field" accept="image/*,.pdf" multiple="multiple" style="display: none;" /> |
| 347 |
|
| 348 |
<script type="text/javascript"> |
| 349 |
/** |
| 350 |
* Declare global score variables |
| 351 |
*/ |
| 352 |
var vbo_prechin_current_room = null, |
| 353 |
vbo_prechin_current_guest = null, |
| 354 |
vbo_prechin_current_paxk = null, |
| 355 |
vbo_typingtoast_displayed = false, |
| 356 |
vbo_typingtoast_changes = 0; |
| 357 |
|
| 358 |
/** |
| 359 |
* Displays a toast message |
| 360 |
*/ |
| 361 |
function vboPresentToast(content, duration, clickcallback) { |
| 362 |
// remove any other previous toast from the document |
| 363 |
jQuery('.vbo-toast-message').remove(); |
| 364 |
// build toast |
| 365 |
var toast = jQuery('<div>').addClass('vbo-toast-message vbo-toast-message-presented'); |
| 366 |
// onclick function |
| 367 |
var onclickfunc = function() { |
| 368 |
// hide toast when clicked |
| 369 |
jQuery(this).removeClass('vbo-toast-message-presented').addClass('vbo-toast-message-dimissed'); |
| 370 |
}; |
| 371 |
if (typeof clickcallback === 'function') { |
| 372 |
onclickfunc = function() { |
| 373 |
// launch callback |
| 374 |
clickcallback.call(this); |
| 375 |
// hide toast either way |
| 376 |
jQuery(this).removeClass('vbo-toast-message-presented').addClass('vbo-toast-message-dimissed'); |
| 377 |
}; |
| 378 |
} |
| 379 |
// register click event on toast |
| 380 |
toast.on('click', onclickfunc); |
| 381 |
// build toast content |
| 382 |
var inner = jQuery('<div>').addClass('vbo-toast-message-content'); |
| 383 |
toast.append(inner.append(content)); |
| 384 |
// present toast |
| 385 |
jQuery('body').append(toast); |
| 386 |
// set timeout for auto-dismiss |
| 387 |
if (typeof duration === 'undefined') { |
| 388 |
duration = 4000; |
| 389 |
} |
| 390 |
if (!isNaN(duration) && duration > 0) { |
| 391 |
// if duration NaN or <= 0, the toast won't be dismissed automatically |
| 392 |
setTimeout(function() { |
| 393 |
jQuery('.vbo-toast-message').removeClass('vbo-toast-message-presented').addClass('vbo-toast-message-dimissed'); |
| 394 |
}, duration); |
| 395 |
} |
| 396 |
} |
| 397 |
|
| 398 |
/** |
| 399 |
* Some older smartphones or tablets may not support files uploading |
| 400 |
*/ |
| 401 |
function vboIsUploadSupported() { |
| 402 |
if (!navigator || !navigator.userAgent) { |
| 403 |
return false; |
| 404 |
} |
| 405 |
if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) { |
| 406 |
return false; |
| 407 |
} else { |
| 408 |
return true; |
| 409 |
} |
| 410 |
} |
| 411 |
|
| 412 |
/** |
| 413 |
* Checks wether a jQuery XHR response object was due to a connection error. |
| 414 |
* Property readyState 0 = Network Error (UNSENT), 4 = HTTP error (DONE). |
| 415 |
* Property responseText may not be set in some browsers. |
| 416 |
* This is what to check to determine if a connection error occurred. |
| 417 |
*/ |
| 418 |
function vboIsConnectionLostError(err) { |
| 419 |
if (!err || !err.hasOwnProperty('status')) { |
| 420 |
return false; |
| 421 |
} |
| 422 |
|
| 423 |
return ( |
| 424 |
err.statusText == 'error' |
| 425 |
&& err.status == 0 |
| 426 |
&& (err.readyState == 0 || err.readyState == 4) |
| 427 |
&& (!err.hasOwnProperty('responseText') || err.responseText == '') |
| 428 |
); |
| 429 |
} |
| 430 |
|
| 431 |
/** |
| 432 |
* Ensures AJAX requests that fail due to connection errors are retried automatically. |
| 433 |
* This function is made specifically to work with AJAX uploads. |
| 434 |
*/ |
| 435 |
function vboDoAjaxUpload(url, data, success, failure, progress, attempt) { |
| 436 |
var VBO_AJAX_MAX_ATTEMPTS = 3; |
| 437 |
|
| 438 |
if (attempt === undefined) { |
| 439 |
attempt = 1; |
| 440 |
} |
| 441 |
|
| 442 |
var settings = { |
| 443 |
type: 'post', |
| 444 |
contentType: false, |
| 445 |
processData: false, |
| 446 |
cache: false, |
| 447 |
}; |
| 448 |
|
| 449 |
// register event for upload progress |
| 450 |
settings.xhr = function() { |
| 451 |
var xhrobj = jQuery.ajaxSettings.xhr(); |
| 452 |
if (xhrobj.upload) { |
| 453 |
// attach progress event |
| 454 |
xhrobj.upload.addEventListener('progress', function(event) { |
| 455 |
// calculate percentage |
| 456 |
var percent = 0; |
| 457 |
var position = event.loaded || event.position; |
| 458 |
var total = event.total; |
| 459 |
if (event.lengthComputable) { |
| 460 |
percent = Math.ceil(position / total * 100); |
| 461 |
} |
| 462 |
// trigger callback |
| 463 |
progress(percent); |
| 464 |
}, false); |
| 465 |
} |
| 466 |
return xhrobj; |
| 467 |
}; |
| 468 |
|
| 469 |
if (typeof url === 'object') { |
| 470 |
// configuration object passed |
| 471 |
Object.assign(settings, url); |
| 472 |
} else { |
| 473 |
// use the default settings |
| 474 |
settings.url = url; |
| 475 |
} |
| 476 |
|
| 477 |
// set request data |
| 478 |
settings.data = data; |
| 479 |
|
| 480 |
return jQuery.ajax( |
| 481 |
settings |
| 482 |
).done(function(resp) { |
| 483 |
if (success !== undefined) { |
| 484 |
// launch success callback function |
| 485 |
success(resp); |
| 486 |
} |
| 487 |
}).fail(function(err) { |
| 488 |
/** |
| 489 |
* If the error is caused by a site connection lost, and if the number |
| 490 |
* of retries is lower than max attempts, retry the same AJAX request. |
| 491 |
*/ |
| 492 |
if (attempt < VBO_AJAX_MAX_ATTEMPTS && vboIsConnectionLostError(err)) { |
| 493 |
// delay the retry by half second |
| 494 |
setTimeout(function() { |
| 495 |
// relaunch same request and increase number of attempts |
| 496 |
console.log('Retrying previous AJAX request'); |
| 497 |
vboDoAjaxUpload(url, data, success, failure, progress, (attempt + 1)); |
| 498 |
}, 500); |
| 499 |
} else { |
| 500 |
// launch the failure callback otherwise |
| 501 |
if (failure !== undefined) { |
| 502 |
failure(err); |
| 503 |
} |
| 504 |
} |
| 505 |
|
| 506 |
// always log the error in console |
| 507 |
console.log('AJAX request failed' + (err.status == 500 ? ' (' + err.responseText + ')' : ''), err); |
| 508 |
}); |
| 509 |
} |
| 510 |
|
| 511 |
/** |
| 512 |
* Updates the progress bar for the current uploading process |
| 513 |
*/ |
| 514 |
function vboUploadSetProgress(selector_suffix, progress) { |
| 515 |
progress = Math.max(0, progress); |
| 516 |
progress = Math.min(100, progress); |
| 517 |
|
| 518 |
var progress_wrap = jQuery('#vbo-paxfield-upload-progress-' + selector_suffix); |
| 519 |
if (!progress_wrap.length) { |
| 520 |
return; |
| 521 |
} |
| 522 |
progress_wrap.find('.vbo-paxfield-upload-progress').width(progress + '%').html(progress + '%'); |
| 523 |
} |
| 524 |
|
| 525 |
/** |
| 526 |
* Uploads the selected document(s) |
| 527 |
*/ |
| 528 |
function vboUploadDocuments(files) { |
| 529 |
// create form data object |
| 530 |
var formData = new FormData(); |
| 531 |
|
| 532 |
// set booking and pre-checkin information |
| 533 |
formData.append('sid', '<?php echo empty($this->order['sid']) && !empty($this->order['idorderota']) ? $this->order['idorderota'] : $this->order['sid']; ?>'); |
| 534 |
formData.append('ts', '<?php echo $this->order['ts']; ?>'); |
| 535 |
formData.append('room_index', vbo_prechin_current_room); |
| 536 |
formData.append('guest_index', vbo_prechin_current_guest); |
| 537 |
formData.append('pax_index', vbo_prechin_current_paxk); |
| 538 |
|
| 539 |
// selector suffix is composed of room, guest and pax field indexes |
| 540 |
var selector_suffix = vbo_prechin_current_room + '-' + vbo_prechin_current_guest + '-' + vbo_prechin_current_paxk; |
| 541 |
|
| 542 |
// iterate files selected and append them to the form data |
| 543 |
for (var i = 0; i < files.length; i++) { |
| 544 |
formData.append('docs[]', files[i]); |
| 545 |
} |
| 546 |
|
| 547 |
// display progress wrap |
| 548 |
jQuery('#vbo-paxfield-upload-progress-' + selector_suffix).show(); |
| 549 |
|
| 550 |
// AJAX request to upload the files selected |
| 551 |
vboDoAjaxUpload( |
| 552 |
// url |
| 553 |
'<?php echo VikBooking::ajaxUrl(JRoute::rewrite('index.php?option=com_vikbooking&task=precheckin_upload_docs&tmpl=component'.(!empty($pitemid) ? '&Itemid='.$pitemid : ''), false)); ?>', |
| 554 |
// form data |
| 555 |
formData, |
| 556 |
// success callback |
| 557 |
function(response) { |
| 558 |
// hide progress wrap |
| 559 |
jQuery('#vbo-paxfield-upload-progress-' + selector_suffix).hide(); |
| 560 |
// unset progress |
| 561 |
vboUploadSetProgress(selector_suffix, 0); |
| 562 |
|
| 563 |
// parse response |
| 564 |
try { |
| 565 |
var obj_res = JSON.parse(response), |
| 566 |
uploaded_urls = []; |
| 567 |
|
| 568 |
for (var i in obj_res) { |
| 569 |
if (!obj_res.hasOwnProperty(i) || !obj_res[i].hasOwnProperty('url')) { |
| 570 |
continue; |
| 571 |
} |
| 572 |
uploaded_urls.push(obj_res[i]['url']); |
| 573 |
} |
| 574 |
if (!uploaded_urls.length) { |
| 575 |
console.log('no valid URLs returned', response); |
| 576 |
return false; |
| 577 |
} |
| 578 |
// update hidden field |
| 579 |
var hidden_inp = jQuery('#vbo-paxfield-curfiles-' + selector_suffix); |
| 580 |
var current_guest_files = hidden_inp.val().split('|'); |
| 581 |
if (!current_guest_files.length || !current_guest_files[0].length) { |
| 582 |
current_guest_files = []; |
| 583 |
} |
| 584 |
// merge current files with new ones uploaded |
| 585 |
var new_guest_files = current_guest_files.concat(uploaded_urls); |
| 586 |
// update hidden input field to contain all files |
| 587 |
hidden_inp.val(new_guest_files.join('|')); |
| 588 |
// display links for the newly uploaded files |
| 589 |
var uploaded_content = ''; |
| 590 |
for (var i = 0; i < uploaded_urls.length; i++) { |
| 591 |
var furl_segments = uploaded_urls[i].split('/'); |
| 592 |
var guest_fname = furl_segments[(furl_segments.length - 1)]; |
| 593 |
var read_fname = guest_fname.substr((guest_fname.indexOf('_') + 1)); |
| 594 |
|
| 595 |
uploaded_content += '<div class="vbo-paxfield-file-uploaded">'; |
| 596 |
uploaded_content += ' <span class="vbo-paxfield-file-uploaded-rm"><?php VikBookingIcons::e('times-circle'); ?></span>'; |
| 597 |
uploaded_content += ' <a href="' + uploaded_urls[i] + '" target="_blank">'; |
| 598 |
uploaded_content += ' <?php VikBookingIcons::e('image'); ?>'; |
| 599 |
uploaded_content += ' <span>' + read_fname + '</span>'; |
| 600 |
uploaded_content += ' </a>'; |
| 601 |
uploaded_content += '</div>'; |
| 602 |
} |
| 603 |
// append the new content |
| 604 |
jQuery('#vbo-paxfield-files-' + selector_suffix).append(uploaded_content); |
| 605 |
|
| 606 |
// display toast message |
| 607 |
vboPresentToast(Joomla.JText._('VBO_PRECHECKIN_TOAST_HELP'), 4000, function() { |
| 608 |
jQuery('html,body').animate({scrollTop: jQuery('.vbo-precheckin-submit').offset().top - 100}, {duration: 400}); |
| 609 |
}); |
| 610 |
} catch(err) { |
| 611 |
console.error('could not parse JSON response for uploading documents', err, response); |
| 612 |
} |
| 613 |
}, |
| 614 |
// failure callback |
| 615 |
function(error) { |
| 616 |
alert(Joomla.JText._('VBO_UPLOAD_FAILED')); |
| 617 |
// hide progress wrap |
| 618 |
jQuery('#vbo-paxfield-upload-progress-' + selector_suffix).hide(); |
| 619 |
// unset progress |
| 620 |
vboUploadSetProgress(selector_suffix, 0); |
| 621 |
|
| 622 |
console.error(error); |
| 623 |
}, |
| 624 |
// progress callback |
| 625 |
function(progress) { |
| 626 |
// update progress bar |
| 627 |
vboUploadSetProgress(selector_suffix, progress); |
| 628 |
} |
| 629 |
); |
| 630 |
} |
| 631 |
|
| 632 |
/** |
| 633 |
* Declare functions for DOM ready |
| 634 |
*/ |
| 635 |
jQuery(function() { |
| 636 |
|
| 637 |
/** |
| 638 |
* Datepicker for birth date |
| 639 |
*/ |
| 640 |
jQuery('.vbo-paxfield-datepicker').datepicker({ |
| 641 |
dateFormat: "<?php echo $juidf; ?>", |
| 642 |
changeMonth: true, |
| 643 |
changeYear: true, |
| 644 |
yearRange: "<?php echo (date('Y') - 100) . ':' . date('Y'); ?>" |
| 645 |
}); |
| 646 |
|
| 647 |
/** |
| 648 |
* Click event on file-upload button |
| 649 |
*/ |
| 650 |
jQuery('.vbo-precheckin-uploadfile').click(function() { |
| 651 |
var elem = jQuery(this); |
| 652 |
|
| 653 |
var room_index = elem.data('roomi'), |
| 654 |
guest_index = elem.data('guesti'), |
| 655 |
pax_index = elem.data('paxk'); |
| 656 |
|
| 657 |
// check if device supports file upload |
| 658 |
if (!vboIsUploadSupported()) { |
| 659 |
alert('Your device may not support files uploading'); |
| 660 |
return false; |
| 661 |
} |
| 662 |
|
| 663 |
// update global vars |
| 664 |
vbo_prechin_current_room = room_index; |
| 665 |
vbo_prechin_current_guest = guest_index; |
| 666 |
vbo_prechin_current_paxk = pax_index; |
| 667 |
|
| 668 |
// trigger the click event on the hidden input field for the files upload |
| 669 |
jQuery('#vbo-precheckin-upload-field').trigger('click'); |
| 670 |
}); |
| 671 |
|
| 672 |
/** |
| 673 |
* Change event on global file-upload hidden field |
| 674 |
*/ |
| 675 |
jQuery('#vbo-precheckin-upload-field').on('change', function(e) { |
| 676 |
// get files selected |
| 677 |
var files = jQuery(this)[0].files; |
| 678 |
|
| 679 |
if (!files || !files.length) { |
| 680 |
console.error('no files selected for upload'); |
| 681 |
return false; |
| 682 |
} |
| 683 |
|
| 684 |
// upload selected files |
| 685 |
vboUploadDocuments(files); |
| 686 |
|
| 687 |
// make the input value empty |
| 688 |
jQuery(this).val(null); |
| 689 |
}); |
| 690 |
|
| 691 |
/** |
| 692 |
* Click event on the button to remove an uploaded file |
| 693 |
*/ |
| 694 |
jQuery(document.body).on('click', '.vbo-paxfield-file-uploaded-rm', function() { |
| 695 |
var file_container = jQuery(this).closest('.vbo-paxfield-file-uploaded'); |
| 696 |
if (!file_container.length) { |
| 697 |
return false; |
| 698 |
} |
| 699 |
var file_url = file_container.find('a').attr('href'); |
| 700 |
var files_selector = file_container.closest('.vbo-paxfield-files').attr('data-gselector'); |
| 701 |
if (confirm(Joomla.JText._('VBO_REMOVEF_CONFIRM'))) { |
| 702 |
var pax_elem = jQuery('#vbo-paxfield-curfiles-' + files_selector); |
| 703 |
var pax_urls = pax_elem.val(); |
| 704 |
if (pax_urls.indexOf(file_url + '|') >= 0) { |
| 705 |
pax_urls = pax_urls.replace(file_url + '|', ''); |
| 706 |
} else if (pax_urls.indexOf('|' + file_url) >= 0) { |
| 707 |
pax_urls = pax_urls.replace('|' + file_url, ''); |
| 708 |
} else { |
| 709 |
pax_urls = pax_urls.replace(file_url, ''); |
| 710 |
} |
| 711 |
// update hidden input value |
| 712 |
pax_elem.val(pax_urls); |
| 713 |
// remove the file container |
| 714 |
file_container.remove(); |
| 715 |
// display toast message |
| 716 |
vboPresentToast(Joomla.JText._('VBO_PRECHECKIN_TOAST_HELP'), 4000, function() { |
| 717 |
jQuery('html,body').animate({scrollTop: jQuery('.vbo-precheckin-submit').offset().top - 100}, {duration: 400}); |
| 718 |
}); |
| 719 |
} |
| 720 |
}); |
| 721 |
|
| 722 |
/** |
| 723 |
* Change event on input fields to trigger the toast message |
| 724 |
*/ |
| 725 |
jQuery('.vbo-precheckin-room-wrapper').find('input[type="text"], select').on('change', function() { |
| 726 |
// if toast displayed and clicked, unset listener |
| 727 |
if (vbo_typingtoast_displayed === true) { |
| 728 |
jQuery('.vbo-precheckin-room-wrapper').find('input[type="text"], select').off('change'); |
| 729 |
} |
| 730 |
// increase counter |
| 731 |
vbo_typingtoast_changes++; |
| 732 |
if (vbo_typingtoast_changes > 2) { |
| 733 |
// reset counter |
| 734 |
vbo_typingtoast_changes = 0; |
| 735 |
// display toast message |
| 736 |
vboPresentToast(Joomla.JText._('VBO_PRECHECKIN_TOAST_HELP'), 4000, function() { |
| 737 |
jQuery('html,body').animate({scrollTop: jQuery('.vbo-precheckin-submit').offset().top - 100}, {duration: 400}); |
| 738 |
// if toast is clicked, we never display it again |
| 739 |
vbo_typingtoast_displayed = true; |
| 740 |
}); |
| 741 |
} |
| 742 |
}); |
| 743 |
|
| 744 |
}); |
| 745 |
</script> |
| 746 |
|