PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.5
VikBooking Hotel Booking Engine & PMS v1.6.5
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / views / tableaux / tmpl / default.php

default.php in VikBooking Hotel Booking Engine & PMS 1.6.5, at admin/views/tableaux/tmpl/default.php

1,636 lines 67.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 $roomids = $this->roomids;
14 $rooms = $this->rooms;
15 $rooms_busy = $this->rooms_busy;
16 $months = $this->months;
17 $fromts = $this->fromts;
18 $tots = $this->tots;
19
20 $vbo_app = VikBooking::getVboApplication();
21 $vbo_app->loadSelect2();
22 $vbo_app->loadDatePicker();
23
24 JHtml::fetch('script', VBO_ADMIN_URI . 'resources/js_upload/jquery.stickytableheaders.min.js');
25
26 $nowdf = VikBooking::getDateFormat(true);
27 if ($nowdf == "%d/%m/%Y") {
28 $df = 'd/m/Y';
29 } elseif ($nowdf == "%m/%d/%Y") {
30 $df = 'm/d/Y';
31 } else {
32 $df = 'Y/m/d';
33 }
34 $datesep = VikBooking::getDateSeparator(true);
35 $juidf = $nowdf == "%d/%m/%Y" ? 'dd/mm/yy' : ($nowdf == "%m/%d/%Y" ? 'mm/dd/yy' : 'yy/mm/dd');
36 $currencysymb = VikBooking::getCurrencySymb(true);
37
38 $month = VikRequest::getInt('month', 0, 'request');
39 $printtableaux = VikRequest::getInt('printtableaux', 0, 'request');
40
41 $colortags = VikBooking::loadBookingsColorTags();
42
43 $days_labels = array(
44 JText::translate('VBSUN'),
45 JText::translate('VBMON'),
46 JText::translate('VBTUE'),
47 JText::translate('VBWED'),
48 JText::translate('VBTHU'),
49 JText::translate('VBFRI'),
50 JText::translate('VBSAT')
51 );
52 $months_labels = array(
53 JText::translate('VBMONTHONE'),
54 JText::translate('VBMONTHTWO'),
55 JText::translate('VBMONTHTHREE'),
56 JText::translate('VBMONTHFOUR'),
57 JText::translate('VBMONTHFIVE'),
58 JText::translate('VBMONTHSIX'),
59 JText::translate('VBMONTHSEVEN'),
60 JText::translate('VBMONTHEIGHT'),
61 JText::translate('VBMONTHNINE'),
62 JText::translate('VBMONTHTEN'),
63 JText::translate('VBMONTHELEVEN'),
64 JText::translate('VBMONTHTWELVE')
65 );
66 $long_months_labels = $months_labels;
67 foreach ($months_labels as $i => $v) {
68 $months_labels[$i] = function_exists('mb_substr') ? mb_substr($v, 0, 3, 'UTF-8') : substr($v, 0, 3);
69 }
70
71 ?>
72 <div class="vbo-tableaux-container">
73 <form name="adminForm" action="index.php?option=com_vikbooking&task=tableaux" method="post" id="adminForm">
74 <div class="vbo-tableaux-months-wrap">
75 <?php
76 foreach ($months as $mdata) {
77 ?>
78 <div class="vbo-tableaux-month-cont">
79 <div class="vbo-tableaux-month-link<?php echo $month == $mdata['from'] ? ' vbo-tableaux-month-link-active' : ''; ?>">
80 <span class="vbo-tableaux-selmonth" data-ts="<?php echo $mdata['from']; ?>" data-from="<?php echo date($df, $mdata['from']); ?>" data-to="<?php echo date($df, $mdata['to']); ?>"><?php echo $mdata['name']; ?></span>
81 </div>
82 </div>
83 <?php
84 }
85 ?>
86 </div>
87 <div id="filter-bar" class="btn-toolbar vbo-btn-toolbar vbo-tableaux-filters" style="width: 100%; display: inline-block;">
88 <div class="btn-group pull-left" style="font-size: 12px;">
89 <select id="roomsel" name="roomids[]" multiple="multiple">
90 <?php
91 foreach ($this->allrooms as $rid => $rdata) {
92 ?>
93 <option value="<?php echo $rid; ?>"<?php echo in_array($rid, $roomids) ? ' selected="selected"' : ''; ?>><?php echo $rdata['name']; ?></option>
94 <?php
95 }
96
97 /**
98 * Use the optgroup to separate rooms from categories in the
99 * drop down menu, only if allrooms > 1 e categories > 1.
100 *
101 * @since 1.13.5
102 */
103 if (count($this->allrooms) > 1 && count($this->categories) > 1) {
104 ?>
105 <optgroup label="<?php echo addslashes(JText::translate('VBOCATEGORYFILTER')); ?>">
106 <?php
107 foreach ($this->categories as $cat) {
108 // we use negative values for the IDs of the categories
109 $cat_id = ($cat['id'] - ($cat['id'] * 2));
110 ?>
111 <option value="<?php echo $cat_id; ?>"><?php echo (in_array($cat['id'], $this->reqcats) ? '- ' : '') . $cat['name']; ?></option>
112 <?php
113 }
114 ?>
115 </optgroup>
116 <?php
117 }
118 //
119 ?>
120 </select>
121 </div>
122 <div class="btn-group pull-left">
123 <span style="font-size: 15px;">&nbsp;</span>
124 </div>
125 <div class="btn-group pull-left input-append">
126 <input type="text" id="vbo-date-from" placeholder="<?php echo JText::translate('VBNEWSEASONONE'); ?>" value="<?php echo date($df, $fromts); ?>" size="14" name="fromdate" onfocus="this.blur();" />
127 <button type="button" class="btn" id="vbo-date-from-trig"><i class="icon-calendar"></i></button>
128 </div>
129 <div class="btn-group pull-left input-append">
130 <input type="text" id="vbo-date-to" placeholder="<?php echo JText::translate('VBNEWSEASONTWO'); ?>" value="<?php echo date($df, $tots); ?>" size="14" name="todate" onfocus="this.blur();" />
131 <button type="button" class="btn" id="vbo-date-to-trig"><i class="icon-calendar"></i></button>
132 </div>
133 <div class="btn-group pull-left">
134 <span style="font-size: 15px;">&nbsp;</span>
135 </div>
136 <div class="btn-group pull-left">
137 <button type="submit" class="btn"><i class="icon-search"></i> <?php echo JText::translate('VBAPPLY'); ?></button>
138 </div>
139 <div class="btn-group pull-right">
140 <a href="javascript: void(0);" onclick="vboManagePermissions();" class="vbo-perms-operators"><i class="vboicn-user-plus icn-nomargin"></i> <span><?php echo JText::translate('VBOPERMSOPERATORS'); ?></span></a>
141 </div>
142 <div class="btn-group pull-right">
143 <a href="javascript: void(0);" onclick="vboSendPrintTableaux();" class="vbcsvexport"><?php VikBookingIcons::e('print'); ?> <span><?php echo JText::translate('VBOPRINT'); ?></span></a>
144 </div>
145 </div>
146 <input type="hidden" name="month" id="vbo-month" value="<?php echo $month; ?>" />
147 <input type="hidden" name="task" value="tableaux" />
148 <input type="hidden" name="option" value="com_vikbooking" />
149 </form>
150
151 <?php
152 // count the cells per month
153 $thead_info = array();
154 $months_days = array();
155 $nowinfo = getdate($fromts);
156 while ($nowinfo[0] <= $tots) {
157 $mkey = $nowinfo['mon'] . '_' . $nowinfo['year'];
158 if (!isset($months_days[$mkey])) {
159 $months_days[$mkey] = 0;
160 }
161 $months_days[$mkey]++;
162 // push information for the table head
163 array_push($thead_info, array(
164 'mon' => $long_months_labels[($nowinfo['mon'] - 1)],
165 'mday' => $nowinfo['mday'],
166 'wday' => $days_labels[$nowinfo['wday']],
167 'year' => $nowinfo['year'],
168 'ts' => $nowinfo[0],
169 ));
170 // next loop
171 $nowinfo = getdate(mktime(0, 0, 0, $nowinfo['mon'], ($nowinfo['mday'] + 1), $nowinfo['year']));
172 }
173
174 // today
175 $todaydt = date('Y-m-d');
176 ?>
177
178 <div class="vbo-tableaux-tbl-container">
179 <div class="vbo-table-responsive vbo-tableaux-tbl-wrap" id="vbo-tableaux-table-scroller">
180 <table class="vbo-table vbo-tableaux-table">
181 <thead class="vbo-tableaux-table-head" style="display: none;">
182 <tr class="vbo-tableaux-table-head-row">
183 <th class="vbo-tableaux-table-head-cell vbo-tableaux-table-head-cell-empty">&nbsp;</th>
184 <?php
185 foreach ($thead_info as $head_day) {
186 ?>
187 <th class="vbo-tableaux-table-head-cell">
188 <div class="vbo-tableaux-table-head-cell-monyear">
189 <span><?php echo $head_day['mon'] . ' ' . $head_day['year']; ?></span>
190 </div>
191 <div class="vbo-tableaux-table-head-cell-wmday">
192 <span><?php echo $head_day['wday'] . ' ' . $head_day['mday']; ?></span>
193 </div>
194 </th>
195 <?php
196 }
197 ?>
198 </tr>
199 </thead>
200 <tbody>
201 <tr class="vbo-tableaux-monthsrow">
202 <td class="vbo-tableaux-emptycell">&nbsp;</td>
203 <?php
204 foreach ($months_days as $mkey => $totdays) {
205 $mkeyparts = explode('_', $mkey);
206 ?>
207 <td class="vbo-tableaux-monthcell" colspan="<?php echo $totdays; ?>"><?php echo $long_months_labels[($mkeyparts[0] - 1)] . ' ' . $mkeyparts[1]; ?></td>
208 <?php
209 }
210 ?>
211 </tr>
212 <tr class="vbo-tableaux-firstrow">
213 <td class="vbo-tableaux-emptycell">&nbsp;</td>
214 <?php
215 $newmonth = 0;
216 $nowinfo = getdate($fromts);
217 while ($nowinfo[0] <= $tots) {
218 $nowinfo_ymd = date('Y-m-d', $nowinfo[0]);
219 $monthclass = !empty($newmonth) && $nowinfo['mon'] != $newmonth ? ' vbo-tableaux-newmonthcell' : '';
220 $monthclass = $nowinfo_ymd == $todaydt ? ' vbo-tableaux-todaycell' : $monthclass;
221 $newmonth = $nowinfo['mon'];
222 $read_day = $days_labels[$nowinfo['wday']] . ' ' . $nowinfo['mday'] . ' ' . $months_labels[($nowinfo['mon'] - 1)] . ' ' . $nowinfo['year'];
223 $fest_class = isset($this->festivities[$nowinfo_ymd]) ? ' vbo-tableaux-festcell' : '';
224 ?>
225 <td class="vbo-tableaux-daycell<?php echo $monthclass . $fest_class; ?>"<?php echo $printtableaux > 0 ? ' width="100' : ''; ?> data-ymd="<?php echo $nowinfo_ymd; ?>" data-readymd="<?php echo $read_day; ?>">
226 <div class="vbo-tableaux-day-cont">
227 <span class="vbo-tableaux-day-wday"><?php echo $days_labels[$nowinfo['wday']]; ?></span>
228 <span class="vbo-tableaux-day-mday"><?php echo $nowinfo['mday']; ?></span>
229 </div>
230 </td>
231 <?php
232 // next loop
233 $nowinfo = getdate(mktime(0, 0, 0, $nowinfo['mon'], ($nowinfo['mday'] + 1), $nowinfo['year']));
234 }
235 ?>
236 </tr>
237 <?php
238 $rooms_features_map = array();
239 $rooms_features_bookings = array();
240 $colortags_map = array();
241 foreach ($rooms as $rid => $rdata) {
242 // distinctive features
243 $room_params = !empty($rdata['params']) ? json_decode($rdata['params'], true) : array();
244 if (is_array($room_params) && array_key_exists('features', $room_params) && count($room_params['features']) > 0) {
245 $rooms_features_map[$rid] = array();
246 foreach ($room_params['features'] as $rind => $rfeatures) {
247 foreach ($rfeatures as $fname => $fval) {
248 if (strlen($fval)) {
249 $rooms_features_map[$rid][$rind] = '#'.$fval;
250 break;
251 }
252 }
253 }
254 if (!(count($rooms_features_map[$rid]) > 0)) {
255 unset($rooms_features_map[$rid]);
256 }
257 }
258 // extra class for single-unit rooms
259 $room_extra_class = $rdata['units'] == 1 ? 'vbo-tableaux-booking-singleunit ' : '';
260 ?>
261 <tr class="vbo-tableaux-roomrow">
262 <td class="vbo-tableaux-roomname" data-roomid="<?php echo $rdata['id']; ?>"><?php echo $rdata['name']; ?></td>
263 <?php
264 $nowinfo = getdate($fromts);
265 $bookbuffer = array();
266 $prevbuffer = array();
267 $positions = array();
268 $newmonth = 0;
269 while ($nowinfo[0] <= $tots) {
270 $nowinfo_ymd = date('Y-m-d', $nowinfo[0]);
271 $monthclass = !empty($newmonth) && $nowinfo['mon'] != $newmonth ? ' vbo-tableaux-newmonthcell' : '';
272 $monthclass = $nowinfo_ymd == $todaydt ? ' vbo-tableaux-todaycell' : $monthclass;
273 $newmonth = $nowinfo['mon'];
274
275 /**
276 * Critical dates defined at room-day level, or for any sub-unit.
277 *
278 * @since 1.13.5
279 */
280 $rdaynote_class = ' vbo-roomdaynote-empty';
281 $rdaynote_icn = 'far fa-sticky-note';
282 $cell_rdnotes = '';
283 $rdnkeys_lookup = range(0, $rdata['units']);
284 $rdaynote_keyids = array();
285 $glob_rdn_keyid = $nowinfo_ymd . '_' . $rdata['id'] . '_0';
286 // find room-day note keys with some notes (room-day level or subroom-day level)
287 foreach ($rdnkeys_lookup as $lookup_index) {
288 $rdaynote_keyid = $nowinfo_ymd . '_' . $rdata['id'] . '_' . $lookup_index;
289 if (isset($this->rdaynotes[$rdaynote_keyid])) {
290 // push associative index with notes
291 $rdaynote_keyids[$lookup_index] = $rdaynote_keyid;
292 }
293 }
294 if (count($rdaynote_keyids)) {
295 // some notes exist for this combination of date, room ID and subunit
296 $rdaynote_class = ' vbo-roomdaynote-full';
297 $rdaynote_icn = 'sticky-note';
298 /**
299 * Try to populate the notes for this room-day cell
300 * only if the previous day does not have the same note.
301 * Just the first readable room-day cell should have notes.
302 */
303 $notes_titles = array();
304 $yesterday_ts = mktime(0, 0, 0, $nowinfo['mon'], ($nowinfo['mday'] - 1), $nowinfo['year']);
305 $yesterday_ymd = date('Y-m-d', $yesterday_ts);
306 // loop through all the keys with notes
307 foreach ($rdaynote_keyids as $lookup_index => $rdaynote_keyid) {
308 $yesterday_keyid = $yesterday_ymd . '_' . $rdata['id'] . '_' . $lookup_index;
309 foreach ($this->rdaynotes[$rdaynote_keyid]['info'] as $today_note) {
310 // only manual (custom) room-day notes will be displayed
311 $display_note = ($today_note->type == 'custom');
312 if (isset($this->rdaynotes[$yesterday_keyid])) {
313 // make sure the same note is not present for yesterday
314 foreach ($this->rdaynotes[$yesterday_keyid]['info'] as $yesterday_note) {
315 if ($today_note->type == $yesterday_note->type && $today_note->name == $yesterday_note->name) {
316 // same note available also for yesterday
317 $display_note = false;
318 break;
319 }
320 }
321 }
322 if ($display_note) {
323 // push just the name of the note
324 array_push($notes_titles, $today_note->name);
325 }
326 }
327 }
328 // separate all notes (if any) with comma
329 $cell_rdnotes = implode(', ', $notes_titles);
330 //
331 }
332 //
333
334 ?>
335 <td class="vbo-tableaux-roombooks<?php echo $monthclass . $rdaynote_class; ?>" data-day="<?php echo $nowinfo_ymd; ?>" data-dayrid="<?php echo $nowinfo_ymd . $rdata['id']; ?>" data-rdnkeys="<?php echo implode(',', array_keys($rdaynote_keyids)); ?>" data-notes="<?php echo $this->escape($cell_rdnotes); ?>">
336 <?php
337 $room_bookings = array();
338 if (isset($rooms_busy[$rid])) {
339 foreach ($rooms_busy[$rid] as $b) {
340 $tmpone = getdate($b['checkin']);
341 $ritts = mktime(0, 0, 0, $tmpone['mon'], $tmpone['mday'], $tmpone['year']);
342 $tmptwo = getdate($b['checkout']);
343 $conts = mktime(0, 0, 0, $tmptwo['mon'], $tmptwo['mday'], $tmptwo['year']);
344 $b['basefrom'] = $ritts;
345 $b['baseto'] = $conts;
346 if ($nowinfo[0] >= $ritts && $nowinfo[0] <= $conts) {
347 array_push($room_bookings, $b);
348 }
349 }
350 /**
351 * By default, we attempt to sort the bookings for this day by room index.
352 *
353 * @since 1.13.5 (J) - 1.3.5 (WP)
354 */
355 if (count($room_bookings)) {
356 $rindexes_map = array();
357 foreach ($room_bookings as $rbk => $rbval) {
358 $rindexes_map[$rbk] = isset($rbval['indexes']) ? $rbval['indexes'] : '';
359 }
360 asort($rindexes_map);
361 $room_bookings_copy = array();
362 foreach ($rindexes_map as $rbk => $rbval) {
363 array_push($room_bookings_copy, $room_bookings[$rbk]);
364 }
365 $room_bookings = $room_bookings_copy;
366 }
367 //
368 }
369 if (count($room_bookings) && count($bookbuffer)) {
370 // sort bookings according to the previous map
371 $newbookings = array();
372 foreach ($bookbuffer as $oid) {
373 foreach ($room_bookings as $kb => $rbook) {
374 if ($oid == $rbook['idorder']) {
375 // get this key first
376 $newbookings[$kb] = $rbook;
377 // do not break the loop as there could be multiple idorder, just continue
378 continue;
379 }
380 }
381 }
382 if (count($newbookings)) {
383 // merge array by keys by unsetting double keys from second array
384 $room_bookings = $newbookings + $room_bookings;
385 }
386 // copy buffer before reset to see whether this is the first cell displayed for the booking
387 $prevbuffer = $bookbuffer;
388 // reset buffer to fill the current day bookings
389 $bookbuffer = array();
390 }
391 $indexpos = 0;
392 foreach ($room_bookings as $k => $rbook) {
393 $contclass = 'stay';
394 if ($rbook['basefrom'] == $nowinfo[0]) {
395 $contclass = 'checkin';
396 } elseif ($rbook['baseto'] == $nowinfo[0]) {
397 $contclass = 'checkout';
398 }
399 $shortstaycls = '';
400 if (ceil(($rbook['baseto'] - $rbook['basefrom']) / 86400) < 2) {
401 $shortstaycls = ' vbo-tableaux-booking-short';
402 }
403 //check position
404 $pos = $indexpos;
405 if (isset($positions[$rbook['idorder']]) && $indexpos < $positions[$rbook['idorder']]) {
406 // print empty blocks to give the right position to this booking
407 $pos = $indexpos.'-'.$positions[$rbook['idorder']];
408 $looplim = ($positions[$rbook['idorder']] - $indexpos);
409 for ($i = 0; $i < $looplim; $i++) {
410 $indexpos++;
411 ?>
412 <div class="<?php echo $room_extra_class; ?>vbo-tableaux-booking vbo-tableaux-booking-empty">
413 <span>&nbsp;</span>
414 </div>
415 <?php
416 }
417 $pos .= '-'.$indexpos;
418 }
419 // push position
420 if (!isset($positions[$rbook['idorder']])) {
421 $positions[$rbook['idorder']] = $indexpos;
422 }
423 // push booking to the buffer for the ordering in the next loop
424 array_push($bookbuffer, $rbook['idorder']);
425
426 // cell content
427 $cellcont = '&nbsp;';
428
429 // booking color tag (if enabled from overv View through cookie or session)
430 if ($this->pbmode == 'tags' && !isset($colortags_map[$rbook['idorder']])) {
431 $colortags_map[$rbook['idorder']] = VikBooking::applyBookingColorTag($rbook);
432 }
433
434 if (!in_array($rbook['idorder'], $prevbuffer)) {
435 // first time we print the details for this booking - compose the content of the element
436 $cellcont = '';
437
438 // customer details
439 if (!empty($rbook['first_name']) || !empty($rbook['last_name'])) {
440 /**
441 * Check if we need to display a profile picture or a channel logo.
442 *
443 * @since 1.16.0 (J) - 1.6.0 (WP)
444 */
445 $booking_avatar_src = null;
446 $booking_avatar_alt = null;
447 if (!empty($rbook['pic'])) {
448 // customer profile picture
449 $booking_avatar_src = strpos($rbook['pic'], 'http') === 0 ? $rbook['pic'] : VBO_SITE_URI . 'resources/uploads/' . $rbook['pic'];
450 $booking_avatar_alt = basename($booking_avatar_src);
451 } elseif (!empty($rbook['channel'])) {
452 // channel logo
453 $logo_helper = VikBooking::getVcmChannelsLogo($rbook['channel'], $get_istance = true);
454 if ($logo_helper !== false) {
455 $booking_avatar_src = $logo_helper->getSmallLogoURL();
456 $booking_avatar_alt = $logo_helper->provenience;
457 }
458 }
459
460 if (!empty($booking_avatar_src)) {
461 // make sure the alt attribute is not too long in case of broken images
462 $booking_avatar_alt = !empty($booking_avatar_alt) && strlen($booking_avatar_alt) > 15 ? '...' . substr($booking_avatar_alt, -12) : $booking_avatar_alt;
463 // append booking avatar image
464 $cellcont .= '<span class="vbo-tableaux-booking-avatar"><img src="' . $booking_avatar_src . '" class="vbo-tableaux-booking-avatar-img" ' . (!empty($booking_avatar_alt) ? 'alt="' . htmlspecialchars($booking_avatar_alt) . '" ' : '') . '/></span>';
465 }
466
467 // customer record
468 $cellcont .= '<span class="vbo-tableaux-guest-name">' . $rbook['first_name'] . ' ' . $rbook['last_name'] . '</span>';
469 } else {
470 // parse the customer data string
471 $custdata_parts = explode("\n", $rbook['custdata']);
472 $enoughinfo = false;
473 if (count($custdata_parts) > 2 && strpos($custdata_parts[0], ':') !== false && strpos($custdata_parts[1], ':') !== false) {
474 // get the first two fields
475 $custvalues = array();
476 foreach ($custdata_parts as $custdet) {
477 if (strlen($custdet) < 1) {
478 continue;
479 }
480 $custdet_parts = explode(':', $custdet);
481 if (count($custdet_parts) >= 2) {
482 unset($custdet_parts[0]);
483 array_push($custvalues, trim(implode(':', $custdet_parts)));
484 }
485 if (count($custvalues) > 1) {
486 break;
487 }
488 }
489 if (count($custvalues) > 1) {
490 $enoughinfo = true;
491 $cellcont .= '<span class="vbo-tableaux-guest-name">' . implode(' ', $custvalues) . '</span>';;
492 }
493 }
494 if (!$enoughinfo) {
495 $cellcont .= '<span class="vbo-tableaux-guest-name">' . $rbook['idorder'] . '</span>';;
496 }
497 }
498
499 // distinctive features
500 if (!empty($rbook['indexes']) && isset($rooms_features_map[$rid])) {
501 $bookindexes = explode(';', $rbook['indexes']);
502 $roomindexes = explode(';', $rbook['roomids']);
503 if (!isset($rooms_features_bookings[$rid.'_'.$rbook['idorder']])) {
504 // the index to read of the feature depending on how many times this booking was printed (in case of multiple same rooms in one booking)
505 $rooms_features_bookings[$rid.'_'.$rbook['idorder']] = 0;
506 } else {
507 // increment index for this room booking
508 $rooms_features_bookings[$rid.'_'.$rbook['idorder']]++;
509 }
510 // seek for the index occurrence of this room in the list of rooms booked
511 $count_pos = -1;
512 $room_pos = null;
513 foreach ($roomindexes as $rk => $rv) {
514 if ((int)$rv == (int)$rid) {
515 $count_pos++;
516 if ($count_pos == $rooms_features_bookings[$rid.'_'.$rbook['idorder']]) {
517 $room_pos = $rk;
518 break;
519 }
520 }
521 }
522 $nowfeatindex = isset($bookindexes[$room_pos]) ? $room_pos : null;
523 if (!is_null($room_pos) && isset($bookindexes[$nowfeatindex]) && isset($rooms_features_map[$rid][$bookindexes[$nowfeatindex]])) {
524 // get this room feature
525 $cellcont .= '<span class="vbo-tableaux-roomindex">' . $rooms_features_map[$rid][$bookindexes[$nowfeatindex]] . '</span> ';
526 }
527 }
528
529 // add invoice/receipt number if available (taken from booking color tag)
530 if (isset($colortags_map[$rbook['idorder']]) && count($colortags_map[$rbook['idorder']])) {
531 if (isset($colortags_map[$rbook['idorder']]['invoice_number'])) {
532 // invoice number
533 $invstyle = isset($colortags_map[$rbook['idorder']]['fontcolor']) ? ' style="color: '.$colortags_map[$rbook['idorder']]['fontcolor'].';"' : '';
534 $cellcont .= ' <a class="vbo-tableaux-invlink"'.$invstyle.' href="'.VBO_SITE_URI.'helpers/invoices/generated/'.$colortags_map[$rbook['idorder']]['invoice_file_name'].'" target="_blank"><i class="'.VikBookingIcons::i('file-text').'"></i> '.$colortags_map[$rbook['idorder']]['invoice_number'].'</a>';
535 } elseif (isset($colortags_map[$rbook['idorder']]['receipt_number'])) {
536 // receipt number
537 $cellcont .= ' <i class="'.VikBookingIcons::i('file-text-o').'" title="'.JText::translate('VBOFISCRECEIPT').' #'.$colortags_map[$rbook['idorder']]['receipt_number'].'"></i>';
538 }
539 }
540 }
541
542 // color tag styles
543 $cont_styles = array();
544 $span_styles = array();
545 if (isset($colortags_map[$rbook['idorder']]) && count($colortags_map[$rbook['idorder']])) {
546 $cont_styles[] = 'background-color: '.$colortags_map[$rbook['idorder']]['color'].';';
547 if (isset($colortags_map[$rbook['idorder']]['fontcolor'])) {
548 $cont_styles[] = 'color: '.$colortags_map[$rbook['idorder']]['fontcolor'].';';
549 $span_styles[] = 'color: '.$colortags_map[$rbook['idorder']]['fontcolor'].';';
550 }
551 }
552
553 // try to guess if this will be the last element of the day (single-unit rooms, check-out day with wider space because of no check-ins on the same day)
554 $last_checkout_class = '';
555 if ($rdata['units'] == 1 && strpos($contclass, 'checkout') !== false && !isset($room_bookings[($k + 1)])) {
556 $last_checkout_class = 'vbo-tableaux-booking-checkout-last ';
557 }
558 ?>
559 <div class="<?php echo $room_extra_class . $last_checkout_class; ?>vbo-tableaux-booking vbo-tableaux-booking-<?php echo $contclass . $shortstaycls . ' vbo-' . $pos; ?>"<?php echo count($cont_styles) ? ' style="'.implode('', $cont_styles).'"' : ''; ?> data-bid="<?php echo $rbook['idorder']; ?>">
560 <span<?php echo count($span_styles) ? ' style="'.implode('', $span_styles).'"' : ''; ?>><?php echo $cellcont; ?></span>
561 </div>
562 <?php
563 // increase the positioning index
564 $indexpos++;
565 }
566 ?>
567 <span class="vbo-roomdaynote-trigger" data-roomday="<?php echo $glob_rdn_keyid; ?>"><?php VikBookingIcons::e($rdaynote_icn, 'vbo-roomdaynote-display'); ?></span>
568 </td>
569 <?php
570 // next loop
571 $nowinfo = getdate(mktime(0, 0, 0, $nowinfo['mon'], ($nowinfo['mday'] + 1), $nowinfo['year']));
572 }
573 ?>
574 </tr>
575 <?php
576 }
577 ?>
578 </tbody>
579 </table>
580 </div>
581 </div>
582
583 </div>
584
585 <?php
586 $opobj = VikBooking::getOperatorInstance();
587 $all_operators = $opobj->getAll();
588 $currentops = $opobj->getOperatorsFromPermissions('tableaux', $all_operators);
589
590 // build JS strings for operators and rooms drop downs
591 $jsoperators = "<select name='oper_id[%s]' class='vbo-perm-opersel-js-%s'><option value=''>-----</option>";
592 foreach ($all_operators as $v) {
593 $jsoperators .= "<option value='".$v['id']."'>".addslashes(trim($v['first_name'].' '.$v['last_name']))."</option>";
594 }
595 $jsoperators .= "</select>";
596 //
597 $jsrooms = "<select name='oper_rooms[%s][]' class='vbo-perm-roomsel-js-%s' multiple='multiple'><option></option>";
598 foreach ($this->allrooms as $rid => $rdata) {
599 $jsrooms .= "<option value='".$rid."'>".addslashes($rdata['name'])."</option>";
600 }
601 $jsrooms .= "</select>";
602 ?>
603
604 <div class="vbo-modal-overlay-block vbo-modal-overlay-block-tableauxperms">
605 <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
606 <div class="vbo-modal-overlay-content vbo-modal-overlay-content-large vbo-modal-overlay-content-tableauxperms">
607 <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-head-dashwidgets">
608 <h3><span><?php echo $vbo_app->createPopover(array('title' => JText::translate('VBOPERMSOPERATORS'), 'content' => JText::translate('VBOPERMSOPERATORSSHELP'))); ?> <?php echo JText::translate('VBOPERMSOPERATORS'); ?></span> <span class="vbo-modal-overlay-close-times" onclick="hideVboDialog();">&times;</span></h3>
609 </div>
610 <div class="vbo-modal-overlay-content-body vbo-modal-overlay-content-body-scroll">
611 <div class="vbo-tableauxperms-info-list">
612 <form action="index.php?option=com_vikbooking&task=operatorperms" method="post" id="vbo-tblx-fperms">
613 <?php
614 $opindex = 1;
615 foreach ($currentops as $op) {
616 ?>
617 <div class="vbo-pmsperm-entry-wrap">
618 <div class="vbo-pmsperm-entry-cont">
619 <div class="vbo-pmsperm-entry-lbl">
620 <?php echo JText::translate('VBOOPERATOR'); ?>
621 </div>
622 <div class="vbo-pmsperm-entry-val">
623 <input type="hidden" name="oper_id[<?php echo $opindex; ?>]" value="<?php echo $op['id']; ?>" />
624 <span><?php echo $op['first_name'].' '.$op['last_name']; ?></span>
625 </div>
626 </div>
627 <div class="vbo-pmsperm-entry-cont">
628 <div class="vbo-pmsperm-entry-lbl">
629 <?php echo JText::translate('VBOPERMTBLXDAYS'); ?>
630 </div>
631 <div class="vbo-pmsperm-entry-val">
632 <input type="number" name="oper_days[<?php echo $opindex; ?>]" value="<?php echo $op['perms']['days']; ?>" min="1" />
633 </div>
634 </div>
635 <div class="vbo-pmsperm-entry-cont">
636 <div class="vbo-pmsperm-entry-lbl">
637 <?php echo JText::translate('VBOPERMTBLXROOMS'); ?>
638 </div>
639 <div class="vbo-pmsperm-entry-val">
640 <select class="vbo-perm-roomsel" name="oper_rooms[<?php echo $opindex; ?>][]" multiple="multiple">
641 <option></option>
642 <?php
643 foreach ($this->allrooms as $rid => $rdata) {
644 ?>
645 <option value="<?php echo $rid; ?>"<?php echo in_array($rid, $op['perms']['rooms']) ? ' selected="selected"' : ''; ?>><?php echo $rdata['name']; ?></option>
646 <?php
647 }
648 ?>
649 </select>
650 </div>
651 </div>
652 <div class="vbo-pmsperm-entry-cont">
653 <div class="vbo-pmsperm-entry-lbl">
654 <?php echo JText::translate('VBOCUSTOMERDETAILS'); ?>
655 </div>
656 <div class="vbo-pmsperm-entry-val">
657 <select name="oper_guestname[<?php echo $opindex; ?>]">
658 <option value="1"<?php echo !empty($op['perms']['guestname']) ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBYES'); ?></option>
659 <option value="0"<?php echo empty($op['perms']['guestname']) ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBNO'); ?></option>
660 </select>
661 </div>
662 </div>
663 <div class="vbo-pmsperm-entry-cont">
664 <div class="vbo-pmsperm-entry-lbl">
665 <?php echo JText::translate('VBPEDITBUSYEXTRACOSTS'); ?>
666 </div>
667 <div class="vbo-pmsperm-entry-val">
668 <select name="oper_roomextras[<?php echo $opindex; ?>]">
669 <option value="1"<?php echo !empty($op['perms']['roomextras']) ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBYES'); ?></option>
670 <option value="0"<?php echo empty($op['perms']['roomextras']) ? ' selected="selected"' : ''; ?>><?php echo JText::translate('VBNO'); ?></option>
671 </select>
672 </div>
673 </div>
674 <div class="vbo-pmsperm-entry-cont">
675 <div class="vbo-pmsperm-entry-rm">
676 <button type="button" class="btn btn-danger" onclick="vboSetRemoveOpPerm(this, <?php echo $op['id']; ?>);">&times;</button>
677 </div>
678 </div>
679 </div>
680 <?php
681 $opindex++;
682 }
683 ?>
684 <input type="hidden" name="permtype" value="tableaux" />
685 <input type="hidden" name="task" value="operatorperms" />
686 <input type="hidden" name="option" value="com_vikbooking" />
687 </form>
688 </div>
689 </div>
690 <div class="vbo-modal-overlay-content-footer">
691 <div class="vbo-modal-overlay-content-footer-left">
692 <button type="button" class="btn btn-secondary" onclick="javascript: vboAddPermission();"><?php VikBookingIcons::e('plus-circle'); ?> <?php echo JText::translate('VBOADDOPERATORPERM'); ?></button>
693 </div>
694 <div class="vbo-modal-overlay-content-footer-right">
695 <button type="button" class="btn btn-success btn-large" onclick="document.getElementById('vbo-tblx-fperms').submit();"><?php echo JText::translate('VBAPPLY'); ?></button>
696 <button type="button" class="btn btn-danger btn-large" onclick="javascript: hideVboDialog();"><?php echo JText::translate('VBANNULLA'); ?></button>
697 </div>
698 </div>
699 </div>
700 </div>
701
702 <div class="vbo-modal-overlay-block vbo-modal-overlay-block-fests">
703 <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
704 <div class="vbo-modal-overlay-content vbo-modal-overlay-content-fests">
705 <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-head-fests">
706 <h3><?php VikBookingIcons::e('star'); ?> <span></span></h3>
707 </div>
708 <div class="vbo-modal-overlay-content-body">
709 <div class="vbo-overlay-fests-list"></div>
710 <div class="vbo-overlay-fests-addnew" data-ymd="">
711 <h4><?php echo JText::translate('VBOADDCUSTOMFESTTODAY'); ?></h4>
712 <div class="vbo-overlay-fests-addnew-elem">
713 <label for="vbo-newfest-name"><?php echo JText::translate('VBPVIEWPLACESONE'); ?></label>
714 <input type="text" id="vbo-newfest-name" value="" />
715 </div>
716 <div class="vbo-overlay-fests-addnew-elem">
717 <label for="vbo-newfest-descr"><?php echo JText::translate('VBPLACEDESCR'); ?></label>
718 <textarea id="vbo-newfest-descr"></textarea>
719 </div>
720 <div class="vbo-overlay-fests-addnew-save">
721 <button type="button" class="btn btn-success" onclick="vboAddFest(this);"><?php echo JText::translate('VBSAVE'); ?></button>
722 </div>
723 </div>
724 </div>
725 </div>
726 </div>
727
728 <div class="vbo-modal-overlay-block vbo-modal-overlay-block-roomdaynotes">
729 <a class="vbo-modal-overlay-close" href="javascript: void(0);"></a>
730 <div class="vbo-modal-overlay-content vbo-modal-overlay-content-roomdaynotes">
731 <div class="vbo-modal-overlay-content-head vbo-modal-overlay-content-head-roomdaynotes">
732 <h3><?php VikBookingIcons::e('exclamation-circle'); ?> <span></span></h3>
733 </div>
734 <div class="vbo-modal-overlay-content-body">
735 <div class="vbo-modal-roomdaynotes-list"></div>
736 <div class="vbo-modal-roomdaynotes-addnew" data-readymd="" data-ymd="" data-roomid="" data-subroomid="">
737 <h4><?php echo JText::translate('VBOADDCUSTOMFESTTODAY'); ?></h4>
738 <div class="vbo-modal-roomdaynotes-addnew-elem">
739 <label for="vbo-newrdnote-name"><?php echo JText::translate('VBPVIEWPLACESONE'); ?></label>
740 <input type="text" id="vbo-newrdnote-name" value="" />
741 </div>
742 <div class="vbo-modal-roomdaynotes-addnew-elem">
743 <label for="vbo-newrdnote-descr"><?php echo JText::translate('VBPLACEDESCR'); ?></label>
744 <textarea id="vbo-newrdnote-descr"></textarea>
745 </div>
746 <div class="vbo-modal-roomdaynotes-addnew-elem">
747 <label for="vbo-newrdnote-cdays"><?php echo JText::translate('VBOCONSECUTIVEDAYS'); ?></label>
748 <input type="number" id="vbo-newrdnote-cdays" min="0" max="365" value="0" onchange="vboRdayNoteCdaysCount();" onkeyup="vboRdayNoteCdaysCount();" />
749 <span class="vbo-newrdnote-dayto">
750 <span class="vbo-newrdnote-dayto-lbl"><?php echo JText::translate('VBOUNTIL'); ?></span>
751 <span class="vbo-newrdnote-dayto-val"></span>
752 </span>
753 </div>
754 <div class="vbo-modal-roomdaynotes-addnew-save">
755 <button type="button" class="btn btn-success" onclick="vboAddRoomDayNote(this);"><?php echo JText::translate('VBSAVE'); ?></button>
756 </div>
757 </div>
758 </div>
759 </div>
760 </div>
761
762 <a class="vbo-basenavuri-details" href="index.php?option=com_vikbooking&task=editorder&goto=tableaux&cid[]=%d" style="display: none;"></a>
763 <a class="vbo-basenavuri-edit" href="index.php?option=com_vikbooking&task=editbusy&goto=tableaux&cid[]=%d" style="display: none;"></a>
764
765 <script type="text/javascript">
766 var vboFests = <?php echo json_encode($this->festivities); ?>;
767 var vboRdayNotes = <?php echo json_encode($this->rdaynotes); ?>;
768 var operatoridsel = "<?php echo $jsoperators; ?>";
769 var operatorroomsel = "<?php echo $jsrooms; ?>";
770 var opindex = <?php echo $opindex; ?>;
771 var vbodialog_on = false;
772 var vbodialogfests_on = false;
773 var vbodialogrdaynotes_on = false;
774
775 function hideVboDialog() {
776 if (vbodialog_on === true) {
777 jQuery(".vbo-modal-overlay-block-tableauxperms").fadeOut(400, function() {
778 jQuery(".vbo-modal-overlay-content-tableauxperms").show();
779 });
780 vbodialog_on = false;
781 }
782 }
783
784 function vboManagePermissions() {
785 jQuery('.vbo-modal-overlay-block-tableauxperms').fadeIn();
786 vbodialog_on = true;
787 }
788
789 function vboAddPermission() {
790 opindex++;
791 var newperm = '';
792 newperm += '<div class="vbo-pmsperm-entry-wrap">';
793 newperm += ' <div class="vbo-pmsperm-entry-cont">';
794 newperm += ' <div class="vbo-pmsperm-entry-lbl"><?php echo addslashes(JText::translate('VBOOPERATOR')); ?></div>';
795 newperm += ' <div class="vbo-pmsperm-entry-val">'+operatoridsel.replace(/%s/g, opindex)+'</div>';
796 newperm += ' </div>';
797 newperm += ' <div class="vbo-pmsperm-entry-cont">';
798 newperm += ' <div class="vbo-pmsperm-entry-lbl"><?php echo addslashes(JText::translate('VBOPERMTBLXDAYS')); ?></div>';
799 newperm += ' <div class="vbo-pmsperm-entry-val"><input type="number" name="oper_days['+opindex+']" value="14" min="1" /></div>';
800 newperm += ' </div>';
801 newperm += ' <div class="vbo-pmsperm-entry-cont">';
802 newperm += ' <div class="vbo-pmsperm-entry-lbl"><?php echo addslashes(JText::translate('VBOPERMTBLXROOMS')); ?></div>';
803 newperm += ' <div class="vbo-pmsperm-entry-val">'+operatorroomsel.replace(/%s/g, opindex)+'</div>';
804 newperm += ' </div>';
805 newperm += ' <div class="vbo-pmsperm-entry-cont">';
806 newperm += ' <div class="vbo-pmsperm-entry-lbl"><?php echo addslashes(JText::translate('VBOCUSTOMERDETAILS')); ?></div>';
807 newperm += ' <div class="vbo-pmsperm-entry-val">';
808 newperm += ' <select name="oper_guestname['+opindex+']">';
809 newperm += ' <option value="1" selected="selected"><?php echo JText::translate('VBYES'); ?></option>';
810 newperm += ' <option value="0"><?php echo JText::translate('VBNO'); ?></option>';
811 newperm += ' </select>';
812 newperm += ' </div>';
813 newperm += ' </div>';
814 newperm += ' <div class="vbo-pmsperm-entry-cont">';
815 newperm += ' <div class="vbo-pmsperm-entry-lbl"><?php echo addslashes(JText::translate('VBPEDITBUSYEXTRACOSTS')); ?></div>';
816 newperm += ' <div class="vbo-pmsperm-entry-val">';
817 newperm += ' <select name="oper_roomextras['+opindex+']">';
818 newperm += ' <option value="1"><?php echo JText::translate('VBYES'); ?></option>';
819 newperm += ' <option value="0"><?php echo JText::translate('VBNO'); ?></option>';
820 newperm += ' </select>';
821 newperm += ' </div>';
822 newperm += ' </div>';
823 newperm += ' <div class="vbo-pmsperm-entry-cont">';
824 newperm += ' <div class="vbo-pmsperm-entry-rm"><button type="button" class="btn btn-danger" onclick="vboSetRemoveOpPerm(this, -1);">&times;</button></div>';
825 newperm += ' </div>';
826 newperm += '</div>';
827 jQuery('#vbo-tblx-fperms').append(newperm);
828 jQuery(".vbo-perm-roomsel-js-"+opindex).select2({placeholder: '<?php echo addslashes(JText::translate('VBCOUPONALLVEHICLES')); ?>', width: "200px", allowClear: true});
829 jQuery(".vbo-perm-opersel-js-"+opindex).select2();
830 }
831
832 function vboSetRemoveOpPerm(that, oper_id) {
833 var elem = jQuery(that);
834 if (!isNaN(oper_id) && oper_id > 0) {
835 jQuery('#vbo-tblx-fperms').append('<input type="hidden" name="oper_rm[]" value="'+oper_id+'" />');
836 }
837 elem.closest('.vbo-pmsperm-entry-wrap').remove();
838 }
839
840 /**
841 * Fests dialog
842 */
843 function hideVboDialogFests() {
844 if (vbodialogfests_on === true) {
845 jQuery(".vbo-modal-overlay-block-fests").fadeOut(400, function () {
846 jQuery(".vbo-modal-overlay-content-fests").show();
847 });
848 vbodialogfests_on = false;
849 }
850 }
851
852 /**
853 * Room-day-notes dialog
854 */
855 function hideVboDialogRdaynotes() {
856 if (vbodialogrdaynotes_on === true) {
857 jQuery(".vbo-modal-overlay-block-roomdaynotes").fadeOut(400, function () {
858 jQuery(".vbo-modal-overlay-content-roomdaynotes").show();
859 });
860 // reset values
861 jQuery('#vbo-newrdnote-name').val('');
862 jQuery('#vbo-newrdnote-descr').val('');
863 jQuery('#vbo-newrdnote-cdays').val('0').trigger('change');
864 // turn flag off
865 vbodialogrdaynotes_on = false;
866 }
867 }
868
869 /* Hover Tooltip */
870 var hovtimer;
871 var hovtip = false;
872 var vboMessages = {
873 loadingTip: "<?php echo addslashes(JText::translate('VIKLOADING')); ?>",
874 numRooms: "<?php echo addslashes(JText::translate('VBEDITORDERROOMSNUM')); ?>",
875 numAdults: "<?php echo addslashes(JText::translate('VBEDITORDERADULTS')); ?>",
876 numNights: "<?php echo addslashes(JText::translate('VBDAYS')); ?>",
877 checkinLbl: "<?php echo addslashes(JText::translate('VBPICKUPAT')); ?>",
878 checkoutLbl: "<?php echo addslashes(JText::translate('VBRELEASEAT')); ?>",
879 numChildren: "<?php echo addslashes(JText::translate('VBEDITORDERCHILDREN')); ?>",
880 totalAmount: "<?php echo addslashes(JText::translate('VBEDITORDERNINE')); ?>",
881 totalPaid: "<?php echo addslashes(JText::translate('VBPEDITBUSYTOTPAID')); ?>",
882 currencySymb: "<?php echo $currencysymb; ?>"
883 };
884
885 function registerHoveringTooltip(that) {
886 if (hovtip) {
887 return false;
888 }
889 if (hovtimer) {
890 clearTimeout(hovtimer);
891 hovtimer = null;
892 }
893 var elem = jQuery(that);
894 var cellheight = elem.outerHeight();
895 hovtimer = setTimeout(function() {
896 hovtip = true;
897 jQuery(
898 "<div class=\"vbo-overview-tipblock\">"+
899 "<div class=\"vbo-overview-tipinner\"><span class=\"vbo-overview-tiploading\">"+vboMessages.loadingTip+"</span></div>"+
900 "<div class=\"vbo-overview-tipexpander\" style=\"display: none;\"><div class=\"vbo-overview-expandtoggle\"><i class=\"<?php echo VikBookingIcons::i('expand'); ?>\"></i></div></div>"+
901 "</div>"
902 ).appendTo(elem);
903 jQuery(".vbo-overview-tipblock").css("bottom", "+="+cellheight);
904 loadTooltipBookings(elem.attr('data-bid'));
905 }, 900);
906 }
907
908 function unregisterHoveringTooltip() {
909 clearTimeout(hovtimer);
910 hovtimer = null;
911 }
912
913 function adjustHoveringTooltip() {
914 setTimeout(function() {
915 var difflim = 35;
916 var otop = jQuery(".vbo-overview-tipblock").offset().top;
917 if (otop < difflim) {
918 jQuery(".vbo-overview-tipblock").css("bottom", "-="+(difflim - otop));
919 } else {
920 // check top position from table
921 var tipheight = jQuery(".vbo-overview-tipblock").outerHeight();
922 var blocktop = jQuery(".vbo-overview-tipblock").parent().offset().top;
923 var tabletop = jQuery(".vbo-tableaux-table").offset().top;
924 if ((blocktop - tabletop) < tipheight) {
925 // tooltip is going under the table, move it down the container
926 jQuery(".vbo-overview-tipblock").css("bottom", "-"+tipheight+'px');
927 }
928 // check left position from second cell
929 var tipwidth = jQuery(".vbo-overview-tipblock").outerWidth();
930 var cellscndleft = jQuery('.vbo-tableaux-table').find('tr td').first().next().offset().left;
931 var blockleft = jQuery('.vbo-overview-tipblock').parent().offset().left;
932 if (tipwidth > (blockleft - cellscndleft)) {
933 // tooltip should start from left: 0 going to the right
934 jQuery(".vbo-overview-tipblock").css("left", "0px");
935 }
936 }
937 }, 100);
938 }
939
940 function hideVboTooltip() {
941 jQuery('.vbo-overview-tipblock').remove();
942 hovtip = false;
943 }
944
945 function loadTooltipBookings(bid) {
946 if (!bid || bid === undefined || !bid.length) {
947 hideVboTooltip();
948 return false;
949 }
950 // ajax request
951 var jqxhr = jQuery.ajax({
952 type: "POST",
953 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=getbookingsinfo'); ?>",
954 data: {
955 tmpl: "component",
956 idorders: bid
957 }
958 }).done(function(res) {
959 try {
960 var obj_res = typeof res === 'string' ? JSON.parse(res) : res;
961 jQuery('.vbo-overview-tiploading').remove();
962 var container = jQuery('.vbo-overview-tipinner');
963 jQuery(obj_res).each(function(k, v) {
964 // get base navigation URIs
965 var base_uri_details = jQuery('.vbo-basenavuri-details').attr('href');
966 var base_uri_edit = jQuery('.vbo-basenavuri-edit').attr('href');
967
968 // build content
969 var bcont = "<div class=\"vbo-overview-tip-bookingcont\">";
970 bcont += "<div class=\"vbo-overview-tip-bookingcont-left\">";
971 bcont += "<div class=\"vbo-overview-tip-bid\"><span class=\"vbo-overview-tip-lbl\">ID <span class=\"vbo-overview-tip-lbl-innerleft\"><a href=\"" + base_uri_edit.replace('%d', v.id) + "\" target=\"_blank\"><i class=\"<?php echo VikBookingIcons::i('edit'); ?>\"></i></a></span></span><span class=\"vbo-overview-tip-cnt\">"+v.id+"</span></div>";
972 bcont += "<div class=\"vbo-overview-tip-bstatus\"><span class=\"vbo-overview-tip-lbl\"><?php echo addslashes(JText::translate('VBPVIEWORDERSEIGHT')); ?></span><span class=\"vbo-overview-tip-cnt\"><div class=\"label "+(v.status == 'confirmed' ? 'label-success' : 'label-warning')+"\">"+v.status_lbl+"</div></span></div>";
973 bcont += "<div class=\"vbo-overview-tip-bdate\"><span class=\"vbo-overview-tip-lbl\"><?php echo addslashes(JText::translate('VBPVIEWORDERSONE')); ?></span><span class=\"vbo-overview-tip-cnt\"><a href=\"" + base_uri_details.replace('%d', v.id) + "\" target=\"_blank\">"+v.ts+"</a></span></div>";
974 bcont += "</div>";
975 bcont += "<div class=\"vbo-overview-tip-bookingcont-right\">";
976 bcont += "<div class=\"vbo-overview-tip-bcustomer\"><span class=\"vbo-overview-tip-lbl\"><?php echo addslashes(JText::translate('VBOCUSTOMER')); ?></span><span class=\"vbo-overview-tip-cnt\">"+v.cinfo+"</span></div>";
977 if (v.roomsnum > 1) {
978 bcont += "<div class=\"vbo-overview-tip-brooms\"><span class=\"vbo-overview-tip-lbl\">"+vboMessages.numRooms+"</span><span class=\"vbo-overview-tip-cnt\">"+v.room_names+"</span></div>";
979 }
980 bcont += "<div class=\"vbo-overview-tip-bguests\"><span class=\"vbo-overview-tip-lbl\">"+vboMessages.numNights+"</span><span class=\"vbo-overview-tip-cnt hasTooltip\" title=\""+vboMessages.checkinLbl+" "+v.checkin+" - "+vboMessages.checkoutLbl+" "+v.checkout+"\">"+v.days+", "+vboMessages.numAdults+": "+v.tot_adults+(v.tot_children > 0 ? ", "+vboMessages.numChildren+": "+v.tot_children : "")+"</span></div>";
981 if (v.hasOwnProperty('rindexes')) {
982 for (var rindexk in v.rindexes) {
983 if (v.rindexes.hasOwnProperty(rindexk)) {
984 bcont += "<div class=\"vbo-overview-tip-brindexes\"><span class=\"vbo-overview-tip-lbl\">"+rindexk+"</span><span class=\"vbo-overview-tip-cnt\">"+v.rindexes[rindexk]+"</span></div>";
985 }
986 }
987 }
988 if (v.hasOwnProperty('channelimg')) {
989 bcont += "<div class=\"vbo-overview-tip-bprovenience\"><span class=\"vbo-overview-tip-lbl\"><?php echo addslashes(JText::translate('VBPVIEWORDERCHANNEL')); ?></span><span class=\"vbo-overview-tip-cnt\">"+v.channelimg+"</span></div>";
990 }
991 bcont += "<div class=\"vbo-overview-tip-bookingcont-total\">";
992 bcont += "<div class=\"vbo-overview-tip-btot\"><span class=\"vbo-overview-tip-lbl\">"+vboMessages.totalAmount+"</span><span class=\"vbo-overview-tip-cnt\">"+vboMessages.currencySymb+" "+v.format_tot+"</span></div>";
993 if (v.totpaid > 0.00) {
994 bcont += "<div class=\"vbo-overview-tip-btot\"><span class=\"vbo-overview-tip-lbl\">"+vboMessages.totalPaid+"</span><span class=\"vbo-overview-tip-cnt\">"+vboMessages.currencySymb+" "+v.format_totpaid+"</span></div>";
995 }
996 var getnotes = v.adminnotes;
997 if (getnotes !== null && getnotes.length) {
998 bcont += "<div class=\"vbo-overview-tip-notes\"><span class=\"vbo-overview-tip-lbl\"><span class=\"vbo-overview-tip-notes-inner\"><i class=\"vboicn-info hasTooltip\" title=\""+getnotes+"\"></i></span></span></div>";
999 }
1000 bcont += "</div>";
1001 bcont += "</div>";
1002 bcont += "</div>";
1003 container.append(bcont);
1004 jQuery('.vbo-overview-tipexpander').show();
1005 });
1006 // adjust the position so that it won't go under other contents
1007 adjustHoveringTooltip()
1008 //
1009 } catch(err) {
1010 // restore
1011 hideVboTooltip();
1012 // display error
1013 console.error('could not parse JSON response', err, res);
1014 alert('Could not parse JSON response');
1015 }
1016 }).fail(function(err) {
1017 // restore
1018 hideVboTooltip();
1019 // display error
1020 console.error(err);
1021 alert(err.responseText);
1022 });
1023 }
1024
1025 function vboSendPrintTableaux() {
1026 jQuery('#adminForm').attr('target', '_blank').append('<input type="hidden" class="vbo-tableaux-rmafterprint" name="tmpl" value="component" /><input type="hidden" class="vbo-tableaux-rmafterprint" name="printtableaux" value="1" />').submit();
1027 setTimeout(function() {
1028 jQuery('#adminForm').attr('target', '_self');
1029 jQuery('.vbo-tableaux-rmafterprint').remove();
1030 }, 500);
1031 }
1032
1033 /**
1034 * Fests
1035 */
1036 function vboRenderFests(day, daytitle) {
1037 // set day title
1038 if (daytitle) {
1039 jQuery('.vbo-modal-overlay-content-fests').find('h3').find('span').text(daytitle);
1040 }
1041 // compose fests information
1042 var fests_html = '';
1043 if (vboFests[day] && vboFests[day]['festinfo'] && vboFests[day]['festinfo'].length) {
1044 for (var i = 0; i < vboFests[day]['festinfo'].length; i++) {
1045 var fest = vboFests[day]['festinfo'][i];
1046 fests_html += '<div class="vbo-overlay-fest-details">';
1047 fests_html += ' <div class="vbo-fest-info">';
1048 fests_html += ' <div class="vbo-fest-name">' + fest['trans_name'] + '</div>';
1049 fests_html += ' <div class="vbo-fest-desc">' + fest['descr'].replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br />' + '$2') + '</div>';
1050 fests_html += ' </div>';
1051 fests_html += ' <div class="vbo-fest-cmds">';
1052 fests_html += ' <button type="button" class="btn btn-danger" onclick="vboRemoveFest(\'' + day + '\', \'' + i + '\', \'' + fest['type'] + '\', this);"><?php VikBookingIcons::e('trash-alt'); ?></button>';
1053 fests_html += ' </div>';
1054 fests_html += '</div>';
1055 }
1056 }
1057 // update ymd key for the selected date, useful for adding new fests
1058 jQuery('.vbo-overlay-fests-addnew').attr('data-ymd', day);
1059 // set content and display modal
1060 jQuery('.vbo-overlay-fests-list').html(fests_html);
1061 jQuery('.vbo-modal-overlay-block-fests').fadeIn();
1062 vbodialogfests_on = true;
1063 }
1064
1065 function vboRemoveFest(day, index, fest_type, that) {
1066 if (!confirm('<?php echo addslashes(JText::translate('VBDELCONFIRM')); ?>')) {
1067 return false;
1068 }
1069 var elem = jQuery(that);
1070 // make the AJAX request to the controller to remove this fest from the DB
1071 var jqxhr = jQuery.ajax({
1072 type: "POST",
1073 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=remove_fest'); ?>",
1074 data: {
1075 tmpl: "component",
1076 dt: day,
1077 ind: index,
1078 type: fest_type
1079 }
1080 }).done(function(res) {
1081 if (res.indexOf('e4j.ok') >= 0) {
1082 // delete fest also from the json-decode array of objects
1083 if (vboFests[day] && vboFests[day]['festinfo']) {
1084 // use splice to remove the desired index from array, or delete would not make the length of the array change
1085 vboFests[day]['festinfo'].splice(index, 1);
1086 // re-build indexes of delete buttons, fundamental for removing the right index at next click
1087 vboRenderFests(day);
1088 if (!vboFests[day]['festinfo'].length) {
1089 // delete also this date object from fests
1090 delete vboFests[day];
1091 // no more fests, remove the class for this date from all cells
1092 jQuery('td.vbo-tableaux-daycell[data-ymd="'+day+'"]').removeClass('vbo-tableaux-festcell');
1093 }
1094 }
1095 elem.closest('.vbo-overlay-fest-details').remove();
1096 } else {
1097 console.log(res);
1098 alert('Invalid response');
1099 }
1100 }).fail(function() {
1101 alert('Request failed');
1102 });
1103 }
1104
1105 function vboAddFest(that) {
1106 var elem = jQuery(that);
1107 var ymd = elem.closest('.vbo-overlay-fests-addnew').attr('data-ymd');
1108 var fest_name = jQuery('#vbo-newfest-name').val();
1109 var fest_descr = jQuery('#vbo-newfest-descr').val();
1110 if (!fest_name.length) {
1111 return false;
1112 }
1113 // make the AJAX request to the controller to add this fest to the DB
1114 var jqxhr = jQuery.ajax({
1115 type: "POST",
1116 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=add_fest'); ?>",
1117 data: {
1118 tmpl: "component",
1119 dt: ymd,
1120 type: "custom",
1121 name: fest_name,
1122 descr: fest_descr
1123 }
1124 }).done(function(res) {
1125 // parse the JSON response that contains the fest object for the passed date
1126 try {
1127 var stored_fest = JSON.parse(res);
1128 if (!vboFests.hasOwnProperty(stored_fest['dt'])) {
1129 // we need to add the proper class to all cells to show that there is a fest
1130 jQuery('td.vbo-tableaux-daycell[data-ymd="'+stored_fest['dt']+'"]').addClass('vbo-tableaux-festcell');
1131 }
1132 vboFests[stored_fest['dt']] = stored_fest;
1133 hideVboDialogFests();
1134 // reset input fields
1135 jQuery('#vbo-newfest-name').val('');
1136 jQuery('#vbo-newfest-descr').val('');
1137 } catch (e) {
1138 console.log(res);
1139 alert('Invalid response');
1140 return false;
1141 }
1142 }).fail(function() {
1143 alert('Request failed');
1144 });
1145 }
1146 //
1147
1148 /**
1149 * Room-day notes
1150 */
1151 var rdaynote_icn_full = '<?php echo VikBookingIcons::i('sticky-note', 'vbo-roomdaynote-display'); ?>';
1152 var rdaynote_icn_empty = '<?php echo VikBookingIcons::i('far fa-sticky-note', 'vbo-roomdaynote-display'); ?>';
1153 var rooms_features_map = JSON.parse('<?php echo isset($rooms_features_map) && count($rooms_features_map) ? json_encode($rooms_features_map) : json_encode(array()); ?>');
1154
1155 function vboRenderRdayNotes(day, idroom, subunit, readymd) {
1156 // compose room-day notes information (subunit always = 0 for room-day level)
1157 var notes_html = '';
1158 var keyids = new Array;
1159 // always push 0 as the room-level day note key
1160 keyids.push(0);
1161 // grab all the other note keys at sub-unit level
1162 if (jQuery('.vbo-tableaux-roombooks[data-dayrid="' + day + idroom + '"]').length) {
1163 var all_nkeys = jQuery('.vbo-tableaux-roombooks[data-dayrid="' + day + idroom + '"]').attr('data-rdnkeys');
1164 if (all_nkeys && all_nkeys.length) {
1165 var nkeys = all_nkeys.split(',');
1166 for (var k in nkeys) {
1167 var int_index = parseInt(nkeys[k]);
1168 if (!nkeys.hasOwnProperty(k) || isNaN(int_index) || int_index < 1) {
1169 continue;
1170 }
1171 // push sub-unit key for lookup
1172 keyids.push(nkeys[k]);
1173 }
1174 }
1175 }
1176 // parse all room keys with notes
1177 for (var z = 0; z < keyids.length; z++) {
1178 // this is the real sub-unit we are parsing
1179 var subunit_index = keyids[z];
1180 var keyid = day + '_' + idroom + '_' + subunit_index;
1181 if (vboRdayNotes.hasOwnProperty(keyid) && vboRdayNotes[keyid]['info'] && vboRdayNotes[keyid]['info'].length) {
1182 for (var i = 0; i < vboRdayNotes[keyid]['info'].length; i++) {
1183 var note_data = vboRdayNotes[keyid]['info'][i];
1184 var subunit_name = '';
1185 if (parseInt(subunit_index) > 0) {
1186 subunit_name = '(' + subunit_index + ') ';
1187 if (rooms_features_map.hasOwnProperty(idroom) && rooms_features_map[idroom].hasOwnProperty(subunit_index)) {
1188 subunit_name = rooms_features_map[idroom][subunit_index] + ' - ';
1189 }
1190 }
1191 notes_html += '<div class="vbo-overlay-fest-details vbo-modal-roomdaynotes-note-details">';
1192 notes_html += ' <div class="vbo-fest-info vbo-modal-roomdaynotes-note-info">';
1193 notes_html += ' <div class="vbo-fest-name vbo-modal-roomdaynotes-note-name">' + subunit_name + note_data['name'] + '</div>';
1194 notes_html += ' <div class="vbo-fest-desc vbo-modal-roomdaynotes-note-desc">' + note_data['descr'].replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br />' + '$2') + '</div>';
1195 notes_html += ' </div>';
1196 notes_html += ' <div class="vbo-fest-cmds vbo-modal-roomdaynotes-note-cmds">';
1197 notes_html += ' <button type="button" class="btn btn-danger" onclick="vboRemoveRdayNote(\'' + i + '\', \'' + day + '\', \'' + idroom + '\', \'' + subunit_index + '\', \'' + note_data['type'] + '\', this);"><?php VikBookingIcons::e('trash-alt'); ?></button>';
1198 notes_html += ' </div>';
1199 notes_html += '</div>';
1200 }
1201 }
1202 }
1203 // update attributes keys for the selected date, useful for adding new notes (always at room-level)
1204 jQuery('.vbo-modal-roomdaynotes-addnew').attr('data-ymd', day).attr('data-roomid', idroom).attr('data-subroomid', '0');
1205 if (readymd !== null) {
1206 jQuery('.vbo-modal-roomdaynotes-addnew').attr('data-readymd', readymd);
1207 jQuery('.vbo-newrdnote-dayto-val').text(readymd);
1208 }
1209 // set content and display modal
1210 jQuery('.vbo-modal-roomdaynotes-list').html(notes_html);
1211 }
1212
1213 function vboAddRoomDayNote(that) {
1214 var mainelem = jQuery(that).closest('.vbo-modal-roomdaynotes-addnew');
1215 var ymd = mainelem.attr('data-ymd');
1216 var roomid = mainelem.attr('data-roomid');
1217 var subroomid = mainelem.attr('data-subroomid');
1218 var note_name = jQuery('#vbo-newrdnote-name').val();
1219 var note_descr = jQuery('#vbo-newrdnote-descr').val();
1220 var note_cdays = jQuery('#vbo-newrdnote-cdays').val();
1221 if (!note_name.length && !note_descr.length) {
1222 alert('Missing required fields');
1223 return false;
1224 }
1225 // make the AJAX request to the controller to add this note to the DB
1226 var jqxhr = jQuery.ajax({
1227 type: "POST",
1228 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=add_roomdaynote'); ?>",
1229 data: {
1230 tmpl: "component",
1231 dt: ymd,
1232 idroom: roomid,
1233 subunit: subroomid,
1234 type: "custom",
1235 name: note_name,
1236 descr: note_descr,
1237 cdays: note_cdays
1238 }
1239 }).done(function(res) {
1240 // parse the JSON response that contains the note object for the passed date
1241 try {
1242 var stored_notes = JSON.parse(res);
1243 var counter = 0;
1244 for (var keyid in stored_notes) {
1245 if (!stored_notes.hasOwnProperty(keyid)) {
1246 continue;
1247 }
1248 var is_date_visible = (jQuery('.vbo-roomdaynote-trigger[data-roomday="' + keyid + '"]').length > 0);
1249 if (!vboRdayNotes.hasOwnProperty(keyid) && is_date_visible) {
1250 // we need to add the proper class to the cell for this note (if it's visible)
1251 jQuery('.vbo-roomdaynote-trigger[data-roomday="' + keyid + '"]').parent('td').removeClass('vbo-roomdaynote-empty').addClass('vbo-roomdaynote-full').find('i').attr('class', rdaynote_icn_full);
1252 }
1253 // update global object with the new notes in any case
1254 vboRdayNotes[keyid] = stored_notes[keyid];
1255 // update readable notes in custom data attribute
1256 if (counter < 1 && is_date_visible && note_name.length) {
1257 // we push just this name
1258 var current_cell_notes = jQuery('.vbo-roomdaynote-trigger[data-roomday="' + keyid + '"]').parent('td').attr('data-notes');
1259 var all_cell_notes = current_cell_notes && current_cell_notes.length ? current_cell_notes.split(', ') : new Array;
1260 all_cell_notes.push(note_name);
1261 jQuery('.vbo-roomdaynote-trigger[data-roomday="' + keyid + '"]').parent('td').attr('data-notes', all_cell_notes.join(', '));
1262 }
1263 // increase counter
1264 counter++;
1265 }
1266 // close modal
1267 hideVboDialogRdaynotes();
1268 // reset input fields
1269 jQuery('#vbo-newrdnote-name').val('');
1270 jQuery('#vbo-newrdnote-descr').val('');
1271 jQuery('#vbo-newrdnote-cdays').val('0').trigger('change');
1272 } catch (e) {
1273 console.log(res);
1274 alert('Invalid response');
1275 return false;
1276 }
1277 }).fail(function() {
1278 alert('Request failed');
1279 });
1280 }
1281
1282 function vboRdayNotesAvailable(day, idroom) {
1283 /**
1284 * We check whether a room has notes at parent or subunit level for the given date.
1285 */
1286 var base_key = day + '_' + idroom + '_';
1287 var notes_available = false;
1288 for (var k in vboRdayNotes) {
1289 if (!vboRdayNotes.hasOwnProperty(k) || k.indexOf(base_key) < 0) {
1290 continue;
1291 }
1292 // notes found for this room, either parent or sub-unit
1293 if (vboRdayNotes[k]['info'] && vboRdayNotes[k]['info'].length) {
1294 notes_available = true;
1295 break;
1296 }
1297 }
1298
1299 return notes_available;
1300 }
1301
1302 function vboRemoveRdayNote(index, day, idroom, subunit, note_type, that) {
1303 if (!confirm('<?php echo addslashes(JText::translate('VBDELCONFIRM')); ?>')) {
1304 return false;
1305 }
1306 var elem = jQuery(that);
1307 // make the AJAX request to the controller to remove this note from the DB
1308 var jqxhr = jQuery.ajax({
1309 type: "POST",
1310 url: "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=remove_roomdaynote'); ?>",
1311 data: {
1312 tmpl: "component",
1313 dt: day,
1314 idroom: idroom,
1315 subunit: subunit,
1316 ind: index,
1317 type: note_type
1318 }
1319 }).done(function(res) {
1320 if (res.indexOf('e4j.ok') >= 0) {
1321 var keyid = day + '_' + idroom + '_' + subunit;
1322 var glob_keyid = day + '_' + idroom + '_0';
1323 // delete note also from the json-decode array of objects
1324 if (vboRdayNotes[keyid] && vboRdayNotes[keyid]['info']) {
1325 // get the original note name
1326 var old_name = vboRdayNotes[keyid]['info'][index]['name'];
1327 // use splice to remove the desired index from array, or delete would not make the length of the array change
1328 vboRdayNotes[keyid]['info'].splice(index, 1);
1329 // re-build indexes of delete buttons, fundamental for removing the right index at next click (reload always at room-level)
1330 vboRenderRdayNotes(day, idroom, '0', null);
1331 if (!vboRdayNotes[keyid]['info'].length && !vboRdayNotesAvailable(day, idroom)) {
1332 // delete also this date object from notes
1333 delete vboRdayNotes[keyid];
1334 // no more notes, update the proper class attribute for this cell (should be visible)
1335 if (jQuery('.vbo-roomdaynote-trigger[data-roomday="' + glob_keyid + '"]').length) {
1336 jQuery('.vbo-roomdaynote-trigger[data-roomday="' + glob_keyid + '"]').parent('td').removeClass('vbo-roomdaynote-full').addClass('vbo-roomdaynote-empty').attr('data-notes', '').find('i').attr('class', rdaynote_icn_empty);
1337 }
1338 } else if (old_name && old_name.length) {
1339 // try to adjust the readable notes in custom data attribute
1340 var current_cell_notes = jQuery('.vbo-roomdaynote-trigger[data-roomday="' + glob_keyid + '"]').parent('td').attr('data-notes');
1341 var all_cell_notes = current_cell_notes && current_cell_notes.length ? current_cell_notes.split(', ') : new Array;
1342 var new_cell_notes = new Array;
1343 for (var i = 0; i < all_cell_notes.length; i++) {
1344 if (all_cell_notes[i].indexOf(old_name) < 0) {
1345 new_cell_notes.push(all_cell_notes[i]);
1346 }
1347 }
1348 jQuery('.vbo-roomdaynote-trigger[data-roomday="' + glob_keyid + '"]').parent('td').attr('data-notes', new_cell_notes.join(', '));
1349 }
1350 }
1351 elem.closest('.vbo-modal-roomdaynotes-note-details').remove();
1352 } else {
1353 console.log(res);
1354 alert('Invalid response');
1355 }
1356 }).fail(function() {
1357 alert('Request failed');
1358 });
1359 }
1360
1361 function vboRdayNoteCdaysCount() {
1362 var cdays = parseInt(jQuery('#vbo-newrdnote-cdays').val());
1363 var defymd = jQuery('.vbo-modal-roomdaynotes-addnew').attr('data-ymd');
1364 var defreadymd = jQuery('.vbo-modal-roomdaynotes-addnew').attr('data-readymd');
1365 defreadymd = !defreadymd || !defreadymd.length ? defymd : defreadymd;
1366 if (isNaN(cdays) || cdays < 1) {
1367 jQuery('.vbo-newrdnote-dayto-val').text(defreadymd);
1368 return;
1369 }
1370 // calculate target (until) date
1371 var targetdate = new Date(defymd);
1372 targetdate.setDate(targetdate.getDate() + cdays);
1373 var target_y = targetdate.getFullYear();
1374 var target_m = targetdate.getMonth() + 1;
1375 target_m = target_m < 10 ? '0' + target_m : target_m;
1376 var target_d = targetdate.getDate();
1377 target_d = target_d < 10 ? '0' + target_d : target_d;
1378 // display target date
1379 var display_target = target_y + '-' + target_m + '-' + target_d;
1380 // check if we can get the "read ymd property"
1381 if (jQuery('.vbo-tableaux-daycell[data-ymd="' + display_target + '"]').length) {
1382 display_target = jQuery('.vbo-tableaux-daycell[data-ymd="' + display_target + '"]').attr('data-readymd');
1383 }
1384 jQuery('.vbo-newrdnote-dayto-val').text(display_target);
1385 }
1386 //
1387
1388 /**
1389 * Tells whether an element can fit entirely in the viewport.
1390 * Example: if a table is too high to fit in the screen.
1391 * If false, it means that scrolling will always be needed.
1392 */
1393 function vboFitsInViewport(selector) {
1394 var elemHeight = jQuery(selector).outerHeight();
1395 var maxHeight = jQuery(window).height();
1396
1397 return elemHeight < maxHeight;
1398 }
1399
1400 // tableaux scrolling
1401 var fittingTableaux = null;
1402 var tableauxStickySet = false;
1403
1404 /**
1405 * Throttle guarantees a constant flow of events at a given time interval,
1406 * but it runs immediately when the event takes place. We rather need a
1407 * debounce technique to group a flurry of events into one single event.
1408 * This is useful for listening to the scrolling event of the table, actually
1409 * the DIV that wraps it with overflow, and setting the sticky headers.
1410 */
1411 function vboDebounceScroll(func, wait, immediate) {
1412 var timeout;
1413 return function() {
1414 var context = this, args = arguments;
1415 var later = function() {
1416 timeout = null;
1417 if (!immediate) func.apply(context, args);
1418 };
1419 var callNow = immediate && !timeout;
1420 clearTimeout(timeout);
1421 timeout = setTimeout(later, wait);
1422 if (callNow) {
1423 func.apply(context, args);
1424 }
1425 }
1426 }
1427 /**
1428 * We do not need a throttle technique, but this method would
1429 * throttle the scroll event rather than debouncing it.
1430 */
1431 function vboThrottleScroll(method, delay) {
1432 var time = Date.now();
1433 return function() {
1434 if ((time + delay - Date.now()) < 0) {
1435 method();
1436 time = Date.now();
1437 }
1438 }
1439 }
1440
1441 /**
1442 * This will fire during the throttle of the scrolling event.
1443 */
1444 function vboHandleScroll() {
1445 if (fittingTableaux === null) {
1446 fittingTableaux = vboFitsInViewport('.vbo-tableaux-table');
1447 }
1448 if (fittingTableaux) {
1449 // no sticky table headers needed, remove the listener as it is not needed
1450 document.getElementById('vbo-tableaux-table-scroller').removeEventListener('scroll', vboDebounceScroll(vboHandleScroll, 1000));
1451 return;
1452 }
1453 // we have scrolled (vertically or horizontally), update the position of the sticky table head
1454 if (tableauxStickySet) {
1455 // destroy sticky table head
1456 jQuery('table.vbo-tableaux-table').stickyTableHeaders('destroy');
1457 }
1458 // re-build sticky head
1459 jQuery('table.vbo-tableaux-table').stickyTableHeaders({cacheHeaderHeight: true, fixedOffset: jQuery('.navbar')});
1460 tableauxStickySet = true;
1461 }
1462
1463 jQuery(document).ready(function() {
1464 // add listener to scroll event on the main table
1465 document.getElementById('vbo-tableaux-table-scroller').addEventListener('scroll', vboDebounceScroll(vboHandleScroll, 1000));
1466
1467 jQuery("#roomsel, .vbo-perm-roomsel").select2({placeholder: '<?php echo addslashes(JText::translate('VBCOUPONALLVEHICLES')); ?>', width: "300px", allowClear: true});
1468
1469 jQuery('#vbo-date-from').datepicker({
1470 showOn: 'focus',
1471 dateFormat: '<?php echo $juidf; ?>',
1472 <?php echo ($this->mindate > 0 ? 'minDate: "'.date(str_replace('%', '', $nowdf), $this->mindate).'", ' : '').($this->maxdate > 0 ? 'maxDate: "'.date(str_replace('%', '', $nowdf), $this->maxdate).'", ' : ''); ?>
1473 onSelect: function( selectedDate ) {
1474 jQuery('#vbo-date-to').datepicker('option', 'minDate', selectedDate);
1475 jQuery('#vbo-month').val('');
1476 }
1477 });
1478
1479 jQuery('#vbo-date-to').datepicker({
1480 showOn: 'focus',
1481 dateFormat: '<?php echo $juidf; ?>',
1482 <?php echo ($this->mindate > 0 ? 'minDate: "'.date(str_replace('%', '', $nowdf), $this->mindate).'", ' : '').($this->maxdate > 0 ? 'maxDate: "'.date(str_replace('%', '', $nowdf), $this->maxdate).'", ' : ''); ?>
1483 onSelect: function( selectedDate ) {
1484 jQuery('#vbo-date-from').datepicker('option', 'maxDate', selectedDate);
1485 jQuery('#vbo-month').val('');
1486 }
1487 });
1488
1489 jQuery('#vbo-date-from-trig, #vbo-date-to-trig').click(function() {
1490 var jdp = jQuery(this).prev('input.hasDatepicker');
1491 if (jdp.length) {
1492 jdp.focus();
1493 }
1494 });
1495
1496 jQuery('.vbo-tableaux-selmonth').click(function() {
1497 var xts = jQuery(this).attr('data-ts');
1498 var xfrom = jQuery(this).attr('data-from');
1499 var xto = jQuery(this).attr('data-to');
1500 jQuery('#vbo-month').val(xts);
1501 jQuery('#vbo-date-from').val(xfrom);
1502 jQuery('#vbo-date-to').val(xto);
1503 jQuery('#adminForm').submit();
1504 });
1505
1506 /* Expand/Collapse tooltip */
1507 jQuery(document.body).on("click", ".vbo-overview-expandtoggle", function() {
1508 jQuery(this).closest('.vbo-overview-tipblock').toggleClass('vbo-overview-tipblock-expanded');
1509 });
1510 /* ----------------------- */
1511
1512 /* Hover Tooltip */
1513 jQuery('.vbo-tableaux-booking-checkin, .vbo-tableaux-booking-checkout, .vbo-tableaux-booking-stay').hover(function() {
1514 registerHoveringTooltip(this);
1515 }, unregisterHoveringTooltip);
1516
1517 jQuery(document).keydown(function(e) {
1518 if (e.keyCode == 27) {
1519 if (hovtip === true) {
1520 hideVboTooltip();
1521 }
1522 if (vbodialog_on === true) {
1523 hideVboDialog();
1524 }
1525 if (vbodialogfests_on === true) {
1526 hideVboDialogFests();
1527 }
1528 if (vbodialogrdaynotes_on === true) {
1529 hideVboDialogRdaynotes();
1530 }
1531 }
1532 });
1533
1534 jQuery(document).mouseup(function(e) {
1535 if (!hovtip && !vbodialogfests_on && !vbodialogrdaynotes_on) {
1536 return false;
1537 }
1538 if (hovtip) {
1539 var vbo_overlay_cont = jQuery(".vbo-overview-tipblock");
1540 if (!vbo_overlay_cont.is(e.target) && vbo_overlay_cont.has(e.target).length === 0) {
1541 hideVboTooltip();
1542 return true;
1543 }
1544 }
1545 if (vbodialogfests_on) {
1546 var vbo_overlay_cont = jQuery(".vbo-modal-overlay-content-fests");
1547 if (!vbo_overlay_cont.is(e.target) && vbo_overlay_cont.has(e.target).length === 0) {
1548 hideVboDialogFests();
1549 }
1550 }
1551 if (vbodialogrdaynotes_on) {
1552 var vbo_overlay_cont = jQuery(".vbo-modal-overlay-content-roomdaynotes");
1553 if (!vbo_overlay_cont.is(e.target) && vbo_overlay_cont.has(e.target).length === 0) {
1554 hideVboDialogRdaynotes();
1555 }
1556 }
1557 });
1558
1559 // fests
1560 jQuery(document.body).on("click", "td.vbo-tableaux-daycell", function() {
1561 if (jQuery(this).hasClass('skip-tableaux-daycell-click')) {
1562 return;
1563 }
1564 var ymd = jQuery(this).attr('data-ymd');
1565 var daytitle = jQuery(this).attr('data-readymd');
1566 if (jQuery(this).hasClass('vbo-tableaux-festcell')) {
1567 // cell has fests
1568 if (!vboFests.hasOwnProperty(ymd)) {
1569 return;
1570 }
1571 vboRenderFests(ymd, daytitle);
1572 } else {
1573 // let the admin create a new fest
1574 // set day title
1575 jQuery('.vbo-modal-overlay-content-fests').find('h3').find('span').text(daytitle);
1576 // update ymd key for the selected date, useful for adding new fests
1577 jQuery('.vbo-overlay-fests-addnew').attr('data-ymd', ymd);
1578 // unset content and display modal for just adding a new fest
1579 jQuery('.vbo-overlay-fests-list').html('');
1580 jQuery('.vbo-modal-overlay-block-fests').fadeIn();
1581 vbodialogfests_on = true;
1582 }
1583 });
1584 //
1585
1586 // room-day notes
1587 jQuery(document.body).on("click", ".vbo-roomdaynote-display", function() {
1588 if (!jQuery(this).closest('.vbo-roomdaynote-trigger').length) {
1589 return;
1590 }
1591 var daytitle = new Array;
1592 var roomday_info = jQuery(this).closest('.vbo-roomdaynote-trigger').attr('data-roomday').split('_');
1593 // readable day
1594 var readymd = roomday_info[0];
1595 if (jQuery('.vbo-tableaux-daycell[data-ymd="' + roomday_info[0] + '"]').length) {
1596 readymd = jQuery('.vbo-tableaux-daycell[data-ymd="' + roomday_info[0] + '"]').attr('data-readymd');
1597 }
1598 daytitle.push(readymd);
1599 // room name
1600 if (jQuery('.vbo-tableaux-roomname[data-roomid="' + roomday_info[1] + '"]').length) {
1601 daytitle.push(jQuery('.vbo-tableaux-roomname[data-roomid="' + roomday_info[1] + '"]').text());
1602 }
1603 // set day title
1604 jQuery('.vbo-modal-overlay-content-head-roomdaynotes').find('h3').find('span').text(daytitle.join(', '));
1605 // populate current room day notes
1606 vboRenderRdayNotes(roomday_info[0], roomday_info[1], roomday_info[2], readymd);
1607 // display modal
1608 jQuery('.vbo-modal-overlay-block-roomdaynotes').fadeIn();
1609 vbodialogrdaynotes_on = true;
1610 //
1611 });
1612 //
1613
1614 // use sticky headers only if the table is longer than the max viewport height
1615 fittingTableaux = vboFitsInViewport('.vbo-tableaux-table');
1616 if (!fittingTableaux) {
1617 // display table head
1618 jQuery('.vbo-tableaux-table-head').show();
1619 // set sticky head for the vertical scrolling
1620 jQuery('table.vbo-tableaux-table').stickyTableHeaders({cacheHeaderHeight: true, fixedOffset: jQuery('.navbar')});
1621 tableauxStickySet = true;
1622 } else {
1623 // hide table head
1624 jQuery('.vbo-tableaux-table-head').hide();
1625 }
1626
1627 <?php
1628 if ($printtableaux > 0) {
1629 ?>
1630 window.print();
1631 <?php
1632 }
1633 ?>
1634 });
1635 </script>
1636