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