<?php 
/*
 * Copyright (c) 2025, Tribal Limited
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Zenario, Tribal Limited nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL TRIBAL LTD BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

//Allow a plugin to show on a page on its own.


require 'basicheader.inc.php';
ze\cookie::startSession();


$type = false;
$path = false;
$methodCall = $_REQUEST['method_call'] ?? false;
if ($methodCall == 'handleOrganizerPanelAJAX') {
	ze::$tuixType = $type = 'organizer';
	ze::$tuixPath = $path = $_REQUEST['__path__'] ?? false;
}

$isForPlugin = ze::request('cID') && ze::request('cType') && ze::request('instanceId');

//Check which method call is being requested
//Some method calls are associated with instances and content items, and some are not
if ($methodCall == 'refreshPlugin'
 || $methodCall == 'showFloatingBox'
 || $methodCall == 'handlePluginAJAX'
 || $methodCall == 'pluginAJAX'
 || $methodCall == 'showRSS'
 || $isForPlugin && (
		$methodCall == 'showFile'
	 || $methodCall == 'showImage'
	 || $methodCall == 'showStandalonePage'
	 || $methodCall == 'exportVisitorTUIX'
	 || $methodCall == 'fillVisitorTUIX'
	 || $methodCall == 'formatVisitorTUIX'
	 || $methodCall == 'validateVisitorTUIX'
	 || $methodCall == 'saveVisitorTUIX'
	 || $methodCall == 'typeaheadSearchAJAX')
) {

	//showRSS and showFloatingBox method calls relate to content items
	require CMS_ROOT. 'zenario/visitorheader.inc.php';
	
	//Check the content item that this is being linked from, and whether the current user has permissions to access it
	$cID = $cType = $content = $chain = $version = $redirectNeeded = $aliasInURL = $langIdInURL = $instanceFound = false;
	ze\content::resolveFromRequest($cID, $cType, $redirectNeeded, $aliasInURL, $langIdInURL, $_GET, $_REQUEST, $_POST);
	
	if (!$cVersion = $_REQUEST['cVersion'] ?? false) {
		$cVersion = ze\content::appropriateVersion($cID, $cType);
	}
	
	
	$isAdmin = ze::isAdmin();
	
	//If dev tools are enabled, turn on the recording of PHP and YAML files used by TUIX, so
	//the debug tools that show this information can work.
	if ($isAdmin && ze\admin::setting('show_dev_tools')) {
		\ze::$recordFiles = true;
	}
	
	
	$status = ze\content::getShowableContent($content, $chain, $version, $cID, $cType, ze::request('cVersion'), $checkRequestVars = true);
	if (!$status || is_string($status)) {
		exit;
	}
	
	ze\content::setShowableContent($content, $chain, $version, true);
	
	
	//If this is a call to an RSS feed, and the slotname was not specified, try to see if this Content Item has a slot registered
	if ($methodCall == 'showRSS'
	 && empty($_REQUEST['slotName'])
	 && empty($_REQUEST['instanceId'])
	 && ze::$rss
	 && ($rss = explode('_', ze::$rss, 2))
	 && (!empty($rss[1]))) {
		$_REQUEST['slotName'] = $_GET['slotName'] = $rss[1];
		$_REQUEST['eggId'] = $_GET['eggId'] = $rss[0];
	}
	

	[$slotName, $instanceId, $slideId, $slideNum, $state, $eggId, $overrideSettings, $overrideFrameworkAndCSS] =
		ze\plugin::getSlotVarsFromRequest();
	
	
	if ($instanceId || $slotName) {
		
		ze\plugin::runSlotContents(
			ze::$slotContents,
			ze::$cID, ze::$cType, ze::$cVersion,
			ze::$layoutId, $singleSlot = true, $slotName,
			$instanceId, $slideId, $slideNum, $state, $eggId,
			$overrideSettings, $overrideFrameworkAndCSS, $isAjaxReload = true
		);
		
		foreach (ze::$slotContents as $s => &$slot) {
			$slotNameNestId = $s;
			$moduleClassName = $slot->moduleClassName();
			$instanceId = $slot->instanceId();
			$instanceFound = true;
			break;
		}
		unset($slot);
	}
	
	if (!$instanceFound) {
		if (!($continueIfNoAccess = $methodCall == 'refreshPlugin' && $isAdmin) || !$slotName) {
			exit;
		
		} else {
			ze\plugin::setupNewBaseClass($slotName);
			$instanceId = 0;
			$slotNameNestId = $slotName;
		}
	
	} else
	if (empty(ze::$slotContents[$slotNameNestId]->class())
	 || (empty(ze::$slotContents[$slotNameNestId]->initStatus())
	  && !($continueIfNoAccess = $methodCall == 'refreshPlugin' && $isAdmin))) {
	  	
	  	if ($isAdmin) {
			echo 'You do not have access to this plugin in this mode, or the plugin settings are incomplete.';
		}
		exit;
	}
	

} elseif ($methodCall == 'handleAJAX'
		|| $methodCall == 'handleOrganizerPanelAJAX'
		|| $methodCall == 'handleAdminToolbarAJAX'
		|| $methodCall == 'showFile'
		|| $methodCall == 'showImage'
		|| $methodCall == 'exportVisitorTUIX'
		|| $methodCall == 'fillVisitorTUIX'
		|| $methodCall == 'formatVisitorTUIX'
		|| $methodCall == 'validateVisitorTUIX'
		|| $methodCall == 'saveVisitorTUIX'
		|| $methodCall == 'typeaheadSearchAJAX'
		|| $methodCall == 'showStandalonePage') {
	
	//Allow handleAJAX, showFile, showImage and showStandalonePage to be for visitors or admins as needed
	if (!empty($_SESSION['admin_logged_in']) || $methodCall == 'handleOrganizerPanelAJAX' || $methodCall == 'handleAdminToolbarAJAX') {
		require 'adminheader.inc.php';
	} else {
		require 'visitorheader.inc.php';
	}
	
	if (ze::request('__pluginClassName__')) {
		if (!($module = ze\module::activate($moduleClassName = $_REQUEST['__pluginClassName__'] ?? false))) {
			exit;
		}
	} elseif (ze::request('moduleClassName')) {
		if (!($module = ze\module::activate($moduleClassName = $_REQUEST['moduleClassName'] ?? false))) {
			exit;
		}
	} elseif (ze::request('__pluginName__')) {
		if (!($module = ze\module::activate($moduleClassName = $_REQUEST['__pluginName__'] ?? false))) {
			exit;
		}
	} else {
		if (!($module = ze\module::activate($moduleClassName = $_REQUEST['moduleName'] ?? false))) {
			exit;
		}
	}
	
	//Look variables such as userId, locationId, etc., in the request
	require ze::editionInclude('checkRequestVars');
	

} elseif (ze::get('method_call') == 'loadPhrase') {
	
	//Look up one or more visitor phrases
	require 'visitorheader.inc.php';
	
	$codes = [];
	if (isset($_GET['__code__'])) {
		$codes = ze\ray::explodeDecodeAndTrim($_GET['__code__']);
	}
	$languageId = ze::get('langId') ?: (($_SESSION['user_lang'] ?? false) ?: ze::$defaultLang);
	
	$sql = "
		SELECT code, local_text
		FROM ". DB_PREFIX. "visitor_phrases
		WHERE language_id = '". ze\escape::asciiInSQL($languageId). "'
		  AND module_class_name = '". ze\escape::asciiInSQL(ze::get('__class__')). "'";
	
	if (!empty($codes)) {
		$sql .= "
		  AND code IN (". ze\escape::in($codes). ")";
	}
	
	$phrases = [];
	$result = ze\sql::select($sql);
	while ($row = ze\sql::fetchAssoc($result)) {
		$isCode = substr($row['code'], 0, 1) == '_';
		$needsTranslating = $isCode || !empty(ze::$langs[$languageId]['translate_phrases']);
		
		if ($needsTranslating) {
			$phrases[$row['code']] = $row['local_text'];
		} else {
			$phrases[$row['code']] = $row['code'];
		}
	}
	
	//If this is a logged in administrator, log any missing phrases
	if (!empty($codes) && ze::isAdmin()) {
		foreach ($codes as $code) {
			if (!isset($phrases[$code])) {
				$phrases[$code] = ze\lang::phrase($code, [], ze::get('__class__'), $languageId, ze\admin::phrase('JavaScript code'));
			}
		}
	}
	
	header('Content-Type: text/javascript; charset=UTF-8');
	ze\ray::jsonDump($phrases);
	exit;
	

} elseif ($methodCall == 'getNewId') {
	//Get at the id of the most recently created/uploaded item to Organizer
	if (isset($_SESSION['sk_new_ids']) && is_array($_SESSION['sk_new_ids'])) {
		echo json_encode($_SESSION['sk_new_ids']);
		unset($_SESSION['sk_new_ids']);
	} else {
		echo json_encode([]);
	}
	exit;
	

} elseif ($methodCall == 'getNewEditorTempFiles') {
	//Get at the details of the most recently created/uploaded image to Organizer
	require 'visitorheader.inc.php';
	$files = [];
	if (isset($_SESSION['sk_new_ids']) && is_array($_SESSION['sk_new_ids'])) {
		foreach ($_SESSION['sk_new_ids'] as $id => $dummy) {
			if ($file = ze\row::get('files', ['id', 'checksum', 'filename', 'width', 'height'], ['id' => $id, 'usage' => 'image'])) {
				$files[$id] = $file;
			}
		}
		unset($_SESSION['sk_new_ids']);
	}
	echo json_encode($files);
	exit;
	

} elseif ($methodCall == 'handleAdminBoxAJAX') {
	
	require 'visitorheader.inc.php';
	
	if (empty($_SESSION['allow_file_uploads_in_the_installer']) && !ze::isAdmin()) {
		exit;
	}
	
	ze\fileAdm::handleAdminBoxAJAX();
	

//Handle any other Admin Mode methods
} else {
	
	//Check to see if the CMS' library of functions has been included, and include it if not
	if (!function_exists('checkPriv')) {
		require 'adminheader.inc.php';
	}
	
	//Otherwise look for a Module Name
	if (ze::request('moduleClassName')) {
		if (!($module = ze\module::activate(ze::request('moduleClassName')))) {
			exit;
		}
	} elseif (ze::request('__pluginName__')) {
		if (!($module = ze\module::activate(ze::request('__pluginName__')))) {
			exit;
		}
	} else {
		if (!($module = ze\module::activate(ze::request('moduleName')))) {
			exit;
		}
	}
}



//Check which method call is being requested and then launch that method

//Output a file
if ($methodCall == 'showFile') {
	
	if ($isForPlugin) {
		$module = ze::$slotContents[$slotNameNestId]->class();
	}
	$module->showFile();
	

} elseif ($methodCall == 'exportVisitorTUIX'
	   || $methodCall == 'fillVisitorTUIX'
	   || $methodCall == 'formatVisitorTUIX'
	   || $methodCall == 'validateVisitorTUIX'
	   || $methodCall == 'saveVisitorTUIX'
	   || $methodCall == 'typeaheadSearchAJAX') {
	
	$requestedPath = $_REQUEST['path'] ?? false;

	ze::$tuixType = 'visitor';
	ze::$tuixPath = $requestedPath;
	
	if ($isForPlugin) {
		$module = ze::$slotContents[$slotNameNestId]->class();
	}
	
	$module = $module->runSubClass(get_class($module)) ?: $module;
	
	
	//Exit if no path is specified
	if (!$requestedPath) {
		echo 'No path specified!';
		exit;

	//Check to see if this path is allowed.
	} elseif (
		!$module->returnVisitorTUIXEnabled($requestedPath)
	 || (!$isForPlugin && !$module->returnVisitorTUIXEnabledForPopouts($requestedPath))
	) {
	  	
	  	if ($isAdmin) {
			echo 'You do not have access to this plugin in this mode, or the plugin settings are incomplete.';
		}
		exit;
	}
	
	
	header('Content-Type: text/javascript; charset=UTF-8');
	$tags = [];
	
	if ($methodCall == 'typeaheadSearchAJAX') {
		$module->typeaheadSearchAJAX($requestedPath, $_REQUEST['_tab'] ?? '', $_REQUEST['_field'] ?? '', $_REQUEST['_search'] ?? '', $tags);
		
	} else {
	
		//Small hack for phrases:
		//Try to note down the first YAML file that was used, and use this to report the path that the phrase was found in
		//(Note that this may be wrong if more than one YAML file is used, but usually we only use one YAML file for each path)
		if (!empty($moduleFilesLoaded[$moduleClassName]['paths'])) {
			foreach ($moduleFilesLoaded[$moduleClassName]['paths'] as $yamlFilePath) {
				ze\tuix::$yamlFilePath = $yamlFilePath;
				break;
			}
		}
	
	
		$exporting = $methodCall == 'exportVisitorTUIX';
		$filling = $methodCall == 'fillVisitorTUIX' || $exporting || empty($_POST['_tuix']);
		$saving = !$filling && $methodCall == 'saveVisitorTUIX';
		$validating = !$filling && ($saving || $methodCall == 'validateVisitorTUIX');
	
		$debugMode = $isAdmin && ze::get('_debug');
	
		ze\tuix::visitorTUIX($module, $requestedPath, $tags, $filling, $validating, $saving, $debugMode, $exporting);
	}
	
	if (!empty(ze::$dumps)) {
		$tags['__dumps'] = ze::$dumps;
		ze::$dumps = [];
	}
	
	ze\ray::jsonDump($tags);
	
	
//Show an image
} elseif ($methodCall == 'showImage') {
	
	if ($isForPlugin) {
		$module = ze::$slotContents[$slotNameNestId]->class();
	}
	$module->showImage();
	

//Show a RSS feed
} elseif ($methodCall == 'showRSS') {
	
	header('Content-Type: application/xml; charset=UTF-8');
	ze::$slotContents[$slotNameNestId]->class()->showRSS();


//Show a standalone page
} elseif ($methodCall == 'showStandalonePage') {
	
	if ($isForPlugin) {
		$module = ze::$slotContents[$slotNameNestId]->class();
	}
	$module->showStandalonePage();
	

//Show a thickbox
} elseif ($methodCall == 'showFloatingBox') {
	
	ze::$slotContents[$slotNameNestId]->class()->show(false, 'showFloatingBox');
	

//Handle an AJAX ze::request (Plugin)
} elseif ($methodCall == 'handlePluginAJAX' || $methodCall == 'pluginAJAX') {
	
	//Handle the old name if it's not been changed yet
	if (method_exists(ze::$slotContents[$slotNameNestId]->class(), 'pluginAJAX')) {
		ze::$slotContents[$slotNameNestId]->class()->pluginAJAX();
	}
	
	ze::$slotContents[$slotNameNestId]->class()->handlePluginAJAX();


//Handle an AJAX ze::request (Module)
} elseif ($methodCall == 'handleAJAX') {
	
	$module->handleAJAX();


//Handle a file download from Organizer
} elseif ($methodCall == 'handleOrganizerPanelAJAX' && !empty($_POST['_download'])) {
	
	//Handle the old name if it's not been changed yet
	if (method_exists($module, 'storekeeperDownload')) {
		$module->storekeeperDownload($_REQUEST['__path__'] ?? false, ze::request('id'), ze::request('refinerName'), ze::request('refinerId'));
	}
	
	$module->organizerPanelDownload($_REQUEST['__path__'] ?? false, ze::request('id'), ze::request('refinerName'), ze::request('refinerId'));
	
	exit;


//Handle an AJAX request from Organizer
} elseif ($methodCall == 'handleOrganizerPanelAJAX' || $methodCall == 'handleAdminToolbarAJAX') {
	
	$newIds = false;
	$message = false;
	
	$newIds = false;
	if ($methodCall == 'handleAdminToolbarAJAX') {
		
		//Handle the old name if it's not been changed yet
		if (method_exists($module, 'adminToolbarAJAX')) {
			$module->adminToolbarAJAX((int) ze::request('cID'), ze::request('cType'), (int) ze::request('cVersion'), ze::request('id'));
		}
		
		$module->handleAdminToolbarAJAX((int) ze::request('cID'), ze::request('cType'), (int) ze::request('cVersion'), ze::request('id'));
	
	} else {
		//Handle the old name if it's not been changed yet
		if (method_exists($module, 'storekeeperAJAX')) {
			$module->storekeeperAJAX($_REQUEST['__path__'] ?? false, ze::request('id'), ze::request('id2'), ze::request('refinerName'), ze::request('refinerId'));
		}
		
		$newIds = $module->handleOrganizerPanelAJAX($_REQUEST['__path__'] ?? false, ze::request('id'), ze::request('id2'), ze::request('refinerName'), ze::request('refinerId'));
	}
	
	if ($newIds && !is_array($newIds)) {
		$newIds = explode(',', $newIds);
	}
	
	if (ze::request('_sk_form_submission')) {
		$message = trim(ob_get_contents());
		ob_end_clean();
		
		//If the admin's browser does not have the Flash Uploader, strip out it's success signal
		if (!empty($_FILES['Filedata']) && $message == '1') {
			$message = '';
		}
		
		//Send the results to Organizer in the parent frame
		echo '
			<html>
				<body>
					<script type="text/javascript">';
		
		
		if ($message) {
			$messageType = 'error';
			
			if		  (substr($message, 0, 24) == '<!--Message_Type:None-->') {
				$message = substr($message, 24);
				$messageType = false;
			} else if (substr($message, 0, 25) == '<!--Message_Type:Error-->') {
				$message = substr($message, 25);
				$messageType = 'error';
			} else if (substr($message, 0, 27) == '<!--Message_Type:Success-->') {
				$message = substr($message, 27);
				$messageType = 'success';
			} else if (substr($message, 0, 27) == '<!--Message_Type:Warning-->') {
				$message = substr($message, 27);
				$messageType = 'warning';
			} else if (substr($message, 0, 28) == '<!--Message_Type:Question-->') {
				$message = substr($message, 28);
				$messageType = 'question';
				
				//Undocumented trick to refresh Organizer!
			} else if (substr($message, 0, 23) == '<!--Reload_Organizer-->' || substr($message, 0, 25) == '<!--Reload_Storekeeper-->') {
					echo '
									self.parent.zenarioO.reloadPage();
								</script>
							</body>
						</html>';
					exit;
			}
		
			echo '
						self.parent.zenarioA.floatingBox(\''. ze\escape::jsOnClick($message). '\', true, \''. $messageType. '\');';
		}
		
		if ($newIds) {
			echo '
						self.parent.zenarioO.deselectAllItems();';
			
			foreach ($newIds as $id) {
				echo '
						self.parent.zenarioO.selectedItems[\'', ze\escape::js($id), '\'] = true;';
			}
			
			echo '
						self.parent.zenarioO.saveSelection();';
		}
		
		echo '
						self.parent.zenarioO.reload();
					</script>
				</body>
			</html>';
	
	} else {
		if ($newIds) {
			if (!is_array($_SESSION['sk_new_ids'] ?? false)) {
				$_SESSION['sk_new_ids'] = [];
			}
			foreach ($newIds as $id) {
				$_SESSION['sk_new_ids'][$id] = true;
			}
		}
		
		if (!empty(ze::$dumps)) {
			ze\escape::flag('DUMPS', json_encode(ze::$dumps), false);
			ze::$dumps = [];
		}
	}


//Refresh a Plugin in a slot
} elseif ($methodCall == 'refreshPlugin') {
	
	$slot = ze::$slotContents[$slotName];
	$module = ze::$slotContents[$slotNameNestId]->class();
	
	//Display an info section at the top of the result, to help the CMS pick up on a few things
	$showInfo = true;
	
	if ($url = $slot->headerRedirectLink()) {
		if (!$isAdmin) {
			$showInfo = false;
		}
		ze\escape::flag('FORCE_PAGE_RELOAD', $url);
	
	} elseif ($slot->pageNeedsReloading()) {
		if (!$isAdmin) {
			$showInfo = false;
		}
		ze\escape::flag('FORCE_PAGE_RELOAD', ze\link::toItem(ze::$cID, ze::$cType, true, '', ze::$alias, true));
	
	}
	
	if ($showInfo) {
		ze\escape::flag('INSTANCE_ID', (int) $slot->instanceId());
		
		if ($isAdmin) {
			ze\escape::flag('ADMIN_ID', ze\admin::id());
		}
		
		if ($userId = (int) ($_SESSION['extranetUserID'] ?? 0)) {
			ze\escape::flag('USER_ID', $userId);
		}
		
		if ($slot->scrollToTop() === true) {
			ze\escape::flag('SCROLL_TO_TOP');
		}
		
		//Lets a Plugin will be placed in a floating box when it reloads
		if ($slot->shownInFloatingBox()) {
			ze\escape::flag('SHOW_IN_FLOATING_BOX');
			if (($params = $slot->floatingBoxParams()) && is_array($params)) {
				ze\escape::flag('FLOATING_BOX_PARAMS', json_encode($params));
			}
		}
		
		//Display the level this Module is at
		$slotLevel = $slot->level();
		ze\escape::flag('LEVEL', $slotLevel);
		
		if ($slideId = (int) $module->zAPIGetTabId()) {
			ze\escape::flag('TAB_ID', $slideId);
		}
		
		$cssClass = $module->wrapperClass();
		
		$layoutPreview = null;
		$slotControls = null;
			
		if ($isAdmin) {
			$slotContents = [$slotName => &$slot];
			$slotControls = ze\pluginAdm::setupSlotControls($slotContents, true);
			
			$moduleId = $slot->moduleId();
			ze\escape::flag('MODULE_ID', $moduleId);
			
			ze\escape::flag('NAMESPACE', $slot->moduleClassName());
			
			ze\escape::flag('WHAT_THIS_IS', $module->returnWhatThisIs());
			
			if (!empty($slot->instanceId())) {
				if (!empty($slot->cID())) {
					ze\escape::flag('WIREFRAME');
				}
				if ($slot->shownInMenuMode()) {
					ze\escape::flag('IS_MENU');
				}
			}
		
			if ($slot->beingEdited()) {
				ze\escape::flag('IN_EDIT_MODE');
			}
		
			if ($slotLevel == 2
			 && ze\priv::check('_PRIV_MANAGE_TEMPLATE_SLOT')
			 && $module->shouldShowLayoutPreview()
			 && $moduleId) {
				
				ob_start();
					$module->showLayoutPreview();
				$layoutPreview = ob_get_clean();
				$cssClass .= ' zenario_slot_with_layout_preview';
			}
			
			//Warn the admin is this content item is public and someone had set a private image to display here
			if (!empty(\ze\content::$piWarnings)) {
	
				$others = count(\ze\content::$piWarnings) - 1;
	
				$mrg = [];
				$mrg['eg1'] = array_shift(\ze\content::$piWarnings);
	
				if ($others) {
					$mrg['eg2'] = array_shift(\ze\content::$piWarnings);
				}
				
				ze\escape::flag('IMAGES_BLOCKED');
				ze\escape::flag('IMAGES_BLOCKED_TITLE',
					ze\admin::nzPhrase("Images blocked",
						"Image blocked",
						"Images blocked",
						$others, $mrg
					)
				);
				ze\escape::flag('IMAGES_BLOCKED_MSG',
					ze\admin::nzPhrase(
						"[[eg1]] is a private image and cannot be shown on a public content item",
						"[[eg1]] and [[eg2]] are private images and cannot be shown on a public content item",
						"[[eg1]] and [[count]] others are private images and cannot be shown on a public content item",
						$others, $mrg
					)
				);
			}
		}
		
		ze\escape::flag('CSS_CLASS', $cssClass);
		
		if (empty($slot->instanceId())
		 || !empty($slot->isSuspended())) {
			
			if (empty($slot->error())) {
				echo ze\admin::phrase('[Empty Slot]');
			} else {
				echo '<em>', htmlspecialchars($slot->error()), '</em>';
			}
		
		} elseif (!$initStatus = $slot->initStatus()) {
			\ze\pluginAdm::showInitialisationError($slot, $initStatus);
		
		} else {
			$module->showSlot();
			
			//Check if the Plugin wants any JavaScript run
			$scriptTypes = [];
			$module->zAPICheckRequestedScripts($scriptTypes);
		
			$i = 0;
			$j = 0;
			foreach ($scriptTypes as $scriptType => &$scripts) {
				foreach ($scripts as &$script) {
					if ($scriptType === 0) {
						ze\escape::flag('SCRIPT_BEFORE'. ++$j, json_encode($script), false);
					} else {
						ze\escape::flag('SCRIPT'. ++$i, json_encode($script), false);
					}
				}
			}
		
			if (!empty(ze::$jsLibs)) {
				$i = 0;
				foreach (ze::$jsLibs as $lib => $stylesheet) {
					ze\escape::flag('JS_LIB'. ++$i, json_encode([$lib, $stylesheet]), false);
				}
			}
		}
		
		if ($layoutPreview !== null) {
			ze\escape::flag('LAYOUT_PREVIEW', $layoutPreview, false);
		}
		if ($slotControls !== null) {
			ze\escape::flag('SLOT_CONTROLS', str_replace('":[]', '":{}', json_encode($slotControls, JSON_INVALID_UTF8_SUBSTITUTE)), false);
		}
		
		ze\escape::flag('PAGE_TITLE', ze::$pageTitle, false);
		
		if (!empty(ze::$dumps)) {
			ze\escape::flag('DUMPS', json_encode(ze::$dumps), false);
			ze::$dumps = [];
		}
	}
}


//Experimental debugging feature.
//Add support for using ze::dump() when pressing AJAX buttons in FEA plugins,
//as well as anything else that opts into it using the "supportsZeDump" flag.
if (!empty(ze::$dumps) && isset($_GET['supportsZeDump'])) {
	ze\escape::flag('DUMPS', json_encode(ze::$dumps), false);
	ze::$dumps = [];
}



//Run post-display actions
if (ze::$canCache) require CMS_ROOT. 'zenario/includes/index.post_display.inc.php';