File "latest_events.php"

Full Path: /home/romayxjt/public_html/wp-content/plugins/vikbooking/admin/helpers/widgets/latest_events.php
File size: 26.15 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * @package     VikBooking
 * @subpackage  com_vikbooking
 * @author      Alessio Gaggii - e4j - Extensionsforjoomla.com
 * @copyright   Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 * @link        https://vikwp.com
 */

defined('ABSPATH') or die('No script kiddies please!');

/**
 * Class handler for admin widget "latest events".
 * 
 * @since 	1.15.0 (J) - 1.5.0 (WP)
 */
class VikBookingAdminWidgetLatestEvents extends VikBookingAdminWidget
{
	/**
	 * The instance counter of this widget. Since we do not load individual parameters
	 * for each widget's instance, we use a static counter to determine its settings.
	 *
	 * @var 	int
	 */
	protected static $instance_counter = -1;

	/**
	 * Default number of events per page.
	 * 
	 * @var 	int
	 */
	protected $events_per_page = 6;

	/**
	 * Default number of loading skeletons (should be less than events per page).
	 * 
	 * @var 	int
	 */
	protected $tot_skeletons = 4;

	/**
	 * Class constructor will define the widget name and identifier.
	 */
	public function __construct()
	{
		// call parent constructor
		parent::__construct();

		$this->widgetName = JText::translate('VBO_W_LATESTEVS_TITLE');
		$this->widgetDescr = JText::translate('VBO_W_LATESTEVS_DESCR');
		$this->widgetId = basename(__FILE__, '.php');

		// define widget and icon and style name
		$this->widgetIcon = '<i class="' . VikBookingIcons::i('history') . '"></i>';
		$this->widgetStyleName = 'blue';

		// load widget's settings
		$this->widgetSettings = $this->loadSettings();
		$this->widgetSettings = !is_array($this->widgetSettings) ? [] : $this->widgetSettings;
	}

	/**
	 * This widget returns the latest history record ID to schedule
	 * periodic watch data in order to be able to trigger notifications.
	 * No CSS/JS assets are needed during preloading.
	 * 
	 * @return 	void|object
	 */
	public function preload()
	{
		// lang vars for JS
		JText::script('VBOBOOKHISTORYLBLTYPE');
		JText::script('VBANYTHING');
		JText::script('VBO_HISTORY_GROUPS');

		// use the history class to get the latest event id
		$history_obj = VikBooking::getBookingHistoryInstance();
		$events = $history_obj->getLatestBookingEvents(0, 1);

		if ($events) {
			$watch_data = new stdClass;
			$watch_data->history_id = $events[0]->id;

			return $watch_data;
		}

		return null;
	}

	/**
	 * Checks for new notifications by using the previous preloaded watch-data.
	 * 
	 * @param 	?VBONotificationWatchdata 	$watch_data 	the preloaded watch-data object.
	 * 
	 * @return 	array 						data object to watch next and notifications array.
	 * 
	 * @see 	preload()
	 * 
	 * @since 	1.15.0 (J) - 1.5.0 (WP)
	 */
	public function getNotifications(?VBONotificationWatchdata $watch_data = null)
	{
		// default empty values
		$watch_next    = null;
		$notifications = null;

		if (!$watch_data) {
			return [$watch_next, $notifications];
		}

		$latest_history_id = (int)$watch_data->get('history_id', 0);
		if (empty($latest_history_id)) {
			return [$watch_next, $notifications];
		}

		// load the latest worthy-of-notification history events
		$history_obj = VikBooking::getBookingHistoryInstance();
		$events = $history_obj->getWorthyEvents($latest_history_id, 10);
		if (!$events) {
			return [$watch_next, $notifications];
		}

		// first off, build the next watch data for this widget
		$watch_next = new stdClass;
		$watch_next->history_id = $events[(count($events) - 1)]->id;

		// filter the newest events by those who have not been dispatched before through Push notifications
		$events = $watch_data->filterPushedReservations($events);

		// compose the notification(s) to dispatch, if any
		if ($events) {
			$notifications = VBONotificationScheduler::getInstance()->buildHistoryDataObjects($events);
		}

		return [$watch_next, $notifications];
	}

