2354 lines
		
	
	
	
		
			58 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			2354 lines
		
	
	
	
		
			58 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace gp\tool{
 | |
| 
 | |
| 	defined('is_running') or die('Not an entry point...');
 | |
| 
 | |
| 	global $GP_ARRANGE, $gpOutConf;
 | |
| 
 | |
| 	$GP_ARRANGE	= true;
 | |
| 	$gpOutConf	= [];
 | |
| 
 | |
| 
 | |
| 	//named menus should just be shortcuts to the numbers in custom menu
 | |
| 	//	custom menu format: $top_level,$bottom_level,$expand_level
 | |
| 
 | |
| 	//custom menu: 0,0,0,0
 | |
| 	$gpOutConf['FullMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetFullMenu',
 | |
| 		'link'		=> 'all_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 0,0,1,1
 | |
| 	$gpOutConf['ExpandMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetExpandMenu',
 | |
| 		'link'		=> 'expanding_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 0,0,2,1
 | |
| 	$gpOutConf['ExpandLastMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetExpandLastMenu',
 | |
| 		'link'		=> 'expanding_bottom_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 0,1,0,0
 | |
| 	$gpOutConf['Menu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetMenu',
 | |
| 		'link'		=> 'top_level_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 1,0,0,0
 | |
| 	$gpOutConf['SubMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetSubMenu',
 | |
| 		'link'		=> 'subgroup_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 0,2,0,0
 | |
| 	$gpOutConf['TopTwoMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetTopTwoMenu',
 | |
| 		'link'		=> 'top_two_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: does not translate, this pays no attention to grouping
 | |
| 	$gpOutConf['BottomTwoMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetBottomTwoMenu',
 | |
| 		'link'		=> 'bottom_two_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 1,2,0,0
 | |
| 	$gpOutConf['MiddleSubMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetSecondSubMenu',
 | |
| 		'link'		=> 'second_sub_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu: 2,3,0,0
 | |
| 	$gpOutConf['BottomSubMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'GetThirdSubMenu',
 | |
| 		'link'		=> 'third_sub_links',
 | |
| 	];
 | |
| 
 | |
| 	//custom menu
 | |
| 	$gpOutConf['CustomMenu'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'CustomMenu',
 | |
| 	];
 | |
| 
 | |
| 	//breadcrumb nav
 | |
| 	$gpOutConf['Breadcrumbs'] = [
 | |
| 		'class'		=> '\\gp\\tool\\Output\\Menu',
 | |
| 		'method'	=> 'BreadcrumbNav',
 | |
| 		'link'		=> 'Breadcrumb Links',
 | |
| 	];
 | |
| 	//$gpOutConf['Breadcrumbs']['method']	= ['\\gp\\tool\\Output', 'BreadcrumbNav'];
 | |
| 	//$gpOutConf['Breadcrumbs']['link']		= 'Breadcrumb Links';
 | |
| 
 | |
| 
 | |
| 	$gpOutConf['Extra']['method']			= ['\\gp\\tool\\Output', 'GetExtra'];
 | |
| 
 | |
| 	//$gpOutConf['Text']['method']			= ['\\gp\\tool\\Output','GetText']; //use Area() and GetArea() instead
 | |
| 
 | |
| 	//$gpOutConf['Image']['method']			= ['\\gp\\tool\\Output','GetImage'];
 | |
| 
 | |
| 	/* The following methods should be used with \gp\tool\Output'::Fetch() */
 | |
| 	$gpOutConf['Gadget']['method']			= ['\\gp\\tool\\Output', 'GetGadget'];
 | |
| 
 | |
| 
 | |
| 	class Output{
 | |
| 
 | |
| 		public static $components			= '';
 | |
| 		public static $editlinks			= '';
 | |
| 		public static $template_included	= false;
 | |
| 
 | |
| 		private static $out_started			= false;
 | |
| 		private static $gadget_cache		= [];
 | |
| 
 | |
| 		public static $edit_area_id			= '';
 | |
| 
 | |
| 		private static $catchable			= [];
 | |
| 
 | |
| 		public static $lang_values			= [];
 | |
| 		public static $inline_vars			= [];
 | |
| 		public static $nested_edit			= false;
 | |
| 
 | |
| 		private static $edit_index			= 0;
 | |
| 
 | |
| 		private static $head_css			= '';
 | |
| 		private static $head_content		= '';
 | |
| 		private static $head_js				= '';
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Backwards compat for functions moved to \gp\tool\Output\Menu
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function __callStatic($name, $args){
 | |
| 
 | |
| 			if( method_exists('\\gp\\tool\\Output\\Menu', $name) ){
 | |
| 				$menu = new \gp\tool\Output\Menu();
 | |
| 				return call_user_func_array([$menu, $name], $args);
 | |
| 			}
 | |
| 
 | |
| 			throw new \Exception('Call to undefined method gp\\tool\\Output::' . $name);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/*
 | |
| 		 *
 | |
| 		 * Request Type Functions
 | |
| 		 * functions used in conjuction with $_REQUEST['gpreq']
 | |
| 		 *
 | |
| 		 */
 | |
| 
 | |
| 
 | |
| 		 public static function Prep(){
 | |
| 			global $page;
 | |
| 			if( !isset($page->rewrite_urls) ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			ini_set('arg_separator.output', '&');
 | |
| 			foreach($page->rewrite_urls as $key => $value){
 | |
| 				output_add_rewrite_var($key, $value);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Send only messages and the content buffer to the client
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function Flush(){
 | |
| 			global $page;
 | |
| 			self::StandardHeaders();
 | |
| 			echo GetMessages();
 | |
| 			echo $page->contentBuffer;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function Content(){
 | |
| 			global $page;
 | |
| 			self::StandardHeaders();
 | |
| 			echo GetMessages();
 | |
| 			$page->GetGpxContent();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function StandardHeaders(){
 | |
| 			header('Content-Type: text/html; charset=utf-8');
 | |
| 			Header('Vary: Accept,Accept-Encoding'); // for proxies
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Send only the messages and content as a simple html document
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function BodyAsHTML(){
 | |
| 			global $page;
 | |
| 
 | |
| 			self::$inline_vars['gp_bodyashtml']	= true;
 | |
| 
 | |
| 			self::TemplateSettings();
 | |
| 
 | |
| 			self::StandardHeaders();
 | |
| 
 | |
| 			echo '<!DOCTYPE html>';
 | |
| 			echo '<html lang="' . $page->lang . '"><head><meta charset="UTF-8" />';
 | |
| 			self::getHead();
 | |
| 			echo '</head>';
 | |
| 
 | |
| 			echo '<body class="gpbody">';
 | |
| 			echo GetMessages();
 | |
| 
 | |
| 			$page->GetGpxContent();
 | |
| 
 | |
| 			echo '</body>';
 | |
| 			echo '</html>';
 | |
| 
 | |
| 			self::HeadContent();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function AdminHtml(){
 | |
| 			global $page;
 | |
| 
 | |
| 			//\gp\tool\Output::$inline_vars['gp_bodyashtml']	= true;
 | |
| 
 | |
| 			self::StandardHeaders();
 | |
| 
 | |
| 			echo '<!DOCTYPE html>';
 | |
| 			echo '<html class="admin_body" lang="' . $page->lang . '"><head><meta charset="UTF-8" />';
 | |
| 			self::getHead();
 | |
| 			echo '</head>';
 | |
| 
 | |
| 			echo '<body class="gpbody">';
 | |
| 			echo GetMessages();
 | |
| 
 | |
| 			$page->GetGpxContent();
 | |
| 
 | |
| 			echo '</body>';
 | |
| 			echo '</html>';
 | |
| 
 | |
| 			self::HeadContent();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get default values from customizer if it exists
 | |
| 		 * return empty array otherwise
 | |
| 		 *
 | |
| 		 * Layout installer will pass a customizer file path
 | |
| 		 *
 | |
| 		 * @static
 | |
| 		 * @since 5.2
 | |
| 		 * @param string $used_in
 | |
| 		 * @param string $customizer_file
 | |
| 		 * @return array
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetCustomizerDefaults($used_in='', $customizer_file=''){
 | |
| 			global $page;
 | |
| 
 | |
| 			if( empty($customizer_file) ){
 | |
| 				$layout_dir			= $page->theme_dir . '/' . $page->theme_color;
 | |
| 				$customizer_file	= $layout_dir . '/customizer.php';
 | |
| 			}
 | |
| 
 | |
| 			if( !file_exists($customizer_file) ){
 | |
| 				// msg('customizer file ' . htmlspecialchars($customizer_file) . ' does not exist'); // TODO remove
 | |
| 				return [];
 | |
| 			};
 | |
| 
 | |
| 			$customizer = \gp\tool\Files::Get($customizer_file, 'customizer');
 | |
| 			// debug('$customizer = ' . pre($customizer));
 | |
| 			$defaults		= [];
 | |
| 
 | |
| 			foreach($customizer as $section => $section_data){
 | |
| 
 | |
| 				foreach($section_data['items'] as $item_name => $item_data){
 | |
| 					if( !empty($used_in) &&
 | |
| 						isset($item_data['control']['used_in']) &&
 | |
| 						is_array($item_data['control']['used_in']) &&
 | |
| 						!in_array($used_in, $item_data['control']['used_in'])
 | |
| 					){
 | |
| 						continue;
 | |
| 					}
 | |
| 
 | |
| 					$defaults[$item_name]['value'] = $item_data['default_value'];
 | |
| 					if( !empty($item_data['default_units']) ){
 | |
| 						$defaults[$item_name]['units'] = $item_data['default_units'];
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return $defaults;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get javascript values from the layout
 | |
| 		 * if the layout has no stored js_vals, try to get customizer defaults
 | |
| 		 * otherwise return empty string
 | |
| 		 *
 | |
| 		 * @static
 | |
| 		 * @since 5.2
 | |
| 		 * @return string js expression like 'var layout_config = JSON;'
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetLayoutJsVars(){
 | |
| 			global $page, $gpLayouts;
 | |
| 
 | |
| 			if( $page->gpLayout ){
 | |
| 				$layout_info = $gpLayouts[$page->gpLayout];
 | |
| 				if( isset($layout_info['js_vars']) ){
 | |
| 					return $layout_info['js_vars'];
 | |
| 				}
 | |
| 			}
 | |
| 			
 | |
| 			$js_vars = self::GetCustomizerDefaults('js');
 | |
| 			return "\n" . 'var layout_config = ' . json_encode($js_vars) . ';' . "\n";
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get configuration array from the layout
 | |
| 		 * if the layout has no stored config, try to get customizer defaults
 | |
| 		 * otherwise return empty array
 | |
| 		 *
 | |
| 		 * @static
 | |
| 		 * @since 5.2
 | |
| 		 * @return array layout configuration
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetLayoutConfig(){
 | |
| 			global $page, $gpLayouts;
 | |
| 
 | |
| 			if( $page->gpLayout ){
 | |
| 				$layout_info = $gpLayouts[$page->gpLayout];
 | |
| 				if( isset($layout_info['config']) ){
 | |
| 					return $layout_info['config'];
 | |
| 				}
 | |
| 			}
 | |
| 			
 | |
| 			return self::GetCustomizerDefaults('php');
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Send all content according to the current layout
 | |
| 		 * @static
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function Template(){
 | |
| 			global $page, $gpLayouts, $layout_config;
 | |
| 			global $GP_ARRANGE, $GP_STYLES, $get_all_gadgets_called;
 | |
| 			global $addon_current_id, $GP_MENU_LINKS, $GP_MENU_CLASS;
 | |
| 			global $GP_MENU_CLASSES, $GP_MENU_ELEMENTS;
 | |
| 
 | |
| 			$get_all_gadgets_called		= false;
 | |
| 			self::$template_included	= true;
 | |
| 
 | |
| 			if( isset($page->theme_addon_id) ){
 | |
| 				$addon_current_id = $page->theme_addon_id;
 | |
| 			}
 | |
| 			self::TemplateSettings();
 | |
| 
 | |
| 			self::StandardHeaders();
 | |
| 
 | |
| 			if( !empty($page->preview_layout_config) ){
 | |
| 				// only exists in Layout Editor preview mode
 | |
| 				$layout_config = $page->preview_layout_config;
 | |
| 			}elseif( empty($layout_config) ){
 | |
| 				$layout_config = self::GetLayoutConfig();
 | |
| 			}
 | |
| 			// debug('$layout_config = ' . pre($layout_config));
 | |
| 
 | |
| 			$path = $page->theme_dir . '/template.php';
 | |
| 
 | |
| 			$return = IncludeScript(
 | |
| 				$path,
 | |
| 				'require',
 | |
| 				[
 | |
| 					'page', 'layout_config',
 | |
| 					'GP_ARRANGE',
 | |
| 					'GP_MENU_LINKS', 'GP_MENU_CLASS',
 | |
| 					'GP_MENU_CLASSES', 'GP_MENU_ELEMENTS'
 | |
| 				]
 | |
| 			);
 | |
| 
 | |
| 			//return will be false if there's a fatal error with the template.php file
 | |
| 			if( $return === false ){
 | |
| 				self::BodyAsHtml();
 | |
| 			}
 | |
| 			\gp\tool\Plugins::ClearDataFolder();
 | |
| 
 | |
| 			self::HeadContent();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get the settings for the current theme if settings.php exists
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function TemplateSettings(){
 | |
| 			global $page;
 | |
| 
 | |
| 			$path = $page->theme_dir . '/settings.php';
 | |
| 			IncludeScript($path, 'require_if', ['page', 'GP_GETALLGADGETS']);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add a Header to the response
 | |
| 		 * The header will be discarded if it's an ajax request or similar
 | |
| 		 *
 | |
| 		 * @param string $header
 | |
| 		 * @param bool $replace
 | |
| 		 * @param int $code
 | |
| 		 * @return bool
 | |
| 		 */
 | |
| 		public static function AddHeader($header, $replace=true, $code=null){
 | |
| 			if( !empty($_REQUEST['gpreq']) ){
 | |
| 				return false;
 | |
| 			}
 | |
| 			if( !is_null($code) ){
 | |
| 				\gp\tool::status_header($code, $header);
 | |
| 			}else{
 | |
| 				header($header, $replace);
 | |
| 			}
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/*
 | |
| 		 *
 | |
| 		 * Content Area Functions
 | |
| 		 *
 | |
| 		 */
 | |
| 
 | |
| 		 public static function GetContainerID($name, $arg=false){
 | |
| 			static $indices;
 | |
| 
 | |
| 			$name = str_replace(
 | |
| 				['+', '/', '='],
 | |
| 				['', '', ''],
 | |
| 				base64_encode($name)
 | |
| 			);
 | |
| 			if( !isset($indices[$name]) ){
 | |
| 				$indices[$name] = 0;
 | |
| 			}else{
 | |
| 				$indices[$name]++;
 | |
| 			}
 | |
| 			return $name . '_' . $indices[$name];
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Fetch the output and return as a string
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function Fetch($default, $arg=''){
 | |
| 			ob_start();
 | |
| 			self::Get($default, $arg);
 | |
| 			return ob_get_clean();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function Get($default='', $arg=''){
 | |
| 			global $page, $gpLayouts, $gpOutConf;
 | |
| 
 | |
| 			$outSet = false;
 | |
| 			$outKeys = false;
 | |
| 
 | |
| 			$layout_info =& $gpLayouts[$page->gpLayout];
 | |
| 
 | |
| 			//container id
 | |
| 			$container_id	= $default . ':' . substr($arg, 0, 10);
 | |
| 			$container_id	= self::GetContainerID($container_id);
 | |
| 
 | |
| 			if( isset($layout_info) && isset($layout_info['handlers']) ){
 | |
| 				$handlers =& $layout_info['handlers'];
 | |
| 				if( isset($handlers[$container_id]) ){
 | |
| 					$outKeys	= $handlers[$container_id];
 | |
| 					$outSet		= true;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//default values
 | |
| 			$outKeys =array();
 | |
| 			if( !$outSet && isset($gpOutConf[$default]) ){
 | |
| 				$outKeys[] = trim($default . ':' . $arg, ':');
 | |
| 			}
 | |
| 
 | |
| 			self::ForEachOutput($outKeys, $container_id);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function ForEachOutput($outKeys, $container_id){
 | |
| 
 | |
| 			if( !is_array($outKeys) || (count($outKeys) == 0) ){
 | |
| 				$info				= [];
 | |
| 				$info['gpOutCmd']	= '';
 | |
| 				self::CallOutput($info, $container_id);
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			foreach($outKeys as $gpOutCmd){
 | |
| 				$info = self::GetgpOutInfo($gpOutCmd);
 | |
| 				if( $info === false ){
 | |
| 					trigger_error('gpOutCmd <i>' . $gpOutCmd . '</i> not set');
 | |
| 					continue;
 | |
| 				}
 | |
| 				$info['gpOutCmd'] = $gpOutCmd;
 | |
| 				self::CallOutput($info, $container_id);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/* static */
 | |
| 		public static function GetgpOutInfo($gpOutCmd){
 | |
| 			global $gpOutConf, $config;
 | |
| 
 | |
| 			$key	= $gpOutCmd = trim($gpOutCmd, ':');
 | |
| 			$info	= false;
 | |
| 			$arg	= '';
 | |
| 			$pos	= mb_strpos($key, ':');
 | |
| 
 | |
| 			if( $pos > 0 ){
 | |
| 				$arg = mb_substr($key, $pos + 1);
 | |
| 				$key = mb_substr($key, 0, $pos);
 | |
| 			}
 | |
| 
 | |
| 			if( isset($gpOutConf[$key]) ){
 | |
| 				$info = $gpOutConf[$key];
 | |
| 			}elseif( isset($config['gadgets'][$key]) ){
 | |
| 				$info = $config['gadgets'][$key];
 | |
| 				$info['is_gadget'] = true;
 | |
| 			}else{
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			$info['key']		= $key;
 | |
| 			$info['arg']		= $arg;
 | |
| 			$info['gpOutCmd']	= $gpOutCmd;
 | |
| 
 | |
| 			return $info;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public static function GpOutLabel($info){
 | |
| 			global $langmessage;
 | |
| 
 | |
| 			$info += ['arg' => '']; // suppress warning with older themes TODO: check the cause
 | |
| 			$label = $info['arg'];
 | |
| 			if( empty($label) ){
 | |
| 				$label = $info['gpOutCmd'];
 | |
| 			}
 | |
| 
 | |
| 			if( isset($info['link']) && isset($langmessage[$info['link']]) ){
 | |
| 				$label = $langmessage[$info['link']];
 | |
| 			}
 | |
| 
 | |
| 			return str_replace([' ', '_', ':'], [' ', ' ', ': '], $label);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function CallOutput($info,$container_id){
 | |
| 			global $GP_ARRANGE, $page, $langmessage, $GP_MENU_LINKS;
 | |
| 			global $GP_MENU_CLASS, $GP_MENU_CLASSES, $gp_current_container;
 | |
| 
 | |
| 			$gp_current_container	= $container_id;
 | |
| 			self::$out_started		= true;
 | |
| 			self::$edit_area_id		= '';
 | |
| 
 | |
| 			if( isset($info['disabled']) ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			//gpOutCmd identifies the output function used, there can only be one
 | |
| 			if( !isset($info['gpOutCmd']) ){
 | |
| 				trigger_error('gpOutCmd not set for $info in CallOutput()');
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			//generate a class based on the area $info
 | |
| 			if( isset($info['html']) ){
 | |
| 				$class = $info['key'];
 | |
| 				$class = preg_replace('#\[.*\]#', '', $class);
 | |
| 			}else{
 | |
| 				$class = $info['gpOutCmd'];
 | |
| 			}
 | |
| 
 | |
| 			//add gpMenu class to all menu areas for better styling
 | |
| 			$add_menu_class = '';
 | |
| 			if( isset($info['class']) && $info['class'] == '\gp\tool\Output\Menu' ){
 | |
| 				$add_menu_class = 'gpMenu ';
 | |
| 			}
 | |
| 			$class			= $add_menu_class . 'gpArea_' . str_replace([':', ','], ['_', ''], trim($class, ':'));
 | |
| 			$param			= $container_id . '|' . $info['gpOutCmd'];
 | |
| 			$permission		= self::ShowEditLink('Admin_Theme_Content');
 | |
| 
 | |
| 
 | |
| 			ob_start();
 | |
| 
 | |
| 			//for theme content arrangement
 | |
| 			if( $GP_ARRANGE && $permission && isset($GLOBALS['GP_ARRANGE_CONTENT']) ){
 | |
| 				$empty_container = empty($info['gpOutCmd']); //empty containers can't be removed and don't have labels
 | |
| 				$class .= ' gp_output_area';
 | |
| 
 | |
| 				echo '<div class="gp_inner_links nodisplay"><div>';
 | |
| 				echo \gp\tool::Link(
 | |
| 					'Admin_Theme_Content/Edit/' . $page->gpLayout,
 | |
| 					$param,
 | |
| 					'cmd=DragArea&dragging=' . urlencode($param) . '&to=%s',
 | |
| 					['data-cmd' => 'creq', 'class' => 'dragdroplink nodisplay']
 | |
| 				); //drag-drop link
 | |
| 
 | |
| 				echo '<div class="output_area_label">';
 | |
| 				if( $empty_container ){
 | |
| 					echo $langmessage['Empty Container'];
 | |
| 				}else{
 | |
| 					echo self::GpOutLabel($info);
 | |
| 				}
 | |
| 				echo '</div>';
 | |
| 
 | |
| 				echo '<div class="output_area_link">';
 | |
| 				echo ' ' . \gp\tool::Link(
 | |
| 					'Admin_Theme_Content/Edit/' . $page->gpLayout,
 | |
| 					'<i class="fa fa-plus"></i> ' . $langmessage['insert'],
 | |
| 					'cmd=SelectContent¶m=' . $param,
 | |
| 					['data-cmd' => 'gpabox']
 | |
| 				);
 | |
| 				if( !$empty_container ){
 | |
| 					echo ' ' . \gp\tool::Link(
 | |
| 						'Admin_Theme_Content/Edit/' . $page->gpLayout,
 | |
| 						'<i class="fa fa-times"></i> ' . $langmessage['remove'],
 | |
| 						'cmd=RemoveArea¶m=' . $param,
 | |
| 						['data-cmd' => 'creq']
 | |
| 					);
 | |
| 				}
 | |
| 				echo '</div>';
 | |
| 
 | |
| 				echo '</div></div>';
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 			//editable links only .. other editable_areas are handled by their output functions
 | |
| 			if( $permission ){
 | |
| 				if( isset($info['link']) ){
 | |
| 					$label = $langmessage[$info['link']];
 | |
| 
 | |
| 					$edit_link = self::EditAreaLink(
 | |
| 						$edit_index,
 | |
| 						'Admin_Theme_Content/Edit/' . urlencode($page->gpLayout),
 | |
| 						$langmessage['edit'],
 | |
| 						'cmd=LayoutMenu&handle=' . $param,
 | |
| 						['data-cmd' => 'gpabox', 'title' => $label ]
 | |
| 					);
 | |
| 					echo '<span class="nodisplay" id="ExtraEditLnks' . $edit_index . '">';
 | |
| 					echo $edit_link;
 | |
| 					echo \gp\tool::Link(
 | |
| 						'Admin/Menu',
 | |
| 						$langmessage['file_manager'],
 | |
| 						'',
 | |
| 						['class' => 'nodisplay']
 | |
| 					);
 | |
| 					//call to current also not needed, there will only be 1 entry);
 | |
| 					echo '</span>';
 | |
| 
 | |
| 					self::$edit_area_id = 'ExtraEditArea'.$edit_index;
 | |
| 
 | |
| 				}elseif( isset($info['key']) && ($info['key'] == 'CustomMenu') ){
 | |
| 
 | |
| 					$edit_link = self::EditAreaLink(
 | |
| 						$edit_index,
 | |
| 						'Admin_Theme_Content/Edit/' . urlencode($page->gpLayout),
 | |
| 						$langmessage['edit'],
 | |
| 						'cmd=LayoutMenu&handle=' . $param,
 | |
| 						['data-cmd' => 'gpabox', 'title' => $langmessage['Links']]
 | |
| 					);
 | |
| 
 | |
| 					echo '<span class="nodisplay" id="ExtraEditLnks' . $edit_index . '">';
 | |
| 
 | |
| 					echo $edit_link;
 | |
| 
 | |
| 					echo \gp\tool::Link(
 | |
| 						'Admin/Menu',
 | |
| 						$langmessage['file_manager'],
 | |
| 						'',
 | |
| 						['class' => 'nodisplay']
 | |
| 					);
 | |
| 
 | |
| 					echo '</span>';
 | |
| 
 | |
| 					self::$edit_area_id = 'ExtraEditArea' . $edit_index;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			self::$editlinks .= ob_get_clean();
 | |
| 
 | |
| 			echo '<div class="' . $class . ' GPAREA">';
 | |
| 			self::ExecArea($info);
 | |
| 			echo '</div>';
 | |
| 
 | |
| 			$GP_ARRANGE				= true;
 | |
| 			$gp_current_container	= false;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function ExecArea($info){
 | |
| 			//retreive from gadget cache if set
 | |
| 			if( isset($info['gpOutCmd']) ){
 | |
| 				$gadget = $info['gpOutCmd'];
 | |
| 				if( substr($gadget, 0, 7) == 'Gadget:' ){
 | |
| 					$gadget = substr($gadget, 7);
 | |
| 				}
 | |
| 				if( isset(self::$gadget_cache[$gadget]) ){
 | |
| 					echo self::$gadget_cache[$gadget];
 | |
| 					return;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			$info += ['arg' => ''];
 | |
| 			$args = [$info['arg'], $info];
 | |
| 
 | |
| 			$info = \gp\tool\Plugins::Filter('ExecArea', [$info, $args]);
 | |
| 			if( !$info ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			self::ExecInfo($info, $args);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Execute a set of directives for theme areas, hooks and special pages
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function ExecInfo($info, $args=[]){
 | |
| 			global $addonFolderName, $installed_addon, $page;
 | |
| 
 | |
| 			$args += ['page' => $page];
 | |
| 
 | |
| 			//addonDir is deprecated as of 2.0b3
 | |
| 			$addon = false;
 | |
| 			if( isset($info['addonDir']) ){
 | |
| 				$addon = $info['addonDir'];
 | |
| 			}elseif( isset($info['addon']) ){
 | |
| 				$addon = $info['addon'];
 | |
| 			}
 | |
| 
 | |
| 			if( $addon !== false ){
 | |
| 				if( gp_safe_mode ){
 | |
| 					return $args;
 | |
| 				}
 | |
| 				\gp\tool\Plugins::SetDataFolder($addon);
 | |
| 			}
 | |
| 
 | |
| 			//if addon was just installed
 | |
| 			if( $installed_addon && $installed_addon === $addonFolderName){
 | |
| 				\gp\tool\Plugins::ClearDataFolder();
 | |
| 				return $args;
 | |
| 			}
 | |
| 
 | |
| 			// check for fatal errors
 | |
| 			if( self::FatalNotice('exec', $info) ){
 | |
| 				return $args;
 | |
| 			}
 | |
| 
 | |
| 			try{
 | |
| 				$args = self::_ExecInfo($info, $args);
 | |
| 			}catch(\Throwable $e){
 | |
| 				\showError(E_ERROR,
 | |
| 					'ExecInfo() Fatal Error: ' . $e->getMessage(),
 | |
| 					$e->GetFile(),
 | |
| 					$e->GetLine(),
 | |
| 					[],
 | |
| 					$e->getTrace()
 | |
| 				);
 | |
| 			}
 | |
| 
 | |
| 			if( $addon !== false ){
 | |
| 				\gp\tool\Plugins::ClearDataFolder();
 | |
| 			}
 | |
| 
 | |
| 			self::PopCatchable();
 | |
| 
 | |
| 			return $args;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function _ExecInfo($info, $args=[]){
 | |
| 			global $dataDir, $gp_overwrite_scripts;
 | |
| 
 | |
| 			// get data
 | |
| 			if( !empty($info['data']) ){
 | |
| 				IncludeScript($dataDir . $info['data'], 'include_if', ['page', 'dataDir', 'langmessage']);
 | |
| 			}
 | |
| 
 | |
| 			// get script
 | |
| 			$has_script = false;
 | |
| 			if( !empty($info['script']) ){
 | |
| 
 | |
| 				if( is_array($gp_overwrite_scripts) && isset($gp_overwrite_scripts[$info['script']]) ){
 | |
| 					$full_path = $gp_overwrite_scripts[$info['script']];
 | |
| 				}else{
 | |
| 					$full_path = $dataDir . $info['script'];
 | |
| 				}
 | |
| 
 | |
| 				if( !file_exists($full_path) ){
 | |
| 					self::ExecError(\CMS_NAME . ' Error: Addon hook script doesn\'t exist.', $info, 'script');
 | |
| 					return $args;
 | |
| 				}
 | |
| 
 | |
| 				if( IncludeScript($full_path, 'include_once', ['page', 'dataDir', 'langmessage']) ){
 | |
| 					$has_script = true;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//class & method execution
 | |
| 			if( !empty($info['class_admin']) && \gp\tool::LoggedIn() ){
 | |
| 				return self::ExecClass($has_script, $info['class_admin'], $info, $args);
 | |
| 			}elseif( !empty($info['class']) ){
 | |
| 				return self::ExecClass($has_script, $info['class'], $info, $args);
 | |
| 			}
 | |
| 
 | |
| 			//method execution
 | |
| 			if( !empty($info['method']) ){
 | |
| 				return self::ExecMethod($has_script, $info, $args);
 | |
| 			}
 | |
| 
 | |
| 			return $args;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Execute hooks that have a ['class'] defined
 | |
| 		 *
 | |
| 		 */
 | |
| 		private static function ExecClass($has_script, $exec_class, $info, $args){
 | |
| 
 | |
| 			if( !class_exists($exec_class) ){
 | |
| 				self::ExecError(\CMS_NAME . ' Error: Addon class doesn\'t exist.', $info, 'class');
 | |
| 				return $args;
 | |
| 			}
 | |
| 
 | |
| 			$object = new $exec_class($args);
 | |
| 
 | |
| 			if( !empty($info['method']) ){
 | |
| 				if( method_exists($object, $info['method']) ){
 | |
| 					$args[0] = call_user_func_array([$object, $info['method']], array_values($args));
 | |
| 				}elseif( $has_script ){
 | |
| 					self::ExecError(\CMS_NAME . ' Error: Addon hook method doesn\'t exist (1).', $info, 'method');
 | |
| 				}
 | |
| 			}
 | |
| 			return $args;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Execute hooks that have a ['method'] defined
 | |
| 		 *
 | |
| 		 */
 | |
| 		private static function ExecMethod($has_script, $info, $args){
 | |
| 
 | |
| 			$callback = $info['method'];
 | |
| 
 | |
| 			//object callbacks since 3.0
 | |
| 			if( is_string($callback) && strpos($callback, '->') !== false ){
 | |
| 				$has_script = true;
 | |
| 				list($object, $method) = explode('->', $callback);
 | |
| 				if( isset($GLOBALS[$object]) &&
 | |
| 					is_object($GLOBALS[$object]) &&
 | |
| 					method_exists($GLOBALS[$object], $method)
 | |
| 				){
 | |
| 					$callback = [$GLOBALS[$object], $method];
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if( is_callable($callback) ){
 | |
| 				$args[0] = call_user_func_array($callback, array_values($args));
 | |
| 			}elseif( $has_script ){
 | |
| 				self::ExecError(\CMS_NAME.' Error: Addon hook method doesn\'t exist (2).', $info, 'method');
 | |
| 			}
 | |
| 
 | |
| 			return $args;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Trigger an error
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function ExecError($msg, $exec_info, $error_info){
 | |
| 			global $config, $addonFolderName;
 | |
| 
 | |
| 			// append addon name
 | |
| 			if( !empty($addonFolderName) && isset($config['addons'][$addonFolderName]) ){
 | |
| 				$msg	.= ' Addon: ' . $config['addons'][$addonFolderName]['name'] . '. ';
 | |
| 			}
 | |
| 
 | |
| 			// which piece of $exec_info is the problem
 | |
| 			if( !isset($exec_info[$error_info]) ){
 | |
| 				$msg	.= $error_info;
 | |
| 			}elseif( is_array($exec_info[$error_info]) ){
 | |
| 				$msg	.= $error_info . ': ' . implode('::', $exec_info[$error_info]);
 | |
| 			}else{
 | |
| 				$msg	.= $error_info . ': ' . $exec_info[$error_info];
 | |
| 			}
 | |
| 
 | |
| 			trigger_error($msg);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Check for fatal errors corresponing to $hash
 | |
| 		 * Notify administrators of disabled components
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function FatalNotice($type, $info){
 | |
| 			global $dataDir, $page;
 | |
| 			static $notified = false;
 | |
| 
 | |
| 			$info					= (array)$info;
 | |
| 			$info['catchable_type']	= $type;
 | |
| 
 | |
| 			$hash_dir				= $dataDir . '/data/_site/fatal_' . $type . '_' . \gp\tool::ArrayHash($info);
 | |
| 			$hash_request			= $hash_dir . '/' . \gp\tool::ArrayHash($_REQUEST);
 | |
| 
 | |
| 			self::$catchable[$hash_request]	= $info;
 | |
| 
 | |
| 			if( !self::FatalLimit($hash_dir) ){
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if( !$notified ){
 | |
| 				error_log( 'Warning: A component of this page has been disabled because it caused fatal errors' );
 | |
| 				$notified = true;
 | |
| 			}
 | |
| 
 | |
| 			self::PopCatchable();
 | |
| 
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Return true if the limit of fatal errors has been reached
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function FatalLimit($hash_dir){
 | |
| 
 | |
| 			//no folder = no fatal error
 | |
| 			if( !file_exists($hash_dir) ){
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			// if the error didn't occur for the exact request and it hasn't happend a lot, allow the code to keep working
 | |
| 			$fatal_hashes = scandir($hash_dir);
 | |
| 			if( $fatal_hashes !== false && count($fatal_hashes) < (gp_allowed_fatal_errors + 3) ){
 | |
| 				// add 3 for ".", ".." and "index.html" entries
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function PopCatchable(){
 | |
| 			array_pop(self::$catchable);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Determine if an inline edit link should be shown for the current user
 | |
| 		 *
 | |
| 		 * @param string $permission
 | |
| 		 * @return bool
 | |
| 		 */
 | |
| 		public static function ShowEditLink($permission=null){
 | |
| 
 | |
| 			if( !is_null($permission) ){
 | |
| 				return !self::$nested_edit && \gp\tool::LoggedIn() && \gp\admin\Tools::HasPermission($permission);
 | |
| 			}
 | |
| 			return !self::$nested_edit && \gp\tool::LoggedIn();
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * @param int $index
 | |
| 		 * @param string $href
 | |
| 		 * @param string $label
 | |
| 		 * @param string $query
 | |
| 		 * @param string|array $attr
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function EditAreaLink(&$index, $href, $label, $query='', $attr=''){
 | |
| 			self::$edit_index++;
 | |
| 			$index = self::$edit_index; //since &$index is passed by reference
 | |
| 
 | |
| 			if( is_array($attr) ){
 | |
| 				$attr += [
 | |
| 					'class'				=> 'ExtraEditLink nodisplay',
 | |
| 					'id'				=> 'ExtraEditLink' . $index,
 | |
| 					'data-gp-area-id'	=> $index,
 | |
| 				];
 | |
| 			}else{
 | |
| 				$attr .= ' class="ExtraEditLink nodisplay" ' .
 | |
| 					'id="ExtraEditLink' . $index . '" ' .
 | |
| 					'data-gp-area-id="' . $index . '"';
 | |
| 			}
 | |
| 			return \gp\tool::Link($href, $label, $query, $attr);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Unless the gadget area is customized by the user, this function will output all active gadgets
 | |
| 		 * If the area has been reorganized, it will output the customized areas
 | |
| 		 * This function is not called from \gp\tool\Output::Get('GetAllGadgets')
 | |
| 		 * so that each individual gadget area can be used as a drag area
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetAllGadgets(){
 | |
| 			global $config, $page, $gpLayouts, $get_all_gadgets_called;
 | |
| 			$get_all_gadgets_called = true;
 | |
| 
 | |
| 			//if we have handler info
 | |
| 			if( isset($gpLayouts[$page->gpLayout]['handlers']['GetAllGadgets']) ){
 | |
| 				self::ForEachOutput($gpLayouts[$page->gpLayout]['handlers']['GetAllGadgets'], 'GetAllGadgets');
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			//show all gadgets if no changes have been made
 | |
| 			if( !empty($config['gadgets']) ){
 | |
| 				$count = 0;
 | |
| 				foreach($config['gadgets'] as $gadget => $info){
 | |
| 					if( isset($info['addon']) ){
 | |
| 						$info['gpOutCmd'] = $info['key'] = $gadget;
 | |
| 						self::CallOutput($info, 'GetAllGadgets');
 | |
| 						$count++;
 | |
| 					}
 | |
| 				}
 | |
| 				if( $count ){
 | |
| 					return;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//Show the area as editable if there isn't anything to show
 | |
| 			$info				= [];
 | |
| 			$info['gpOutCmd']	= '';
 | |
| 			self::CallOutput($info, 'GetAllGadgets');
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Simply determine if a Gadget exists
 | |
| 		 * allows us to check whether a plugin gadget exists before loading it in template.php
 | |
| 		 * @since 5.2-rc
 | |
| 		 * @param string Gadget id
 | |
| 		 * @return boolean
 | |
| 		 */
 | |
| 		public static function GadgetExists($id){
 | |
| 			global $config;
 | |
| 			return isset($config['gadgets'][$id]);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get a Single Gadget
 | |
| 		 * This method should be called using \gp\tool\Output::Fetch('Gadget',$gadget_name)
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetGadget($id){
 | |
| 			global $config;
 | |
| 
 | |
| 			if( !isset($config['gadgets'][$id]) ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			self::ExecArea($config['gadgets'][$id]);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Prepare the gadget content before getting template.php
 | |
| 		 * so that gadget functions can add css and js to the head
 | |
| 		 * @return null
 | |
| 		 */
 | |
| 		public static function PrepGadgetContent(){
 | |
| 			global $page;
 | |
| 
 | |
| 			//not needed for admin pages
 | |
| 			if( $page->pagetype == 'admin_display' ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			$gadget_info = self::WhichGadgets($page->gpLayout);
 | |
| 
 | |
| 			foreach($gadget_info as $gpOutCmd => $info){
 | |
| 				if( !isset(self::$gadget_cache[$gpOutCmd]) ){
 | |
| 					ob_start();
 | |
| 					self::ExecArea($info);
 | |
| 					self::$gadget_cache[$gpOutCmd] = ob_get_clean();
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Return information about the gadgets being used in the current layout
 | |
| 		 * @return array
 | |
| 		 */
 | |
| 		public static function WhichGadgets($layout){
 | |
| 			global $config, $gpLayouts;
 | |
| 
 | |
| 			$gadget_info = $temp_info = [];
 | |
| 			if( !isset($config['gadgets']) ){
 | |
| 				return $gadget_info;
 | |
| 			}
 | |
| 
 | |
| 			$layout_info = & $gpLayouts[$layout];
 | |
| 
 | |
| 			$GetAllGadgets = true;
 | |
| 			if( isset($layout_info['all_gadgets']) && !$layout_info['all_gadgets'] ){
 | |
| 				$GetAllGadgets = false;
 | |
| 			}
 | |
| 
 | |
| 			if( isset($layout_info['handlers']) ){
 | |
| 				foreach($layout_info['handlers'] as $handler => $out_cmds){
 | |
| 					//don't prep even if GetAllGadgets is set in the layout's config
 | |
| 					if( $handler == 'GetAllGadgets' && !$GetAllGadgets ){
 | |
| 						continue;
 | |
| 					}
 | |
| 					foreach($out_cmds as $gpOutCmd){
 | |
| 						$temp_info[$gpOutCmd] = self::GetgpOutInfo($gpOutCmd);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//add all gadgets if $GetAllGadgets is true and the GetAllGadgets handler isn't overwritten
 | |
| 			if( $GetAllGadgets && !isset($layout_info['handlers']['GetAllGadgets']) ){
 | |
| 				foreach($config['gadgets'] as $gadget => $temp){
 | |
| 					if( isset($temp['addon']) ){
 | |
| 						$temp_info[$gadget] = self::GetgpOutInfo($gadget);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			foreach($temp_info as $gpOutCmd => $info){
 | |
| 				if( isset($info['is_gadget']) &&
 | |
| 					$info['is_gadget'] &&
 | |
| 					!isset($info['disabled'])
 | |
| 				){
 | |
| 					$gadget_info[$gpOutCmd] = $info;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return $gadget_info;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function GetExtra($name='Side_Menu', $info=[]){
 | |
| 			echo \gp\tool\Output\Extra::GetExtra($name);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function GetImage($src, $attributes=[]){
 | |
| 			global $page, $dataDir, $langmessage, $gpLayouts;
 | |
| 
 | |
| 			//$width,$height,$attributes = ''
 | |
| 			$attributes				= (array)$attributes;
 | |
| 			$attributes				+= ['class' => ''];
 | |
| 			$attributes['class'] 	.= 'GPAREA filetype-image';
 | |
| 			unset($attributes['id']);
 | |
| 
 | |
| 			//default image information
 | |
| 			$img_rel = dirname($page->theme_rel) . '/' . ltrim($src, '/');
 | |
| 
 | |
| 			//container id
 | |
| 			$container_id = 'Image:' . $src;
 | |
| 			$container_id = self::GetContainerID($container_id);
 | |
| 
 | |
| 			//select custom image
 | |
| 			if( isset($gpLayouts[$page->gpLayout]) &&
 | |
| 				isset($gpLayouts[$page->gpLayout]['images']) &&
 | |
| 				isset($gpLayouts[$page->gpLayout]['images'][$container_id]) &&
 | |
| 				is_array($gpLayouts[$page->gpLayout]['images'][$container_id])
 | |
| 			){
 | |
| 				//shuffle($gpLayouts[$page->gpLayout]['images'][$container_id]);
 | |
| 				//Does not make sense ? There will always be only 1 entry in 
 | |
| 				//for this container as it is per img element
 | |
| 				//call to current also not needed, there will only be 1 entry
 | |
| 				$image = $gpLayouts[$page->gpLayout]['images'][$container_id][0];
 | |
| 
 | |
| 				$img_full = $dataDir.$image['img_rel'];
 | |
| 				if( file_exists($img_full) ){
 | |
| 					$img_rel				= $image['img_rel'];
 | |
| 					$attributes['width']	= $image['width'];
 | |
| 					$attributes['height']	= $image['height'];
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//attributes
 | |
| 			if( !isset($attributes['alt']) ){
 | |
| 				$attributes['alt'] = '';
 | |
| 			}
 | |
| 
 | |
| 			//edit options
 | |
| 			$editable = self::ShowEditLink('Admin_Theme_Content');
 | |
| 			if( $editable ){
 | |
| 				$edit_link = self::EditAreaLink(
 | |
| 					$edit_index,
 | |
| 					'Admin_Theme_Content/Image/' . $page->gpLayout,
 | |
| 					$langmessage['edit'],
 | |
| 					'file=' . rawurlencode($img_rel) . '&container=' . $container_id . '&time=' . time(),
 | |
| 					['title' => 'Edit Image', 'data-cmd' => 'inline_edit_generic' ]
 | |
| 				);
 | |
| 				self::$editlinks 		.= '<span class="nodisplay" id="ExtraEditLnks' .
 | |
| 												$edit_index . '">' .
 | |
| 												$edit_link .
 | |
| 											'</span>';
 | |
| 				$attributes['class']	.= ' editable_area';
 | |
| 				$attributes['id']		= 'ExtraEditArea' . $edit_index;
 | |
| 			}
 | |
| 
 | |
| 			//remove class if empty, commented because class will never be empty anymore because of filetype-image
 | |
| 			// $attributes['class'] = trim($attributes['class']);
 | |
| 			// if( empty($attributes['class']) ){
 | |
| 			//	unset($attributes['class']);
 | |
| 			//}
 | |
| 
 | |
| 			//convert attributes to string
 | |
| 			$str = '';
 | |
| 			foreach($attributes as $key => $value){
 | |
| 				$str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8', false) . '"';
 | |
| 			}
 | |
| 			echo '<img src="' . \gp\tool::GetDir($img_rel, true) . '"' . $str . '/>';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/*
 | |
| 		 *
 | |
| 		 * Output Additional Areas
 | |
| 		 *
 | |
| 		 */
 | |
| 
 | |
| 		/* draggable html and editable text */
 | |
| 		public static function Area($name,$html){
 | |
| 			global $gpOutConf;
 | |
| 			if( self::$out_started ){
 | |
| 				trigger_error('\gp\tool\Output::Area() must be called before all other output functions');
 | |
| 				return;
 | |
| 			}
 | |
| 			$name 						= '[text]' . $name;
 | |
| 			$gpOutConf[$name]			= [];
 | |
| 			$gpOutConf[$name]['method']	= ['\\gp\\tool\\Output', 'GetAreaOut'];
 | |
| 			$gpOutConf[$name]['html']	= $html;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function GetArea($name, $text){
 | |
| 			$name = '[text]' . $name;
 | |
| 			self::Get($name, $text);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function GetAreaOut($text,$info){
 | |
| 			global $config, $langmessage, $page;
 | |
| 
 | |
| 			$html =& $info['html'];
 | |
| 
 | |
| 			$wrap = self::ShowEditLink('Admin_Theme_Content');
 | |
| 			if( $wrap ){
 | |
| 				self::$editlinks .= self::EditAreaLink(
 | |
| 					$edit_index,
 | |
| 					'Admin_Theme_Content/Text',
 | |
| 					$langmessage['edit'],
 | |
| 					'cmd=EditText&key=' . urlencode($text) . '&return=' . urlencode($page->title),
 | |
| 					['title' => htmlspecialchars($text), 'data-cmd'	=> 'gpabox']
 | |
| 				);
 | |
| 				echo '<div class="editable_area inner_size" id="ExtraEditArea' . $edit_index . '">';
 | |
| 				// class="edit_area" added by javascript
 | |
| 			}
 | |
| 
 | |
| 			if( isset($config['customlang'][$text]) ){
 | |
| 				$text = $config['customlang'][$text];
 | |
| 
 | |
| 			}elseif( isset($langmessage[$text]) ){
 | |
| 				$text = $langmessage[$text];
 | |
| 			}
 | |
| 
 | |
| 			echo str_replace('%s', $text, $html); //in case there's more than one %s
 | |
| 
 | |
| 			if( $wrap ){
 | |
| 				echo '</div>';
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get additional CSS classes that can be added to the
 | |
| 		 * html or body elements' class atrribute
 | |
| 		 * e.g. to display an larger header only on the homepage
 | |
| 		 * Use in template.php: <html class="<?php gpOutput::GetPageInfoClasses(); ?>">
 | |
| 		 * @since 5.2-rc
 | |
| 		 * @param boolean $echo_classes (defaults to true), output the class names as space-separated string
 | |
| 		 * @return array of css class names that apply
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetPageInfoClasses($echo_classes=true){
 | |
| 			global $page;
 | |
| 
 | |
| 			$classes = [];
 | |
| 		
 | |
| 			if( self::is_front_page() ){
 | |
| 				$classes[] = 'is-homepage';
 | |
| 			}
 | |
| 
 | |
| 			if( $page->pagetype == 'special_display' ){
 | |
| 				$classes[] = 'is-special-page';
 | |
| 			}
 | |
| 
 | |
| 			switch( $page->gp_index ){
 | |
| 				case 'special_contact':
 | |
| 					$classes[] = 'is-contactform-page';
 | |
| 					break;
 | |
| 
 | |
| 				case 'special_galleries':
 | |
| 					$classes[] = 'is-galleries-page';
 | |
| 					break;
 | |
| 
 | |
| 				case 'special_gpsearch':
 | |
| 					$classes[] = 'is-search-page';
 | |
| 					break;
 | |
| 
 | |
| 				case 'special_missing':
 | |
| 					$classes[] = 'is-missing-page';
 | |
| 					break;
 | |
| 
 | |
| 				case 'special_blog':
 | |
| 					$classes[] = 'is-blog-page';
 | |
| 					if( isset($_GET['id']) ){
 | |
| 						$classes[] = 'is-single-post-page';
 | |
| 					}
 | |
| 					break;
 | |
| 
 | |
| 				case 'special_blog_categories':
 | |
| 					$classes[] = 'is-blog-page';
 | |
| 					$classes[] = 'is-blog-categories-page';
 | |
| 					if( isset($_GET['cat']) ){
 | |
| 						$classes[] = 'is-single-category-page';
 | |
| 					}
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			if( $echo_classes && !empty($classes) ){
 | |
| 				echo ' ' . implode(' ', $classes) . ' ';
 | |
| 			}
 | |
| 
 | |
| 			return $classes;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/*
 | |
| 		 *
 | |
| 		 * editable text, not draggable
 | |
| 		 *
 | |
| 		 *
 | |
| 		 */
 | |
| 
 | |
| 		/**
 | |
| 		 * similar to ReturnText() but links to script for editing all addon texts
 | |
| 		 * the $html parameter should primarily be used when the text is to be placed
 | |
| 		 * inside of a link or other element that cannot have a link and/or span as a child node
 | |
| 		 */
 | |
| 		public static function GetAddonText($key, $html='%s', $wrapper_class=''){
 | |
| 			global $addonFolderName;
 | |
| 
 | |
| 			if( !$addonFolderName ){
 | |
| 				return self::ReturnText($key, $html, $wrapper_class);
 | |
| 			}
 | |
| 
 | |
| 			$query = 'cmd=AddonTextForm&addon=' . urlencode($addonFolderName) . '&key=' . urlencode($key);
 | |
| 			return self::ReturnTextWorker($key, $html, $query, $wrapper_class);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function ReturnText($key,$html='%s', $wrapper_class=''){
 | |
| 			$query = 'cmd=EditText&key='.urlencode($key);
 | |
| 			return self::ReturnTextWorker($key, $html, $query, $wrapper_class);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function ReturnTextWorker($key, $html, $query, $wrapper_class=''){
 | |
| 			global $langmessage;
 | |
| 
 | |
| 			$text		= self::SelectText($key);
 | |
| 			$result		= str_replace('%s', $text, $html); //in case there's more than one %s
 | |
| 
 | |
| 			$editable	= self::ShowEditLink('Admin_Theme_Content');
 | |
| 			if( $editable ){
 | |
| 
 | |
| 				$title = htmlspecialchars(strip_tags($key));
 | |
| 				if( strlen($title) > 20 ){
 | |
| 					$title = substr($title, 0, 20) . '...'; //javscript may shorten it as well
 | |
| 				}
 | |
| 
 | |
| 				self::$editlinks .= self::EditAreaLink(
 | |
| 					$edit_index,
 | |
| 					'Admin_Theme_Content/Text',
 | |
| 					$langmessage['edit'],
 | |
| 					$query,
 | |
| 					['title' => $title, 'data-cmd' => 'gpabox']
 | |
| 				);
 | |
| 				return '<span class="editable_area ' . $wrapper_class .'" '
 | |
| 				 . 'id="ExtraEditArea' . $edit_index . '">' . $result . '</span>';
 | |
| 			}
 | |
| 
 | |
| 			if( $wrapper_class ){
 | |
| 				return '<span class="' . $wrapper_class . '">' . $result . '</span>';
 | |
| 			}
 | |
| 
 | |
| 			return $result;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Returns the user translated string if it exists or
 | |
| 		 * $key (the untranslated string) if a translation doesn't exist
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function SelectText($key){
 | |
| 			global $config,$langmessage;
 | |
| 
 | |
| 			$text = $key;
 | |
| 			if( isset($config['customlang'][$key]) ){
 | |
| 				$text = $config['customlang'][$key];
 | |
| 
 | |
| 			}elseif( isset($langmessage[$key]) ){
 | |
| 				$text = $langmessage[$key];
 | |
| 			}
 | |
| 			return $text;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/*
 | |
| 		 *
 | |
| 		 * Generate and output the <head> portion of the html document
 | |
| 		 *
 | |
| 		 */
 | |
| 
 | |
| 		 public static function GetHead(){
 | |
| 			\gp\tool\Plugins::Action('GetHead');
 | |
| 			self::PrepGadgetContent();
 | |
| 			echo '<!-- get_head_placeholder ' . \gp_random . ' -->';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function HeadContent(){
 | |
| 			global $config, $page, $wbMessageBuffer;
 | |
| 
 | |
| 			//before ob_start() so plugins can get buffer content
 | |
| 			\gp\tool\Plugins::Action('HeadContent');
 | |
| 
 | |
| 
 | |
| 			if( \gp\tool::LoggedIn() ){
 | |
| 				\gp\tool::AddColorBox();
 | |
| 			}
 | |
| 
 | |
| 			//always include javascript when there are messages
 | |
| 			if( $page->admin_js || !empty($page->jQueryCode) || !empty($wbMessageBuffer) || isset($_COOKIE['cookie_cmd']) ){
 | |
| 				\gp\tool::LoadComponents('gp-main');
 | |
| 			}
 | |
| 			//defaults
 | |
| 			\gp\tool::LoadComponents('jquery,gp-additional');
 | |
| 
 | |
| 			//get css and js info
 | |
| 			$scripts = \gp\tool\Output\Combine::ScriptInfo( self::$components );
 | |
| 
 | |
| 			ob_start();
 | |
| 			self::GetHead_TKD();
 | |
| 			self::$head_content = ob_get_clean();
 | |
| 
 | |
| 			ob_start();
 | |
| 			self::GetHead_CSS($scripts['css']); //css before js so it's available to scripts
 | |
| 			self::$head_css = ob_get_clean();
 | |
| 
 | |
| 			//javascript
 | |
| 			ob_start();
 | |
| 			self::GetHead_Lang();
 | |
| 			self::GetHead_JS($scripts['js']);
 | |
| 			self::GetHead_InlineJS();
 | |
| 			self::$head_js = ob_get_clean();
 | |
| 
 | |
| 			//gadget info
 | |
| 			if( isset($config['addons']) ){
 | |
| 				foreach($config['addons'] as $addon_info){
 | |
| 					if( !empty($addon_info['html_head']) ){
 | |
| 						self::MoveScript($addon_info['html_head']);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if( !empty($page->head) ){
 | |
| 				self::MoveScript($page->head);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Move <script>..</script> to self::$head_js
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function MoveScript($string){
 | |
| 
 | |
| 			//conditional comments with script tags
 | |
| 			$patt = '#' . preg_quote('<!--[if', '#') . '.*?' . preg_quote('<![endif]-->', '#') . '#s';
 | |
| 			if( preg_match_all($patt,$string, $matches) ){
 | |
| 				foreach($matches[0] as $match){
 | |
| 					if( strpos($match,'<script') !== false ){
 | |
| 						$string = str_replace($match, '', $string);
 | |
| 						self::$head_js .= "\n" . $match;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//script tags
 | |
| 			if( preg_match_all('#<script.*?</script>#i',$string,$matches) ){
 | |
| 				foreach($matches[0] as $match){
 | |
| 					$string = str_replace($match, '', $string);
 | |
| 					self::$head_js .= "\n" . $match;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//add the rest to the head_content
 | |
| 			self::$head_content .= "\n" . $string;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Output the title, keywords, description and other meta for the current html document
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetHead_TKD(){
 | |
| 			global $config, $page, $gpLayouts;
 | |
| 
 | |
| 			//charset
 | |
| 			if( $page->gpLayout &&
 | |
| 				isset($gpLayouts[$page->gpLayout]) &&
 | |
| 				isset($gpLayouts[$page->gpLayout]['doctype'])
 | |
| 			){
 | |
| 				echo $gpLayouts[$page->gpLayout]['doctype'];
 | |
| 			}
 | |
| 
 | |
| 			//title, keyords & description
 | |
| 			$page_title = self::MetaTitle();
 | |
| 			self::MetaKeywords($page_title);
 | |
| 			self::MetaDescription($page_title);
 | |
| 
 | |
| 			if( !empty($page->TitleInfo['rel']) ){
 | |
| 				echo "\n" . '<meta name="robots" content="' . $page->TitleInfo['rel'] . '" />';
 | |
| 			}
 | |
| 
 | |
| 			echo "\n" . '<meta name="generator" content="' . \CMS_NAME_FULL . '" />';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add the <title> tag to the page
 | |
| 		 * return the value
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function MetaTitle(){
 | |
| 			global $page, $config;
 | |
| 
 | |
| 			$meta_title = '';
 | |
| 			$page_title = '';
 | |
| 			if( !empty($page->TitleInfo['browser_title']) ){
 | |
| 				$page_title = $page->TitleInfo['browser_title'];
 | |
| 			}elseif( !empty($page->label) ){
 | |
| 				$page_title = strip_tags($page->label);
 | |
| 			}elseif( isset($page->title) ){
 | |
| 				$page_title = \gp\tool::GetBrowserTitle($page->title);
 | |
| 			}
 | |
| 			$meta_title .= $page_title;
 | |
| 			if( !empty($page_title) && !empty($config['title']) ){
 | |
| 				$meta_title .=  ' - ';
 | |
| 			}
 | |
| 			$meta_title .= $config['title'];
 | |
| 
 | |
| 			$meta_title = \gp\tool\Plugins::Filter(
 | |
| 				'MetaTitle',
 | |
| 				[$meta_title, $page_title, $config['title']]
 | |
| 			);
 | |
| 
 | |
| 			echo "\n" . '<title>' . strip_tags($meta_title) . '</title>';
 | |
| 			return $page_title;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add the <meta name="keywords"> tag to the page
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function MetaKeywords($page_title){
 | |
| 			global $page, $config;
 | |
| 
 | |
| 			if( count($page->meta_keywords) ){
 | |
| 				$keywords = $page->meta_keywords;
 | |
| 			}elseif( !empty($page->TitleInfo['keywords']) ){
 | |
| 				$keywords = explode(',', $page->TitleInfo['keywords']);
 | |
| 			}
 | |
| 			$keywords[]		= strip_tags($page_title); 
 | |
| 			$page->label .= "";
 | |
| 			$keywords[]		= strip_tags($page->label);
 | |
| 
 | |
| 			$site_keywords	= explode(',', $config['keywords']);
 | |
| 			$keywords		= array_merge($keywords, $site_keywords);
 | |
| 			$keywords		= array_unique($keywords);
 | |
| 			$keywords		= array_filter($keywords);
 | |
| 
 | |
| 			echo "\n<meta name=\"keywords\" content=\"" . implode(', ', $keywords) . "\" />";
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add the <meta name="dscription"> tag to the page
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function MetaDescription($page_title){
 | |
| 			global $page, $config;
 | |
| 
 | |
| 			$description = '';
 | |
| 			if( !empty($page->meta_description) ){
 | |
| 				$description .= $page->meta_description;
 | |
| 			}elseif( !empty($page->TitleInfo['description']) ){
 | |
| 				$description .= $page->TitleInfo['description'];
 | |
| 			}else{
 | |
| 				$description .= $page_title;
 | |
| 			}
 | |
| 			$description = self::EndPhrase($description);
 | |
| 
 | |
| 			if( !empty($config['desc']) ){
 | |
| 				$description .= htmlspecialchars($config['desc']);
 | |
| 			}
 | |
| 			$description = trim($description);
 | |
| 
 | |
| 			if( !empty($description) ){
 | |
| 				echo "\n" . '<meta name="description" content="' . $description . '" />';
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Prepare and output any inline Javascript for the current page
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetHead_InlineJS(){
 | |
| 			global $page, $gp_titles;
 | |
| 
 | |
| 			if( isset($page->gp_index) &&
 | |
| 				isset($gp_titles[$page->gp_index]['vis']) &&
 | |
| 				$gp_titles[$page->gp_index]['vis'] == 'private'
 | |
| 			){
 | |
| 				$page->jQueryCode .= '$("html").addClass("isPrivate");' . "\n";
 | |
| 			}
 | |
| 
 | |
| 			if( \gp\tool::LoggedIn() && $page->pagetype !== 'admin_display' ){
 | |
| 				$page->jQueryCode .= '$gp.HideAdminUI.init();' . "\n";
 | |
| 				// get available classes
 | |
| 				$avail_classes		= \gp\admin\Settings\Classes::GetClasses();
 | |
| 				$avail_classes		= \gp\tool\Plugins::Filter('AvailableClasses', [$avail_classes]);
 | |
| 				$page->head_script .= "\n" . 'var gp_avail_classes = ' . json_encode($avail_classes) . ';';
 | |
| 			}
 | |
| 
 | |
| 			// get customizer js vars
 | |
| 			$layout_js_vars = self::GetLayoutJsVars();
 | |
| 			// debug('$layout_js_vars = <em>' . $layout_js_vars . '</em>');
 | |
| 
 | |
| 			ob_start();
 | |
| 
 | |
| 			echo $layout_js_vars;
 | |
| 
 | |
| 			echo $page->head_script . "\n";
 | |
| 
 | |
| 			if( !empty($page->jQueryCode) ){
 | |
| 				echo '$(function(){' . "\n";
 | |
| 				echo $page->jQueryCode . "\n";
 | |
| 				echo '});';
 | |
| 			}
 | |
| 
 | |
| 			$inline = ob_get_clean();
 | |
| 			$inline = ltrim($inline);
 | |
| 
 | |
| 			echo "\n" . '<script type="text/javascript">' . "\n" . $inline . "\n" . '</script>' . "\n";
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add language values to the current page
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetHead_Lang(){
 | |
| 			global $langmessage;
 | |
| 
 | |
| 			if( !count(self::$lang_values) ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			echo "\n" . '<script type="text/javascript">';
 | |
| 			echo 'var gplang = {';
 | |
| 			$comma = '';
 | |
| 			foreach(self::$lang_values as $from_key => $to_key){
 | |
| 				echo $comma;
 | |
| 				echo $to_key . ':"'	. str_replace(['\\', '"'], ['\\\\', '\"'], $langmessage[$from_key]) . '"';
 | |
| 				$comma = ',';
 | |
| 			}
 | |
| 			echo "}; </script>";
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Prepare and output the Javascript for the current page
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetHead_JS($scripts){
 | |
| 			global $page, $config;
 | |
| 
 | |
| 			$combine	= $config['combinejs'] && !\gp\tool::loggedIn() && ($page->pagetype !== 'admin_display');
 | |
| 			$scripts	= self::GetHead_CDN('js', $scripts);
 | |
| 
 | |
| 			//just local jquery
 | |
| 			if( !count($page->head_js) && count($scripts) === 1 && isset($scripts['jquery']) ){
 | |
| 				echo '<!-- jquery_placeholder ' . \gp_random . ' -->';
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			if( !$combine || $page->head_force_inline ){
 | |
| 				echo "\n<script type=\"text/javascript\">\n";
 | |
| 				\gp\tool::jsStart();
 | |
| 				echo "\n</script>";
 | |
| 			}
 | |
| 
 | |
| 			if( is_array($page->head_js) ){
 | |
| 				$scripts += $page->head_js; //other js files
 | |
| 			}else{
 | |
| 				trigger_error('$page->head_js is not an array');
 | |
| 			}
 | |
| 
 | |
| 			Output\Assets::CombineFiles($scripts, 'js', $combine);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Prepare and output the css for the current page
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetHead_CSS($to_add){
 | |
| 			global $page, $config, $dataDir;
 | |
| 
 | |
| 			$scripts	= [];
 | |
| 			$to_add		= self::GetHead_CDN('css', $to_add);
 | |
| 			$scripts	= Output\Assets::MergeScripts($scripts, $to_add);
 | |
| 
 | |
| 
 | |
| 			if( isset($page->css_user) ){
 | |
| 				$scripts	= Output\Assets::MergeScripts($scripts, $page->css_user);
 | |
| 			}
 | |
| 
 | |
| 			// add theme css
 | |
| 			if( !empty($page->theme_name) && $page->get_theme_css === true ){
 | |
| 				$scripts	= Output\Assets::MergeScripts($scripts, Output\Assets::LayoutStyleFiles());
 | |
| 			}
 | |
| 
 | |
| 			//styles that need to override admin.css should be added to $page->css_admin;
 | |
| 			if( isset($page->css_admin)  ){
 | |
| 				$scripts	= Output\Assets::MergeScripts($scripts, $page->css_admin);
 | |
| 			}
 | |
| 
 | |
| 			// disable 'combine css' if 'create_css_sourcemaps' is set to true in /gpconfig.php
 | |
| 			$combinecss = \create_css_sourcemaps ? false : $config['combinecss'];
 | |
| 
 | |
| 			Output\Assets::CombineFiles($scripts, 'css', $combinecss);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add CDN hosted resources to the page
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetHead_CDN($type, $scripts){
 | |
| 			global $config;
 | |
| 
 | |
| 			if( empty($config['cdn']) ){
 | |
| 				return $scripts;
 | |
| 			}
 | |
| 
 | |
| 			$cdn		= $config['cdn'];
 | |
| 
 | |
| 			foreach($scripts as $key => $script_info){
 | |
| 
 | |
| 				if( !isset($script_info['cdn']) || !isset($script_info['cdn'][$cdn]) ){
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				$cdn_url = $script_info['cdn'][$cdn];
 | |
| 
 | |
| 				//remove packages
 | |
| 				if( isset($script_info['package']) ){
 | |
| 					foreach($scripts as $_key => $_info){
 | |
| 						if( isset($_info['package']) && $_info['package'] == $script_info['package'] ){
 | |
| 							unset($scripts[$_key]);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				unset($scripts[$key]);
 | |
| 
 | |
| 				echo Output\Assets::FormatAsset($type,$cdn_url);
 | |
| 			}
 | |
| 
 | |
| 			return $scripts;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get the path for the custom css/scss/less file
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function CustomStyleFile($layout, $style_type){
 | |
| 			global $dataDir;
 | |
| 
 | |
| 			if( $style_type == 'scss' ){
 | |
| 				return $dataDir . '/data/_layouts/' . $layout . '/custom.scss';
 | |
| 			}
 | |
| 
 | |
| 			return $dataDir . '/data/_layouts/' . $layout . '/custom.css';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get the path for the customizer css/scss/less file
 | |
| 		 *
 | |
| 		 * @since 5.2
 | |
| 		 */
 | |
| 		public static function CustomizerStyleFile($layout, $style_type){
 | |
| 			global $dataDir;
 | |
| 
 | |
| 			if( $style_type == 'scss' ){
 | |
| 				return $dataDir . '/data/_layouts/' . $layout . '/customizer.scss';
 | |
| 			}
 | |
| 
 | |
| 			return $dataDir . '/data/_layouts/' . $layout . '/customizer.css';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get the path for the custom layout config file
 | |
| 		 *
 | |
| 		 * @since 5.2
 | |
| 		 */
 | |
| 		public static function LayoutConfigFile($layout){
 | |
| 			global $dataDir;
 | |
| 
 | |
| 			return $dataDir . '/data/_layouts/' . $layout . '/config.php';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Get the filetype of the style.* file
 | |
| 		 *
 | |
| 		 * @return string
 | |
| 		 */
 | |
| 		public static function StyleType($dir){
 | |
| 
 | |
| 			$types = ['less','scss'];
 | |
| 
 | |
| 			foreach($types as $type){
 | |
| 				$path = $dir . '/style.'.$type;
 | |
| 				if( file_exists($path) ){
 | |
| 					return $type;
 | |
| 				}
 | |
| 			}
 | |
| 			return 'css';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Determines whether the passed directory qualifies as layout
 | |
| 		 * by checking whether a style.css, style.less or style.css file exists
 | |
| 		 * @return boolean
 | |
| 		 */
 | |
| 		public static function IsLayoutDir($dir){
 | |
| 
 | |
| 			$types = ['less','scss','css'];
 | |
| 
 | |
| 			foreach($types as $type){
 | |
| 				$path = $dir . '/style.' . $type;
 | |
| 				if( file_exists($path) ){
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Complete the response by adding final content to the <head> of the document
 | |
| 		 * @static
 | |
| 		 * @since 2.4.1
 | |
| 		 * @param string $buffer html content
 | |
| 		 * @return string finalized response
 | |
| 		 */
 | |
| 		public static function BufferOut($buffer){
 | |
| 			global $config;
 | |
| 
 | |
| 			//add error notice if there was a fatal error
 | |
| 			if( !ini_get('display_errors') ){
 | |
| 				$last_error	= self::LastFatal();
 | |
| 				if( !empty($last_error) ){
 | |
| 					self::RecordFatal($last_error);
 | |
| 					$buffer .= self::FatalMessage($last_error);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			//remove lock
 | |
| 			if( defined('gp_has_lock') && \gp_has_lock ){
 | |
| 				\gp\tool\Files::Unlock('write', \gp_random);
 | |
| 			}
 | |
| 
 | |
| 			//make sure whe have a complete html request
 | |
| 			$placeholder = '<!-- get_head_placeholder ' . \gp_random . ' -->';
 | |
| 			if( strpos($buffer,$placeholder) === false ){
 | |
| 				return $buffer;
 | |
| 			}
 | |
| 
 | |
| 			$replacements		= [];
 | |
| 
 | |
| 			//performace stats
 | |
| 			if( class_exists('admin_tools') ){
 | |
| 				$replacements	= self::PerformanceStats();
 | |
| 			}
 | |
| 
 | |
| 			//head content
 | |
| 			//add css to bottom of <body>
 | |
| 			if( \load_css_in_body ){
 | |
| 				$buffer = self::AddToBody($buffer, self::$head_css);
 | |
| 				$replacements[$placeholder]	= self::$head_content;
 | |
| 			}else{
 | |
| 				$replacements[$placeholder]	= self::$head_css . self::$head_content;
 | |
| 			}
 | |
| 
 | |
| 			//add js to bottom of <body>
 | |
| 			$buffer = self::AddToBody($buffer, self::$head_js);
 | |
| 
 | |
| 			//add jquery if needed
 | |
| 			$placeholder = '<!-- jquery_placeholder ' . \gp_random . ' -->';
 | |
| 			$replacement = '';
 | |
| 			if( !empty(self::$head_js) || stripos($buffer, '<script') !== false ){
 | |
| 				$replacement = Output\Assets::FormatAsset('js',\gp\tool::GetDir('/include/thirdparty/js/jquery.js')); // TODO: restore this line
 | |
| 			}
 | |
| 
 | |
| 			$replacements[$placeholder]	= $replacement;
 | |
| 
 | |
| 			//messages
 | |
| 			$pos = strpos($buffer, '<!-- message_start ' . \gp_random . ' -->');
 | |
| 			$len = strpos($buffer, '<!-- message_end -->') - $pos;
 | |
| 			if( $pos && $len ){
 | |
| 				$replacement = GetMessages(false);
 | |
| 				$buffer = substr_replace($buffer, $replacement, $pos, $len + 20);
 | |
| 			}
 | |
| 
 | |
| 			return str_replace( array_keys($replacements), array_values($replacements), $buffer);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add content to the html document before the </body> tag
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function AddToBody($buffer, $add_string){
 | |
| 
 | |
| 			if( empty($add_string) ){
 | |
| 				return $buffer;
 | |
| 			}
 | |
| 
 | |
| 			$pos_body = stripos($buffer, '</body');
 | |
| 			if( $pos_body !== false ){
 | |
| 				return substr_replace($buffer, "\n" . $add_string . "\n", $pos_body, 0);
 | |
| 			}
 | |
| 
 | |
| 			return $buffer;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Return the message displayed when a fatal error has been caught
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function FatalMessage($error_details){
 | |
| 
 | |
| 			$message = '<p>Oops, an error occurred while generating this page.<p>';
 | |
| 
 | |
| 			if( !\gp\tool::LoggedIn() ){
 | |
| 
 | |
| 				//reload non-logged in users automatically if there were catchable errors
 | |
| 				if( !empty(self::$catchable) ){
 | |
| 					$message .= 'Reloading... <script type="text/javascript">'
 | |
| 						. 'window.setTimeout(function(){window.location.href = '
 | |
| 						. 'window.location.href},1000);</script>';
 | |
| 				}else{
 | |
| 					$message .= '<p>If you are the site administrator, you can troubleshoot '
 | |
| 						. 'the problem by changing php\'s display_errors setting to 1 in '
 | |
| 						. 'the gpconfig.php file.</p><p>If the problem is being caused by an addon, '
 | |
| 						. 'you may also be able to bypass the error by enabling ' . \CMS_NAME . '\'s '
 | |
| 						. 'safe mode in the gpconfig.php file.</p><p>More information is available '
 | |
| 						. 'in the <a href="' . \CMS_DOMAIN . '/Docs/Main/Troubleshooting">Documentation</a>.'
 | |
| 						. '</p><p><a href="?">Reload this page to continue</a>.</p>';
 | |
| 				}
 | |
| 
 | |
| 				return $message;
 | |
| 			}
 | |
| 
 | |
| 			$message .= '<h3>Error Details</h3>'
 | |
| 					.pre($error_details)
 | |
| 					. '<p><a href="?">Reload this page</a></p>'
 | |
| 					. '<p style="font-size:90%">Note: Error details are only '
 | |
| 					. 'displayed for logged in administrators</p>'
 | |
| 					. \gp\tool::ErrorBuffer(true, false);
 | |
| 
 | |
| 			return $message;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Determine if a fatal error has been fired
 | |
| 		 * @return array
 | |
| 		 */
 | |
| 		public static function LastFatal(){
 | |
| 			$fatal_errors	= [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR];
 | |
| 			$last_error		= error_get_last();
 | |
| 			if( is_array($last_error) && in_array($last_error['type'], $fatal_errors) ){
 | |
| 				return $last_error;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Record fatal errors in /data/_site/ so we can prevent subsequent requests from having the same issue
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function RecordFatal($last_error){
 | |
| 			global $config, $addon_current_id, $addonFolderName;
 | |
| 
 | |
| 			$last_error['request'] = $_SERVER['REQUEST_URI'];
 | |
| 			if( $addon_current_id ){
 | |
| 				$last_error['addon_name'] = $config['addons'][$addonFolderName]['name'];
 | |
| 				$last_error['addon_id'] = $addon_current_id;
 | |
| 			}
 | |
| 
 | |
| 			$last_error['file'] = realpath($last_error['file']);//may be redundant
 | |
| 			showError(
 | |
| 				$last_error['type'],
 | |
| 				$last_error['message'],
 | |
| 				$last_error['file'],
 | |
| 				$last_error['line'],
 | |
| 				false
 | |
| 			); //send error to logger
 | |
| 
 | |
| 			if( empty(self::$catchable) ){
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			$last_error['time'] = time();
 | |
| 			$last_error['request_method'] = $_SERVER['REQUEST_METHOD'];
 | |
| 			if( !empty($last_error['file']) ){
 | |
| 				$last_error['file_modified'] = filemtime($last_error['file']);
 | |
| 				$last_error['file_size'] = filesize($last_error['file']);
 | |
| 			}
 | |
| 
 | |
| 			$content	= json_encode($last_error);
 | |
| 			$temp		= array_reverse(self::$catchable);
 | |
| 
 | |
| 			foreach($temp as $filepath => $info){
 | |
| 
 | |
| 				\gp\tool\Files::Save($filepath,$content);
 | |
| 
 | |
| 				if( $info['catchable_type'] == 'exec' ){
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Return Performance Stats about the current request
 | |
| 		 *
 | |
| 		 * @return array
 | |
| 		 */
 | |
| 		public static function PerformanceStats(){
 | |
| 
 | |
| 			$stats = [];
 | |
| 
 | |
| 			if( function_exists('memory_get_peak_usage') ){
 | |
| 				$stats['<span cms-memory-usage>?</span>']	= \gp\admin\Tools::FormatBytes(memory_get_usage());
 | |
| 				$stats['<span cms-memory-max>?</span>']		= \gp\admin\Tools::FormatBytes(memory_get_peak_usage());
 | |
| 			}
 | |
| 
 | |
| 			if( isset($_SERVER['REQUEST_TIME_FLOAT']) ){
 | |
| 				$time	= microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
 | |
| 			}else{
 | |
| 				$time	= microtime(true) - gp_start_time;
 | |
| 			}
 | |
| 
 | |
| 			$stats['<span cms-seconds>?</span>']	= round($time, 3);
 | |
| 			$stats['<span cms-ms>?</span>']			= round($time * 1000);
 | |
| 
 | |
| 			return $stats;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Return true if the user agent is a search engine bot
 | |
| 		 * Detection is rudimentary and shouldn't be relied on
 | |
| 		 * @return bool
 | |
| 		 */
 | |
| 		public static function DetectBot(){
 | |
| 			$user_agent =& $_SERVER['HTTP_USER_AGENT'];
 | |
| 			return (bool)preg_match('#bot|yahoo\! slurp|ask jeeves|ia_archiver|spider|crawler#i', $user_agent);
 | |
| 		}
 | |
| 
 | |
| 		/**
 | |
| 		 * Return true if the current page is the home page
 | |
| 		 */
 | |
| 		public static function is_front_page(){
 | |
| 			global $config, $page;
 | |
| 			return $page->gp_index == $config['homepath_key'];
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Outputs the sitemap link, admin login/logout link, powered by link and messages
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetAdminLink($messages=true){
 | |
| 			self::GetSitemapLink(); // as of 5.2-rc
 | |
| 			echo ' ';
 | |
| 			self::GetLoginLink(); // as of 5.2-rc
 | |
| 			echo ' ';
 | |
| 			self::GetPoweredByLink(); // as of 5.2-rc
 | |
| 
 | |
| 			\gp\tool\Plugins::Action('GetAdminLink');
 | |
| 
 | |
| 			if( $messages ){
 | |
| 				echo GetMessages();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Outputs only the sitemap link
 | |
| 		 * as of 5.2-rc
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetSitemapLink(){
 | |
| 			global $config, $langmessage, $page;
 | |
| 
 | |
| 			if( !isset($config['showsitemap']) || $config['showsitemap'] ){
 | |
| 				echo ' <span class="sitemap_link">';
 | |
| 				echo \gp\tool::Link(
 | |
| 					'Special_Site_Map',
 | |
| 					$langmessage['site_map']
 | |
| 				);
 | |
| 				\gp\tool\Plugins::Action('GetSitemapLink');
 | |
| 				echo '</span>';
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Outputs only the login/logout link
 | |
| 		 * as of 5.2-rc
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetLoginLink($force_show=false){
 | |
| 			global $config, $langmessage, $page;
 | |
| 
 | |
| 			if( $force_show || !isset($config['showlogin']) || $config['showlogin'] ){
 | |
| 				echo '<span class="login_link">';
 | |
| 					if( \gp\tool::LoggedIn() ){
 | |
| 						echo \gp\tool::Link(
 | |
| 							$page->title,
 | |
| 							$langmessage['logout'],
 | |
| 							'cmd=logout',
 | |
| 							['data-cmd' => 'cnreq', 'rel' => 'nofollow']
 | |
| 						);
 | |
| 					}else{
 | |
| 						echo \gp\tool::Link(
 | |
| 							'Admin',
 | |
| 							$langmessage['login'],
 | |
| 							'file=' . rawurlencode($page->title),
 | |
| 							['data-cmd' => 'login', 'rel' => 'nofollow']
 | |
| 						);
 | |
| 					}
 | |
| 				\gp\tool\Plugins::Action('GetLoginLink');
 | |
| 				echo '</span>';
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function AdminLinkGadget(){
 | |
| 			self::GetAdminLink(false);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function LoginLinkGadget(){
 | |
| 			self::GetLoginLink(true);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Outputs only the powered_by link
 | |
| 		 * as of 5.2-rc
 | |
| 		 * @static
 | |
| 		 */
 | |
| 		public static function GetPoweredByLink($always_show=false){
 | |
| 			global $config;
 | |
| 
 | |
| 			if( !isset($config['showgplink']) || $config['showgplink'] ){
 | |
| 				if( self::is_front_page() || $always_show ){
 | |
| 					echo '<span id="powered_by_link">';
 | |
| 					echo 'Powered by <a href="' . \CMS_DOMAIN . '" target="_blank">' . \CMS_NAME . '</a>';
 | |
| 					\gp\tool\Plugins::Action('GetPoweredByLink');
 | |
| 					echo '</span>';
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add punctuation to the end of a string if it isn't already punctuated.
 | |
| 		 * Looks for !?.,;: characters
 | |
| 		 *
 | |
| 		 * @static
 | |
| 		 * @since 2.4RC1
 | |
| 		 */
 | |
| 		public static function EndPhrase($string){
 | |
| 			$string = trim($string);
 | |
| 			if( empty($string) ){
 | |
| 				return $string;
 | |
| 			}
 | |
| 			$len = strspn($string, '!?.,;:', -1);
 | |
| 			if( $len == 0 ){
 | |
| 				$string .= '.';
 | |
| 			}
 | |
| 			return $string . ' ';
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public static function RunOut(){
 | |
| 			global $langmessage, $page;
 | |
| 
 | |
| 			$page->RunScript();
 | |
| 
 | |
| 			//prepare the admin content
 | |
| 			if( \gp\tool::LoggedIn() ){
 | |
| 				\gp\admin\Tools::AdminHtml();
 | |
| 			}
 | |
| 
 | |
| 			//decide how to send the content
 | |
| 			self::Prep();
 | |
| 			switch(\gp\tool::RequestType()){
 | |
| 
 | |
| 				// <a data-cmd="admin_box">
 | |
| 				case 'flush':
 | |
| 					self::Flush();
 | |
| 					break;
 | |
| 
 | |
| 				// remote request
 | |
| 				// file browser
 | |
| 				case 'body':
 | |
| 					\gp\tool::CheckTheme();
 | |
| 					self::BodyAsHTML();
 | |
| 					break;
 | |
| 
 | |
| 				case 'admin':
 | |
| 					self::AdminHtml();
 | |
| 					break;
 | |
| 
 | |
| 				// <a data-cmd="gpajax">
 | |
| 				// <a data-cmd="gpabox">
 | |
| 				// <input data-cmd="gpabox">
 | |
| 				case 'json':
 | |
| 					\gp\tool::CheckTheme();
 | |
| 					\gp\tool\Output\Ajax::Response();
 | |
| 					break;
 | |
| 
 | |
| 				case 'content':
 | |
| 					self::Content();
 | |
| 					break;
 | |
| 
 | |
| 				default:
 | |
| 					\gp\tool::CheckTheme();
 | |
| 					self::Template();
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			// if logged in, don't send 304 response
 | |
| 			if( \gp\tool::LoggedIn() ){
 | |
| 				//empty edit links if there isn't a layout
 | |
| 				if( !$page->gpLayout ){
 | |
| 					self::$editlinks = '';
 | |
| 				}
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			// attempt to send 304 response
 | |
| 			if( $page->fileModTime > 0 ){
 | |
| 				global $wbMessageBuffer;
 | |
| 				$len	= ob_get_length();
 | |
| 				$etag	= \gp\tool::GenEtag(
 | |
| 					$page->fileModTime,
 | |
| 					$len,
 | |
| 					json_encode($wbMessageBuffer),
 | |
| 					self::$head_content,
 | |
| 					self::$head_js
 | |
| 				);
 | |
| 				\gp\tool::Send304($etag);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/**
 | |
| 		 * Add one or more components to the page. Output the <script> and/or <style> immediately
 | |
| 		 * @param string $names comma separated list of components
 | |
| 		 *
 | |
| 		 */
 | |
| 		public static function GetComponents($names=''){
 | |
| 			$scripts = \gp\tool\Output\Combine::ScriptInfo($names);
 | |
| 
 | |
| 			$scripts['css'] = self::GetHead_CDN('css', $scripts['css']);
 | |
| 			Output\Assets::CombineFiles($scripts['css'], 'css', false);
 | |
| 
 | |
| 			$scripts['js'] = self::GetHead_CDN('js', $scripts['js']);
 | |
| 			Output\Assets::CombineFiles($scripts['js'], 'js', false);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| }
 | |
| 
 | |
| namespace{
 | |
| 	class gpOutput extends gp\tool\Output{}
 | |
| }
 |