'common/css/xeicon/', '@\beditor/skins/xpresseditor/js/xe_textarea\.(?:min\.)?js@' => 'editor/skins/ckeditor/js/xe_textarea.js', '@/lang$@' => '/lang/lang.xml', ); /** * Image type information for SEO */ protected $_image_type = 'none'; /** * Produce HTML compliant content given a module object.\n * @param ModuleObject $oModule the module object * @return string compiled template string */ public function toDoc(&$oModule) { // SECISSUE https://github.com/xpressengine/xe-core/issues/1583 $oSecurity = new Security(); $oSecurity->encodeHTML('is_keyword', 'search_keyword', 'search_target', 'order_target', 'order_type'); $template_path = $oModule->getTemplatePath(); $template_file = $oModule->getTemplateFile(); if(!is_dir($template_path)) { if($oModule->module_info->module == $oModule->module) { $skin = $oModule->origin_module_info->skin; } else { $skin = $oModule->module_config->skin; } if(Context::get('module') != 'admin' && strpos(Context::get('act'), 'Admin') === false) { if($skin && is_string($skin)) { $theme_skin = explode('|@|', $skin); $template_path = $oModule->getTemplatePath(); if(count($theme_skin) == 2) { $theme_path = sprintf('./themes/%s', $theme_skin[0]); // FIXME $theme_path $theme_path $theme_path ?? if(substr($theme_path, 0, strlen($theme_path)) != $theme_path) { $template_path = sprintf('%s/modules/%s/', $theme_path, $theme_skin[1]); } } } else { $template_path = $oModule->getTemplatePath(); } } else { $template_path = $oModule->getTemplatePath(); } } $oTemplate = new Rhymix\Framework\Template($template_path, $template_file); $output = $oTemplate->compile(); // add .x div for adminitration pages if(Context::getResponseMethod() == 'HTML') { $x_exclude_actions = array( 'dispPageAdminContentModify' => true, 'dispPageAdminMobileContentModify' => true, 'dispPageAdminMobileContent' => true, ); $current_act = strval(Context::get('act')); if(Context::get('module') != 'admin' && strpos($current_act, 'Admin') !== false && !isset($x_exclude_actions[$current_act])) { $output = '
' . $output . '
'; } // Wrap content in layout $use_layout = Context::get('layout') !== 'none'; if (!$use_layout && isset($_REQUEST['layout']) && !self::isPartialPageRendering()) { $use_layout = true; } if ($use_layout) { $start = microtime(true); Context::set('content', $output, false); $layout_path = $oModule->getLayoutPath(); $layout_file = $oModule->getLayoutFile(); $edited_layout_file = $oModule->getEditedLayoutFile(); // get the layout information currently requested $oLayoutModel = getModel('layout'); $layout_info = Context::get('layout_info'); $layout_srl = $layout_info->layout_srl ?? 0; // compile if connected to the layout if($layout_srl > 0) { // handle separately if the layout is faceoff if($layout_info && isset($layout_info->type) && $layout_info->type == 'faceoff') { $oLayoutModel->doActivateFaceOff($layout_info); Context::set('layout_info', $layout_info); } // search if the changes CSS exists in the admin layout edit window $edited_layout_css = $oLayoutModel->getUserLayoutCss($layout_srl); if(FileHandler::exists($edited_layout_css)) { Context::loadFile(array($edited_layout_css, 'all', '', 100)); } } if(!$layout_path) { $layout_path = './common/tpl'; } if(!$layout_file) { $layout_file = 'default_layout'; } $oTemplate = new Rhymix\Framework\Template; $output = $oTemplate->compile($layout_path, $layout_file, $edited_layout_file); // Add layout header script. if ($layout_srl > 0) { $part_config = ModuleModel::getModulePartConfig('layout', $layout_srl); if ($part_config && isset($part_config->header_script)) { Context::addHtmlHeader($part_config->header_script, true); } } // if popup_layout, remove admin bar. $realLayoutPath = FileHandler::getRealPath($layout_path); if(substr_compare($realLayoutPath, '/', -1) !== 0) { $realLayoutPath .= '/'; } $pathInfo = pathinfo($layout_file); $onlyLayoutFile = $pathInfo['filename']; $GLOBALS['__layout_compile_elapsed__'] = microtime(true) - $start; } } // Add OpenGraph and Twitter metadata if (config('seo.og_enabled') && Context::get('module') !== 'admin') { $this->_addOpenGraphMetadata(); if (config('seo.twitter_enabled')) { $this->_addTwitterMetadata(); } } // set icon $site_module_info = Context::get('site_module_info'); $oAdminModel = getAdminModel('admin'); $favicon_url = $oAdminModel->getFaviconUrl($site_module_info->domain_srl); $mobicon_url = $oAdminModel->getMobileIconUrl($site_module_info->domain_srl); Context::set('favicon_url', $favicon_url); Context::set('mobicon_url', $mobicon_url); // Only print the X-UA-Compatible meta tag if somebody is still using IE if (preg_match('!Trident/7\.0!', $_SERVER['HTTP_USER_AGENT'] ?? '')) { Context::addMetaTag('X-UA-Compatible', 'IE=edge', true); } return $output; } /** * Check if partial page rendering (dropping the layout) is enabled. * * @return bool */ public static function isPartialPageRendering() { $ppr = config('view.partial_page_rendering') ?? 'internal_only'; if ($ppr === 'disabled') { return false; } elseif ($ppr === 'ajax_only' && empty($_SERVER['HTTP_X_REQUESTED_WITH'])) { return false; } elseif ($ppr === 'internal_only' && (!isset($_SERVER['HTTP_REFERER']) || !Rhymix\Framework\URL::isInternalURL($_SERVER['HTTP_REFERER']))) { return false; } elseif ($ppr === 'except_robots' && isCrawler()) { return false; } else { return true; } } /** * when display mode is HTML, prepare code before print. * @param string $output compiled template string * @return void */ public function prepareToPrint(&$output) { if(Context::getResponseMethod() != 'HTML') { return; } $start = microtime(true); // move in body to the header $output = preg_replace_callback('!(.*?)<\/style>!is', array($this, '_moveStyleToHeader'), $output); // move and in body to the header $output = preg_replace_callback('!<(link|meta)\b(.*?)>!is', array($this, '_moveLinkToHeader'), $output); // change a meta fine(widget often put the tag like to the content because of caching) $output = preg_replace_callback('//is', array($this, '_transMeta'), $output); // handles a relative path generated by using the rewrite module if(Context::isAllowRewrite()) { $pattern = '/(action)=(["\'])(["\'])/s'; $output = preg_replace($pattern, '$1=$2' . \RX_BASEURL . '$3', $output); $pattern = '/(action|poster|src|href)=(["\'])\.\/([^"\']*)(["\'])/s'; $output = preg_replace($pattern, '$1=$2' . \RX_BASEURL . '$3$4', $output); $pattern = '/src=(["\'])((?:files\/(?:attach|cache|faceOff|member_extra_info|thumbnails)|addons|common|(?:m\.)?layouts|modules|widgets|widgetstyle)\/[^"\']+)(["\'])/s'; $output = preg_replace($pattern, 'src=$1' . \RX_BASEURL . '$2$3', $output); $pattern = '/href=(["\'])(\?[^"\']+)/s'; $output = preg_replace($pattern, 'href=$1' . \RX_BASEURL . '$2', $output); } // prevent the 2nd request due to url(none) of the background-image $output = preg_replace('/url\((["\']?)none(["\']?)\)/is', 'none', $output); $INPUT_ERROR = Context::get('INPUT_ERROR'); if(is_array($INPUT_ERROR) && count($INPUT_ERROR)) { $keys = array_map(function($str) { return preg_quote($str, '@'); }, array_keys($INPUT_ERROR)); $keys = '(' . implode('|', $keys) . ')'; $output = preg_replace_callback('@(]*?)\sname="' . $keys . '"([^>]*?)/?>@is', array(&$this, '_preserveValue'), $output); $output = preg_replace_callback('@]*\sname="' . $keys . '".+@isU', array(&$this, '_preserveSelectValue'), $output); $output = preg_replace_callback('@]*\sname="' . $keys . '".+@isU', array(&$this, '_preserveTextAreaValue'), $output); } $GLOBALS['__trans_content_elapsed__'] = microtime(true) - $start; // Remove unnecessary information $output = preg_replace('/member\_\-([0-9]+)/s', 'member_0', $output); // convert the final layout Context::set('content', $output); if(Mobile::isFromMobilePhone()) { $this->_loadMobileJSCSS(); } else { $this->_loadDesktopJSCSS(); } $oTemplate = new Rhymix\Framework\Template('./common/tpl', 'common_layout'); $output = $oTemplate->compile(); // replace the user-defined-language $output = Context::replaceUserLang($output); // remove template path comment tag /* if(!Rhymix\Framework\Debug::isEnabledForCurrentUser()) { $output = preg_replace('/\n\r?\n/', "\n", $output); } */ } /** * when display mode is HTML, prepare code before print about tag value. * @param array $match input value. * @return string input value. */ function _preserveValue($match) { $INPUT_ERROR = Context::get('INPUT_ERROR'); if (!is_scalar($INPUT_ERROR[$match[3]])) { return $match[0]; } $str = $match[1] . $match[2] . ' name="' . $match[3] . '"' . $match[4]; // get type $type = 'text'; if(preg_match('/\stype="([^"]+)"/i', $str, $m)) { $type = strtolower($m[1]); } switch($type) { case 'radio': case 'checkbox': if(preg_match('@\s(?i:value)="' . preg_quote($INPUT_ERROR[$match[3]], '@') . '"@', $str)) { $str = preg_replace('@\schecked(="[^"]*?")?@', ' checked="checked"', $str); } break; default: if (!preg_match('@\svalue="([^"]*?)"@', $str)) { $str = $str . ' value=""'; } $str = preg_replace_callback('@\svalue="([^"]*?)"@', function() use($INPUT_ERROR, $match) { return ' value="' . escape($INPUT_ERROR[$match[3]], true) . '"'; }, $str); } return $str . ' />'; } /** * when display mode is HTML, prepare code before print about '; } /** * when display mode is HTML, prepare code before print about '; } /** * Move