	/**
	 * Custom method for this widget only to load the history events.
	 * The method is called by the admin controller through an AJAX request.
	 * The visibility should be public, it should not exit the process, and
	 * any content sent to output will be returned to the AJAX response.
	 * In this case we return an array because this method requires "return":1.
	 * 
	 * It's the actual rendering of the widget which also allows navigation.
	 * 
	 * @return 	mixed 	boolean false in case of error, or associative array.
	 */
	public function loadHistoryEvents()
	{
		$instance = VikRequest::getInt('instance', 0, 'request');
		$offset = VikRequest::getInt('offset', 0, 'request');
		$evtype = VikRequest::getString('evtype', '', 'request');
		$length = VikRequest::getInt('length', $this->events_per_page, 'request');
		$wrapper = VikRequest::getString('wrapper', '', 'request');

		// update widget's settings
		if ($instance >= 0) {
			if (!isset($this->widgetSettings[$instance])) {
				// push a new instance
				$this->widgetSettings[] = $this->getDefaultEventSettings($evtype);
				$instance = count($this->widgetSettings) - 1;
			}
			$this->widgetSettings[$instance]->evtype = $evtype;
			$this->updateSettings(json_encode($this->widgetSettings));
		}

		// use the history class to get the events
		$history_obj = VikBooking::getBookingHistoryInstance();
		$events = $history_obj->getLatestBookingEvents($offset, $length, $min_id = 0, [$evtype]);

		// check if a next page can be available
		$has_next_page = (count($events) >= $length);

		// start output buffering
		ob_start();

		// loop through all history events
		$now = time();
		$today = date('Y-m-d');
		foreach ($events as $history) {
			if ($history->status == 'confirmed') {
				$ord_status = '<span class="label label-success vbo-status-label">' . JText::translate('VBCONFIRMED') . '</span>';
			} elseif ($history->status == 'standby') {
				$ord_status = '<span class="label label-warning vbo-status-label">' . JText::translate('VBSTANDBY') . '</span>';
			} else {
				$ord_status = '<span class="label label-error vbo-status-label">' . JText::translate('VBCANCELLED') . '</span>';
			}
			if (!empty($history->booking_type) && !strcasecmp($history->booking_type, 'overbooking')) {
				$ord_status .= ' <span class="label label-error vbo-status-label vbo-label-small">' . JText::translate('VBO_BTYPE_OVERBOOKING') . '</span>';
			}
			$nominative = strlen($history->nominative) > 1 ? $history->nominative : VikBooking::getFirstCustDataField($history->custdata);
			$ch_logo_obj = VikBooking::getVcmChannelsLogo($history->channel, true);
			$channel_logo = is_object($ch_logo_obj) ? $ch_logo_obj->getSmallLogoURL() : '';
			$nights_lbl = $history->days > 1 ? JText::translate('VBDAYS') : JText::translate('VBDAY');

			$dt_obj = new JDate($history->dt);
			$dt_obj->setTimezone(new DateTimeZone(date_default_timezone_get()));

			// calculate check-in date information
			$checkin_info = getdate($history->checkin);
			if (date('Y-m-d', $history->checkin) == $today) {
				// check-in today
				$checkind_lbl = JText::translate('VBTODAY');
				$checkind_icn = '<i class="' . VikBookingIcons::i('plane-arrival') . '"></i>';
			} elseif ($history->checkin > $now) {
				// check-in in the future
				$checkind_lbl = VikBooking::sayWeekDay($checkin_info['wday'], true) . ', ' . date(str_replace("/", $this->datesep, $this->df), $history->checkin);
				$checkind_icn = '<i class="' . VikBookingIcons::i('sort-up') . '"></i> ';
			} else {
				// check-in in the past
				$checkind_lbl = VikBooking::sayWeekDay($checkin_info['wday'], true) . ', ' . date(str_replace("/", $this->datesep, $this->df), $history->checkin);
				$checkind_icn = '<i class="' . VikBookingIcons::i('sort-down') . '"></i> ';
			}
			?>
			<div class="vbo-widget-history-record" data-recordid="<?php echo $history->id; ?>" onclick="vboWidgetLatestEventsOpenBooking('<?php echo $history->idorder; ?>');">
				<div class="vbo-widget-history-avatar">
				<?php
				if (!empty($channel_logo)) {
					// channel logo has got the highest priority
					?>
					<img class="vbo-widget-history-avatar-profile" src="<?php echo $channel_logo; ?>" />
					<?php
				} elseif (!empty($history->pic)) {
					// customer profile picture
					?>
					<img class="vbo-widget-history-avatar-profile" src="<?php echo strpos($history->pic, 'http') === 0 ? $history->pic : VBO_SITE_URI . 'resources/uploads/' . $history->pic; ?>" />
					<?php
				} else {
					// we use an icon as fallback
					VikBookingIcons::e('hotel', 'vbo-widget-history-avatar-icon');
				}
				?>
				</div>
				<div class="vbo-widget-history-content">
					<div class="vbo-widget-history-content-head">
						<div class="vbo-widget-history-content-info-details">
							<?php echo $ord_status; ?>
							<h4><?php echo $nominative; ?></h4>
						</div>
						<div class="vbo-widget-history-content-info-booking">
							<div class="vbo-widget-history-content-info-dates">
								<span class="vbo-widget-history-booking-id">
									<span class="label label-info"><?php echo $history->idorder; ?></span>
								</span>
								<span class="vbo-widget-history-date"><?php echo $dt_obj->format('D, d M Y H:i', true); ?></span>
							</div>
							<div class="vbo-widget-history-booking-checkin">
								<span><?php echo $checkind_icn . $checkind_lbl; ?></span>
								<span><?php echo ' - ' . $history->days . ' ' . $nights_lbl; ?></span>
							</div>
						</div>
					</div>
					<div class="vbo-widget-history-content-info-msg">
						<span class="vbo-widget-history-content-info-msg-descr"><?php echo $history_obj->validType($history->type, true); ?></span>
					</div>
				</div>
			</div>
			<?php
		}

		// append navigation
		?>
		<div class="vbo-widget-commands vbo-widget-commands-right">
			<div class="vbo-widget-commands-main">
			<?php
			if ($offset > 0) {
				// show backward navigation button
				?>
				<div class="vbo-widget-command-chevron vbo-widget-command-prev">
					<span class="vbo-widget-command-chevron-prev" onclick="vboWidgetLatestEventsNavigate('<?php echo $wrapper; ?>', -1);"><?php VikBookingIcons::e('chevron-left'); ?></span>
				</div>
				<?php
			}
			if ($has_next_page) {
				// show forward navigation button
				?>
				<div class="vbo-widget-command-chevron vbo-widget-command-next">
					<span class="vbo-widget-command-chevron-next" onclick="vboWidgetLatestEventsNavigate('<?php echo $wrapper; ?>', 1);"><?php VikBookingIcons::e('chevron-right'); ?></span>
				</div>
			<?php
			}
			?>
			</div>
		</div>
		<?php

		// get the HTML buffer
		$html_content = ob_get_contents();
		ob_end_clean();

		// return an associative array of values
		return array(
			'html' 		  => $html_content,
			'tot_records' => count($events),
			'next_page'   => (int)$has_next_page,
		);
	}

	public function render(?VBOMultitaskData $data = null)
	{
		// increase widget's instance counter
		static::$instance_counter++;

		// check whether the widget is being rendered via AJAX when adding it through the customizer
		$is_ajax = $this->isAjaxRendering();

		// check whether we are in the multitask panel
		$is_multitask = $this->isMultitaskRendering();

		// check whether the widget requires settings
		$needs_settings = !$is_ajax;
		$data_instance  = !$is_ajax ? static::$instance_counter : '-1';
		if ($is_multitask && $is_ajax) {
			$guess_inst_counter = $this->guessMultitaskHistoryInstance($data);
			if ($guess_inst_counter !== false) {
				// force the loading of the guessed widget instance's settings
				static::$instance_counter = $guess_inst_counter;
				$data_instance = $guess_inst_counter;
				$needs_settings = true;
			}
		}

		// generate a unique ID for the sticky notes wrapper instance
		$wrapper_instance = !$is_ajax ? static::$instance_counter : rand();
		$wrapper_id = 'vbo-widget-latestevents-' . $wrapper_instance;

		// get permissions
		$vbo_auth_bookings = JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking');

		// load the settings for this specific instance of the widget
		$instance_settings = $this->getDefaultEventSettings();
		if ($needs_settings && is_array($this->widgetSettings) && isset($this->widgetSettings[static::$instance_counter])) {
			if (is_object($this->widgetSettings[static::$instance_counter]) && count(get_object_vars($this->widgetSettings[static::$instance_counter]))) {
				$instance_settings = $this->widgetSettings[static::$instance_counter];
			}
		}

		// history object
		$history_obj = VikBooking::getBookingHistoryInstance();

		// get all history types and groups
		$history_types  = $history_obj->getTypesMap();
		$history_groups = $history_obj->getTypeGroups();

		// get the current event-type filter
		$current_evtype = '';
		$current_evname = '';
		if (!empty($instance_settings->evtype)) {
			if (isset($history_types[$instance_settings->evtype])) {
				$current_evtype = $instance_settings->evtype;
				$current_evname = $history_types[$current_evtype];
			} elseif (isset($history_groups[$instance_settings->evtype])) {
				$current_evtype = $instance_settings->evtype;
				$current_evname = JText::translate('VBO_HISTORY_GROUPS') . ' - ' . $history_groups[$current_evtype]['name'];
			}
		}

		?>
		<div id="<?php echo $wrapper_id; ?>" class="vbo-admin-widget-wrapper" data-instance="<?php echo $data_instance; ?>" data-offset="0" data-evtype="<?php echo $current_evtype; ?>" data-length="<?php echo $this->events_per_page; ?>">
			<div class="vbo-admin-widget-head">
				<div class="vbo-admin-widget-head-inline">
					<h4><?php echo $this->widgetIcon; ?> <span><?php echo $this->widgetName; ?></span></h4>
					<div class="vbo-admin-widget-head-commands">

						<div class="vbo-reportwidget-commands">
							<div class="vbo-reportwidget-commands-main">
								<div class="vbo-reportwidget-command-dates">
									<div class="vbo-reportwidget-period-name"><?php echo JText::translate('VBOBOOKHISTORYLBLTYPE'); ?></div>
									<div class="vbo-widget-latestevents-filttype-name"><?php echo !empty($current_evname) ? $current_evname : JText::translate('VBANYTHING'); ?></div>
								</div>
							</div>
							<div class="vbo-reportwidget-command-dots">
								<span class="vbo-widget-command-togglefilters vbo-widget-latestevents-togglefilters" onclick="vboWidgetLatestEventsToggleFilters('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('ellipsis-v'); ?></span>
							</div>
						</div>
						<div class="vbo-reportwidget-filters">
							<div class="vbo-reportwidget-filter">
								<select class="vbo-latestevents-filttype-event">
									<option value=""></option>
									<optgroup label="<?php echo htmlspecialchars(JText::translate('VBO_HISTORY_GROUPS')); ?>">
									<?php
									foreach ($history_groups as $ev_key => $ev_data) {
										?>
										<option value="<?php echo $ev_key; ?>"<?php echo !empty($instance_settings->evtype) && $instance_settings->evtype == $ev_key ? ' selected="selected"' : ''; ?>><?php echo $ev_data['name']; ?></option>
										<?php
									}
									?>
									</optgroup>
									<optgroup label="<?php echo htmlspecialchars(JText::translate('VBOBOOKHISTORYTAB')); ?>">
									<?php
									foreach ($history_types as $ev_key => $ev_name) {
										?>
										<option value="<?php echo $ev_key; ?>"<?php echo !empty($instance_settings->evtype) && $instance_settings->evtype == $ev_key ? ' selected="selected"' : ''; ?>><?php echo $ev_name; ?></option>
										<?php
									}
									?>
									</optgroup>
								</select>
							</div>
							<div class="vbo-reportwidget-filter vbo-reportwidget-filter-confirm">
								<button type="button" class="btn vbo-config-btn" onclick="vboWidgetLatestEventsFilterType('<?php echo $wrapper_id; ?>');"><?php echo JText::translate('VBADMINNOTESUPD'); ?></button>
							</div>
						</div>

					</div>
				</div>
			</div>
			<div class="vbo-widget-latestevents-wrap">
				<div class="vbo-widget-latestevents-inner">
					<div class="vbo-widget-latestevents-list">
					<?php
					for ($i = 0; $i < $this->tot_skeletons; $i++) {
						?>
						<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">
							<div class="vbo-dashboard-guest-activity-avatar">
								<div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>
							</div>
							<div class="vbo-dashboard-guest-activity-content">
								<div class="vbo-dashboard-guest-activity-content-head">
									<div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>
								</div>
								<div class="vbo-dashboard-guest-activity-content-info-msg">
									<div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>
								</div>
							</div>
						</div>
						<?php
					}
					?>
					</div>
				</div>
			</div>
		</div>
		<?php

		if (static::$instance_counter === 0 || $is_ajax) {
			/**
			 * Print the JS code only once for all instances of this widget.
			 * The real rendering is made through AJAX, not when the page loads.
			 */
			?>
		<a class="vbo-widget-latest-events-basenavuri" href="<?php echo VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikbooking&task=editorder&cid[]=%d#bookhistory', $xhtml = false); ?>" style="display: none;"></a>

		<script type="text/javascript">

			/**
			 * Open the booking details page for the clicked event
			 */
			function vboWidgetLatestEventsOpenBooking(id) {
				var has_perms = <?php echo (int)$vbo_auth_bookings; ?>;
				if (!has_perms) {
					return false;
				}
				var open_url = jQuery('.vbo-widget-latest-events-basenavuri').first().attr('href');
				open_url = open_url.replace('%d', id);
				// navigate in a new tab
				window.open(open_url, '_blank');
			}

			/**
			 * Display the loading skeletons.
			 */
			function vboWidgetLatestEventsSkeletons(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}
				widget_instance.find('.vbo-widget-latestevents-list').html('');
				for (var i = 0; i < <?php echo $this->tot_skeletons; ?>; i++) {
					var skeleton = '';
					skeleton += '<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">';
					skeleton += '	<div class="vbo-dashboard-guest-activity-avatar">';
					skeleton += '		<div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>';
					skeleton += '	</div>';
					skeleton += '	<div class="vbo-dashboard-guest-activity-content">';
					skeleton += '		<div class="vbo-dashboard-guest-activity-content-head">';
					skeleton += '			<div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>';
					skeleton += '		</div>';
					skeleton += '		<div class="vbo-dashboard-guest-activity-content-info-msg">';
					skeleton += '			<div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>';
					skeleton += '		</div>';
					skeleton += '	</div>';
					skeleton += '</div>';
					// append skeleton
					jQuery(skeleton).appendTo(widget_instance.find('.vbo-widget-latestevents-list'));
				}
			}

			/**
			 * Toggle widget filters.
			 */
			function vboWidgetLatestEventsToggleFilters(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				widget_instance.find('.vbo-reportwidget-filters').toggle();
			}

			/**
			 * Perform the request to load the history events.
			 */
			function vboWidgetLatestEventsLoad(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// get vars for making the request
				var current_instance = widget_instance.attr('data-instance');
				var current_offset   = parseInt(widget_instance.attr('data-offset'));
				var current_evtype   = widget_instance.attr('data-evtype');
				var length_per_page  = parseInt(widget_instance.attr('data-length'));

				// the widget method to call
				var call_method = 'loadHistoryEvents';

				// make a request to load the history events
				VBOCore.doAjax(
					"<?php echo $this->getExecWidgetAjaxUri(); ?>",
					{
						widget_id: "<?php echo $this->getIdentifier(); ?>",
						call: call_method,
						return: 1,
						instance: current_instance,
						offset: current_offset,
						evtype: current_evtype,
						length: length_per_page,
						wrapper: wrapper,
						tmpl: "component"
					},
					function(response) {
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!obj_res.hasOwnProperty(call_method) || !obj_res[call_method]) {
								console.error('Unexpected JSON response', obj_res);
								return false;
							}

							// replace HTML with new history events
							widget_instance.find('.vbo-widget-latestevents-list').html(obj_res[call_method]['html']);
							
							// check results
							var tot_records = obj_res[call_method]['tot_records'] || 0;
							if (!isNaN(tot_records) && parseInt(tot_records) < 1) {
								// no results can indicate the offset is invalid or too high
								if (!isNaN(current_offset) && parseInt(current_offset) > 0) {
									// reset offset to 0
									widget_instance.attr('data-offset', 0);
									// show loading skeletons
									vboWidgetLatestEventsSkeletons(wrapper);
									// reload the first page
									vboWidgetLatestEventsLoad(wrapper);
								}
							}
						} catch(err) {
							console.error('could not parse JSON response', err, response);
						}
					},
					function(error) {
						// remove the skeleton loading
						widget_instance.find('.vbo-widget-latestevents-list').find('.vbo-dashboard-guest-activity-skeleton').remove();
						console.error(error);
					}
				);
			}

			/**
			 * Navigate between the various pages of the history events.
			 */
			function vboWidgetLatestEventsNavigate(wrapper, direction) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// show loading skeletons
				vboWidgetLatestEventsSkeletons(wrapper);

				// current offset
				var current_offset = parseInt(widget_instance.attr('data-offset'));

				// events per page per type
				var steps = <?php echo $this->events_per_page; ?>;

				// check direction and update offsets for nav
				if (direction > 0) {
					// navigate forward
					widget_instance.attr('data-offset', (current_offset + steps));
				} else {
					// navigate backward
					var new_offset = current_offset - steps;
					new_offset = new_offset >= 0 ? new_offset : 0;
					widget_instance.attr('data-offset', new_offset);
				}

				// launch navigation
				vboWidgetLatestEventsLoad(wrapper);
			}

			/**
			 * Update the events (history) type filter
			 */
			function vboWidgetLatestEventsFilterType(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// get selected event-type filter
				var cur_evname = '';
				var cur_evtype = widget_instance.find('select.vbo-latestevents-filttype-event').val();
				if (!cur_evtype || !cur_evtype.length) {
					cur_evtype = '';
					cur_evname = Joomla.JText._('VBANYTHING');
				} else {
					cur_evname = widget_instance.find('select.vbo-latestevents-filttype-event').find('option:selected').text();
					if (cur_evtype.length === 3) {
						cur_evname = Joomla.JText._('VBO_HISTORY_GROUPS') + ' - ' + cur_evname;
					}
				}

				// hide filters when making a new request
				widget_instance.find('.vbo-reportwidget-filters').hide();

				// update title text with the new event name
				widget_instance.find('.vbo-widget-latestevents-filttype-name').text(cur_evname);

				// update current event-type filter
				widget_instance.attr('data-evtype', cur_evtype);

				// always reset the offset to 0
				widget_instance.attr('data-offset', 0);

				// show loading skeletons
				vboWidgetLatestEventsSkeletons(wrapper);

				// reload data
				vboWidgetLatestEventsLoad(wrapper);
			}
			
		</script>
			<?php
		}
		?>

		<script type="text/javascript">

			jQuery(function() {

				// when document is ready, load history events for this widget's instance
				vboWidgetLatestEventsLoad('<?php echo $wrapper_id; ?>');

				// render select2
				jQuery('#<?php echo $wrapper_id; ?>').find('select.vbo-latestevents-filttype-event').select2({
					placeholder: Joomla.JText._('VBOBOOKHISTORYLBLTYPE'),
					width: '100%',
					allowClear: true,
				});

			});
			
		</script>

		<?php
	}

	/**
	 * Protected method to guess if the widget being rendered via AJAX in the
	 * multitask panel should load specific settings. Should be called when
	 * settings have been loaded, and if AJAX + multitask rendering is detected.
	 * It's assumed that the AJAX rendering of a multitask widget takes place one
	 * second before the AJAX event that updates the multitask map to push the widget.
	 * 
	 * @param 	?VBOMultitaskData 	$data 	the data object injected to the widget.
	 * 
	 * @return 	bool|int 	false on failure, guessed settings index otherwise.
	 * 
	 * @since 	1.16.0 (J) - 1.6.0 (WP)
	 */
	protected function guessMultitaskHistoryInstance(?VBOMultitaskData $data = null)
	{
		if (!is_array($this->widgetSettings) || !count($this->widgetSettings)) {
			// nothing to guess if this widget has got no saved settings
			return false;
		}

		if (!is_object($data)) {
			// multitask data object must be set
			return false;
		}

		// the page must be set in the multitask object
		$vbo_page = $data->getPage();
		if (empty($vbo_page)) {
			// nothing to guess if no current page set
			return false;
		}

		// get the map for the current page
		$page_map = VikBooking::getAdminWidgetsInstance()->getMultitaskingMap($vbo_page, $whole = false);
		if (!is_array($page_map) || !count($page_map)) {
			// the multitask panel of this page has got no widgets saved, return the first index for settings
			return 0;
		}

		// count how many widgets of this type are already on this page
		$guessed_index = 0;
		foreach ($page_map as $widget_type) {
			if ($widget_type == $this->getIdentifier()) {
				$guessed_index++;
			}
		}

		// return the guessed index, which will load the next hypothetical instance
		return $guessed_index;
	}

	/**
	 * Returns the default settings object for reading the latest history events.
	 * 
	 * @param 	string 	$evtype 	optional event type requested.
	 * 
	 * @return 	stdClass 			default object with default setting properties.
	 * 
	 * @since 	1.16.0 (J) - 1.6.0 (WP)
	 */
	protected function getDefaultEventSettings($evtype = null)
	{
		$opts = new stdClass;
		$opts->evtype = '';

		if (!empty($evtype)) {
			$opts->evtype = $evtype;
		} elseif (!$this->isAjaxRendering() && !$this->isMultitaskRendering() && static::$instance_counter > 0) {
			// by default, the 2nd instance of the widget will fetch a group of events
			$opts->evtype = $this->hasChannelManager() ? 'GCM' : 'GBK';
		}

		return $opts;
	}
}