/** * Utility function to translate a filesize in bytes into a human-readable version. * * @param int $filesize Filesize in bytes * @param int $round Precision to round to * * @return string */ function format_size($filesize, $round = 2) { $suf = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'); $c = 0; while ($filesize >= 1024) { $c++; $filesize = $filesize / 1024; } return I18NLoader::FormatNumber($filesize, $round) . ' ' . $suf[$c]; }
/** * Display a filesize in a human-readable format. * * #### Example Usage * * <pre> * {filesize 123} => "123 bytes" * {filesize 2048} => "2 kiB" * </pre> * * @param array $params Associative (and/or indexed) array of smarty parameters passed in from the template * @param Smarty $smarty Parent Smarty template object * * @return string * @throws SmartyException */ function smarty_function_filespeed($params, $smarty){ $size = $params[0]; $suf = array('bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps', 'Ebps', 'Zbps', 'Ybps'); $c = 0; while ($size >= 1024) { $c++; $size = $size / 1024; } return \Core\i18n\I18NLoader::FormatNumber($size, 1) . ' ' . $suf[$c]; }
$default = str_replace('"', '\\"', $keyData['results']['FALLBACK']); $output .= implode("\n;", explode("\n", $default)) . "\";\n"; if($keyData['found']){ $output .= $keyData['key'] . " = \"" . str_replace('"', '\\"', $keyData['match_str']) . "\";\n"; } else{ $output .= $keyData['key'] . " = \"\";\n"; } $output .= "\n"; } // Now generate any dialect-specific keys. foreach($baseData['dialects'] as $dialect){ $output .= "; Dialect-specific overrides for " . $dialect . "\n[" . $dialect . "]\n"; foreach($matches as $m){ $keyData = \Core\i18n\I18NLoader::Get($m, $dialect); if($keyData['found'] && $keyData['match_key'] == $dialect){ // This specific dialect has an override. $output .= $keyData['key'] . " = \"" . str_replace('"', '\\"', $keyData['match_str']) . "\";\n"; } } $output .= "\n"; } if($arguments->getArgumentValue('dry-run')){ echo $output; } else{ // Write this output to the requested ini file! $file = \Core\Filestore\Factory::File($dir . '/i18n/' . $lang . '.ini'); $file->putContents($output);
public function view(){ $v = $this->getView(); $pages = PageModel::Find(array('admin' => '1')); $groups = array(); $flatlist = array(); if(isset($_SESSION['user_sudo'])){ $p = new PageModel('/user/sudo'); $p->set('title', 'Exit SUDO Mode'); $groups['SUDO'] = [ 'title' => 'SUDO', 'href' => '', 'children' => [ 'Exit SUDO Mode' => $p, ], ]; $flatlist[ 'Exit SUDO Mode' ] = $p; } if(\Core\user()){ foreach($pages as $p){ /** @var PageModel $p */ if(!\Core\user()->checkAccess($p->get('access'))) continue; // Pages can define which sub-menu they get grouped under. // The 'Admin' submenu is the default. $group = $p->get('admin_group') ? $p->get('admin_group') : 't:STRING_ADMIN'; // Support i18n here! if(strpos($group, 't:') === 0){ $group = t(substr($group, 2)); } if(!isset($groups[$group])){ $groups[$group] = [ 'title' => $group, 'href' => '', 'children' => [], ]; } if($p->get('baseurl') == '/admin'){ // Admin gets special treatment. $groups[t('STRING_ADMIN')]['href'] = '/admin'; continue; } switch($p->get('title')){ case 'System Configuration': $p->set('title', "System Config"); break; case 'Navigation Listings': $p->set('title', "Navigation"); break; case 'Content Page Listings': $p->set('title', "Content Pages"); break; default: $p->set( 'title', trim( str_replace(['Administration', 'Admin'],'', $p->get('title')) ) ); } $title = $p->get('title'); // Support i18n here! if(strpos($title, 't:') === 0){ $title = t(substr($title, 2)); } if(isset($groups[$title])){ // Link the main group to this page instead of an empty link. // This removes duplicate links such as the group "User" and page "User". $groups[$title]['href'] = $p->get('rewriteurl'); } else{ // The new grouped pages $groups[$group]['children'][ $title ] = $p; // And the flattened list to support legacy templates. $flatlist[ $title ] = $p; } } // This is a hack to make sure that users can view the /admin link if they can view other admin pages. /*if(sizeof($flatlist) && !isset($groups['Admin']['Dashboard'])){ $p = new PageModel('/admin'); $p->set('title', 'Dashboard'); $groups['Admin']['Dashboard'] = $p; }*/ } ksort($flatlist); ksort($groups); foreach($groups as $gname => $dat){ ksort($groups[$gname]['children']); } // Build a list of languages that can be set by the user. $locales = \Core\i18n\I18NLoader::GetLocalesEnabled(); $selected = \Core\i18n\I18NLoader::GetUsersLanguage(); $languages = []; if(sizeof($locales) > 1){ // There is at least 1 language available on the system, YAY! foreach($locales as $localeKey => $localeDat){ if(($pos = strpos($localeKey, '_')) !== false){ // This locale contains an underscore, that means it has a corresponding country! // These are what we want to display to the end user. $country = substr($localeKey, $pos+1); // Here I am retrieving the language and dialect in the native dialect if at all possible. // This is because if you as a user only can read your native language and your browser renders something different, // then you want to be able to read what you're switching it to. $str1 = new \Core\i18n\I18NString($localeDat['lang']); $str1->setLanguage($localeKey); $localeTitle = $str1->getTranslation(); if($localeDat['dialect']){ $str2 = new \Core\i18n\I18NString($localeDat['dialect']); $str2->setLanguage($localeKey); $localeTitle .= ' (' . $str2->getTranslation() . ')'; } $languages[] = [ 'key' => $localeKey, 'title' => $localeTitle, 'country' => $country, 'image' => 'assets/images/iso-country-flags/' . strtolower($country) . '.png', 'selected' => $localeKey == $selected, ]; } } } $v->templatename = 'widgets/adminmenu/view.tpl'; $v->assign('pages', $flatlist); $v->assign('groups', $groups); $v->assign('languages', $languages); return $v; }
/** * Set the site permissions to a given Form object. * * Used by the create and update pages. * * @param Form $form * @param UserGroupModel $model */ private function _setPermissionsToForm(Form $form, UserGroupModel $model){ // I want to split up the permission set into a set of groups, based on the first key. $groups = []; foreach(Core::GetPermissions() as $key => $data){ if($key{0} == '/'){ $group = substr($key, 1, strpos($key, '/', 1)-1); } else{ $group = 'general'; } if(!isset($groups[$group])){ $groups[$group] = []; } // NEW i18n support for config options! $i18nKey = \Core\i18n\I18NLoader::KeyifyString($key); //$opts['description'] = t('MESSAGE_PERM__' . $i18nKey); $groups[$group][$key] = t('STRING_PERMISSION_' . $i18nKey); } // Now, I can add these groups to the form. foreach($groups as $gkey => $options){ // Make the title a little more friendly. $gtitle = ucwords($gkey) . ' Permissions to Assign'; $form->addElement( 'checkboxes', array( 'group' => 'Permissions', 'id' => 'permissions-' . $gkey, 'name' => 'permissions', 'title' => $gtitle, 'options' => $options, 'value' => $model->getPermissions(), ) ); } }
/** * Page to view and test the i18n settings and strings of this site. * * Also useful for viewing what strings are currently installed and where they came from! * * @return int */ public function i18n(){ $view = $this->getView(); $request = $this->getPageRequest(); if(!\Core\user()->checkAccess('g:admin')){ // This test page is an admin-only utility. return View::ERROR_ACCESSDENIED; } /*$locales = Core\i18n\I18NLoader::GetLocalesAvailable(); // Languages will be the current languages/locales available on the system. $languages = []; foreach($locales as $lang => $dat){ if(strpos($lang, '_') !== false){ $base = substr($lang, 0, strpos($lang, '_')); if(!isset($languages[$base])){ // Add the base language, (useful here because the editor may want to edit only the base language and not specific dialects). $languages[$base] = t($dat['lang']); } } $languages[$lang] = t($dat['lang']) . (($dat['dialect']) ? ' (' . t($dat['dialect']) . ')' : ''); }*/ // I need to use GetLocalesAvailable because the higher level functions will only return what's currently enabled, // which is the entire point of this page! $locales = Core\i18n\I18NLoader::GetLocalesAvailable(); // Make this full list a more flat list suitable for populating directly into the form element. $all = []; foreach($locales as $key => $dat){ $all[$key] = t($dat['lang']) . ' (' . t($dat['dialect']) . ')'; } $enabled = \ConfigHandler::Get('/core/language/languages_enabled'); // This is expected to be a pipe-seperated list of languages/locales enabled. $enabled = array_map('trim', explode('|', $enabled)); // Did the user request a specific language? $requested = $request->getParameter('lang'); if($requested){ $showStrings = false; $showForm = true; } else{ $showStrings = true; $showForm = false; $requested = \Core\i18n\I18NLoader::GetUsersLanguage(); } $strings = \Core\i18n\I18NLoader::GetAllStrings($requested); $form = new Form(); $form->set('callsmethod', 'AdminController::_i18nSaveHandler'); $form->addElement( 'checkboxes', [ 'name' => 'languages[]', 'title' => t('STRING_CONFIG_CORE_LANGUAGE_LANGUAGES_ENABLED'), 'description' => t('MESSAGE_CONFIG_CORE_LANGUAGE_LANGUAGES_ENABLED'), 'options' => $all, 'value' => $enabled, ] ); /* $form->addElement('system', ['name' => 'lang', 'value' => $requested]); foreach($strings as $dat){ $type = strpos($dat['key'], 'MESSAGE_') === 0 ? 'textarea' : 'text'; $form->addElement( $type, [ 'name' => $dat['key'], 'title' => $dat['key'], 'value' => $dat['found'] ? $dat['match_str'] : '', 'description' => $dat['results']['DEFAULT'] ? $dat['results']['DEFAULT'] : $dat['results']['FALLBACK'], ] ); } */ $form->addElement('submit', ['value' => t('STRING_SAVE')]); $view->addBreadcrumb('t:STRING_ADMIN', '/admin'); $view->title = 't:STRING_I18N_LANGUAGES'; //$view->assign('languages', $languages); $view->assign('form', $form); $view->assign('strings', $strings); $view->assign('show_strings', $showStrings); $view->assign('show_form', $showForm); $view->assign('requested', $requested); }
/** * Get the breakdown of recorded events and their time into the profiler operation. * * @return string */ public function getEventTimesFormatted(){ $out = ''; foreach ($this->getEvents() as $t) { $in = round($t['timetotal'], 5) * 1000; $dcm = I18NLoader::GetLocaleConv('decimal_point'); if ($in == 0){ $time = '0000' . $dcm . '00 ms'; } else{ $parts = explode($dcm, $in); $whole = str_pad($parts[0], 4, 0, STR_PAD_LEFT); $dec = (isset($parts[1])) ? str_pad($parts[1], 2, 0, STR_PAD_RIGHT) : '00'; $time = $whole . $dcm . $dec . ' ms'; } $mem = '[mem: ' . \Core\Filestore\format_size($t['memory']) . '] '; $event = $t['event']; $out .= "[$time] $mem- $event" . "\n"; } return $out; }
/** * Fetch this view as an HTML string. * @return mixed|null|string */ public function fetch() { if($this->_fetchCache !== null){ // w00t ;) return $this->_fetchCache; } try{ $body = $this->fetchBody(); \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record( 'Fetched application content from within View->fetch() for ' . $this->templatename ); } catch(Exception $e){ $this->error = View::ERROR_SERVERERROR; \Core\ErrorManagement\exception_handler($e, ($this->mode == View::MODE_PAGE)); $body = ''; } // If there's no template, I have nothing to even do! if ($this->mastertemplate === false) { return $body; } // Else if it's null, it's just not set yet :p // @deprecated here! elseif ($this->mastertemplate === null) { $this->mastertemplate = ConfigHandler::Get('/theme/default_template'); } // Whee! //var_dump($this->templatename, Core\Templates\Template::ResolveFile($this->templatename)); // Content types take priority on controlling the master template. if ($this->contenttype == View::CTYPE_JSON) { $mastertpl = false; } else { // Master template depends on the render mode. switch ($this->mode) { case View::MODE_PAGEORAJAX: if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){ $mastertpl = false; $this->mode = View::MODE_AJAX; } else{ $mastertpl = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/skins/' . $this->mastertemplate; $this->mode = View::MODE_PAGE; } break; case View::MODE_NOOUTPUT: case View::MODE_AJAX: $mastertpl = false; break; case View::MODE_PAGE: case View::MODE_EMAILORPRINT: $mastertpl = Core\Templates\Template::ResolveFile('skins/' . $this->mastertemplate); //$mastertpl = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/skins/' . $this->mastertemplate; break; case View::MODE_WIDGET: $mastertpl = Core\Templates\Template::ResolveFile('widgetcontainers/' . $this->mastertemplate); break; } } // If there's *still* no template, I still have nothing to do. if (!$mastertpl) return $body; $template = \Core\Templates\Template::Factory($mastertpl); // Ensure that the template is linked to this View correctly. $template->setView($this); //$template = new Core\Templates\Template(); //$template->setBaseURL('/'); // Page-level views have some special variables. if ($this->mode == View::MODE_PAGE) { $template->assign('breadcrumbs', $this->getBreadcrumbs()); $template->assign('controls', $this->controls); $template->assign('messages', Core::GetMessages()); // Tack on the pre and post body variables from the current page. //$body = CurrentPage::GetBodyPre() . $body . CurrentPage::GetBodyPost(); } // Widgets need some special variables too. //if($this->mode == View::MODE_WIDGET){ // //var_dump($this->getVariable('widget')); die(); // $template->assign('widget', $this->getVariable('widget')); //} // This logic is needed for the SEO title, since that's usually completely human unfriendly. if(isset($this->meta['title']) && $this->meta['title']){ $template->assign('seotitle', $this->meta['title']); } else{ $template->assign('seotitle', $this->getTitle()); } $template->assign('title', $this->getTitle()); $template->assign('body', $body); // The body needs some custom classes for assisting the designers. // These are mainly pulled from the UA. $ua = \Core\UserAgent::Construct(); $this->bodyclasses = array_merge($this->bodyclasses, $ua->getPseudoIdentifier(true)); // Provide a way for stylesheets to target this page specifically. switch ($this->error) { case View::ERROR_BADREQUEST: case View::ERROR_PAYMENTREQUIRED: case View::ERROR_ACCESSDENIED: case View::ERROR_NOTFOUND: case View::ERROR_METHODNOTALLOWED: case View::ERROR_NOTACCEPTABLE: case View::ERROR_PROXYAUTHENTICATIONREQUIRED: case View::ERROR_REQUESTTIMEOUT: case View::ERROR_CONFLICT: case View::ERROR_GONE: case View::ERROR_LENGTHREQUIRED: case View::ERROR_PRECONDITIONFAILED: case View::ERROR_ENTITYTOOLARGE: case View::ERROR_URITOOLARGE: case View::ERROR_UNSUPPORTEDMEDIATYPE: case View::ERROR_RANGENOTSATISFIABLE: case View::ERROR_EXPECTATIONFAILED: case View::ERROR_UNAUTHORIZED: $url = 'error-' . $this->error; break; case 403: $url = "error-403 page-user-login"; break; default: $url = strtolower(trim(preg_replace('/[^a-z0-9\-]*/i', '', str_replace('/', '-', $this->baseurl)), '-')); } while($url != ''){ $this->bodyclasses[] = 'page-' . $url; $url = substr($url, 0, strrpos($url, '-')); } $bodyclasses = strtolower(implode(' ', $this->bodyclasses)); $template->assign('body_classes', $bodyclasses); try{ $data = $template->fetch(); } catch(SmartyException $e){ $this->error = View::ERROR_SERVERERROR; error_log('[view error]'); error_log('Template name: [' . $mastertpl . ']'); \Core\ErrorManagement\exception_handler($e); require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html'); die(); } catch(TemplateException $e){ $this->error = View::ERROR_SERVERERROR; error_log('[view error]'); error_log('Template name: [' . $mastertpl . ']'); \Core\ErrorManagement\exception_handler($e); require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html'); die(); } if($this->mode == View::MODE_EMAILORPRINT && $this->contenttype == View::CTYPE_HTML){ // Inform other elements that the page is just about to be rendered. HookHandler::DispatchHook('/core/page/rendering', $this); // Replace the </head> tag with the head data from the current page // and the </body> with the foot data from the current page. // This is needed to be done at this stage because some element in // the template after rendering may add additional script to the head. // Also tack on any attributes for the <html> tag. if(preg_match('#</head>#i', $data)){ // I need to do preg_replace because I only want to replace the FIRST instance of </head> $data = preg_replace('#</head>#i', $this->getHeadContent() . "\n" . '</head>', $data, 1); } } elseif ($this->mode == View::MODE_PAGE && $this->contenttype == View::CTYPE_HTML) { // Inform other elements that the page is just about to be rendered. HookHandler::DispatchHook('/core/page/rendering', $this); // Metadata! w00t // Replace the </head> tag with the head data from the current page // and the </body> with the foot data from the current page. // This is needed to be done at this stage because some element in // the template after rendering may add additional script to the head. // Also tack on any attributes for the <html> tag. if(preg_match('#</head>#i', $data)){ // I need to do preg_replace because I only want to replace the FIRST instance of </head> $data = preg_replace('#</head>#i', $this->getHeadContent() . "\n" . '</head>', $data, 1); } if(preg_match('#</body>#i', $data)){ // I need to use strrpos because I only want the LAST instance of </body> $match = strrpos($data, '</body>'); $foot = $this->getFootContent(); if(defined('ENABLE_XHPROF') && function_exists('xhprof_disable')){ require_once('xhprof_lib/utils/xhprof_lib.php'); #SKIPCOMPILER require_once('xhprof_lib/utils/xhprof_runs.php'); #SKIPCOMPILER $xhprof_data = xhprof_disable(); $namespace = trim(str_replace(['.', '/'], '-', HOST . REL_REQUEST_PATH), '-'); $xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, $namespace); define('XHPROF_RUN', $run_id); define('XHPROF_SOURCE', $namespace); $xhprof_link = sprintf( '<a href="' . SERVERNAME . '/xhprof/index.php?run=%s&source=%s" target="_blank">View XHprof Profiler Report</a>' . "\n", $run_id, $namespace ); } else{ $xhprof_link = ''; } // If the viewmode is regular and DEVELOPMENT_MODE is enabled, show some possibly useful information now that everything's said and done. if (DEVELOPMENT_MODE) { $legend = '<div class="fieldset-title">%s<i class="icon-chevron-down expandable-hint"></i><i class="icon-chevron-up collapsible-hint"></i></div>' . "\n"; $debug = ''; $debug .= '<pre class="xdebug-var-dump screen">'; $debug .= '<fieldset class="debug-section collapsible" id="debug-section-template-information">'; $debug .= sprintf($legend, 'Template Information'); $debug .= "<span>"; $debug .= 'Base URL: ' . $this->baseurl . "\n"; $debug .= 'Template Requested: ' . $this->templatename . "\n"; $debug .= 'Template Actually Used: ' . \Core\Templates\Template::ResolveFile($this->templatename) . "\n"; $debug .= 'Master Skin: ' . $this->mastertemplate . "\n"; $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible" id="debug-section-performance-information">'; $debug .= sprintf($legend, 'Performance Information'); $debug .= "<span>"; $debug .= $xhprof_link; $debug .= "Database Reads: " . \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler()->readCount() . "\n"; $debug .= "Database Writes: " . \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler()->writeCount() . "\n"; //$debug .= "Number of queries: " . DB::Singleton()->counter . "\n"; //$debug .= "Amount of memory used by PHP: " . \Core\Filestore\format_size(memory_get_usage()) . "\n"; $debug .= "Amount of memory used by PHP: " . \Core\Filestore\format_size(memory_get_peak_usage(true)) . "\n"; $profiler = Core\Utilities\Profiler\Profiler::GetDefaultProfiler(); $debug .= "Total processing time: " . $profiler->getTimeFormatted() . "\n"; $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible" id="debug-section-profiler-information">'; $debug .= sprintf($legend, 'Core Profiler'); $debug .= "<span>"; $debug .= $profiler->getEventTimesFormatted(); $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-components-information">'; // Tack on what components are currently installed. $debug .= sprintf($legend, 'Available Components'); $debugcomponents = array_merge(Core::GetComponents(), Core::GetDisabledComponents()); $debug .= "<span>"; // Give me sorting! ksort($debugcomponents); foreach ($debugcomponents as $l => $v) { if($v->isEnabled() && $v->isReady()){ $debug .= '[<span style="color:green;">Enabled</span>]'; } elseif($v->isEnabled() && !$v->isReady()){ $debug .= '[<span style="color:red;">!ERROR!</span>]'; } else{ $debug .= '[<span style="color:red;">Disabled</span>]'; } $debug .= $v->getName() . ' ' . $v->getVersion() . "<br/>"; } $debug .= "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-hooks-information">'; // I wanna see what hooks are registered too! $debug .= sprintf($legend, 'Registered Hooks'); foreach(HookHandler::GetAllHooks() as $hook){ $debug .= "<span>"; /** @var $hook Hook */ $debug .= $hook->name; if($hook->description) $debug .= ' <em> - ' . $hook->description . '</em>'; $debug .= "\n" . '<span style="color:#999;">Return expected: ' . $hook->returnType . '</span>'; $debug .= "\n" . '<span style="color:#999;">Attached by ' . $hook->getBindingCount() . ' binding(s).</span>'; foreach($hook->getBindings() as $b){ $debug .= "\n" . ' * ' . $b['call']; } $debug .= "\n\n"; $debug .= "</span>"; } $debug .= '</fieldset>'; // Display the licensed content on this application $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-licenser-information">'; $debug .= sprintf($legend, 'Licensed Information'); $lic = \Core\Licenser::GetRaw(); $debug .= '<div>'; foreach($lic as $dat){ $debug .= $dat['url'] . '::' . $dat['feature'] . ' => ' . $dat['value'] . "\n"; } $debug .= '</div></fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-includes-information">'; // I want to see how many files were included. $debug .= sprintf($legend, 'Included Files'); $debug .= '<span>Number: ' . sizeof(get_included_files()) . "</span>"; $debug .= '<span>'. implode("<br/>", get_included_files()) . "</span>"; $debug .= '</fieldset>'; $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-query-information">'; $debug .= sprintf($legend, 'Query Log'); $profiler = \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler(); $debug .= '<div>' . $profiler->getEventTimesFormatted() . '</div>'; $debug .= '</fieldset>'; // Display all the i18n strings available on the system. $debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-i18nstrings-information">'; $debug .= sprintf($legend, 'I18N Strings Available'); $strings = \Core\i18n\I18NLoader::GetAllStrings(); $debug .= '<ul>'; foreach($strings as &$s){ $debug .= '<li>' . $s['key'] . '</li>'; } $debug .= '</ul>'; $debug .= '</fieldset>'; $debug .= '</pre>'; // And append! $foot .= "\n" . $debug; } $data = substr_replace($data, $foot . "\n" . '</body>', $match, 7); } $data = preg_replace('#<html#', '<html ' . $this->getHTMLAttributes(), $data, 1); // This logic has been migrated to the {$body_classes} variable. /* if(preg_match('/<body[^>]*>/', $data, $matches)){ // body is $matches[0]. $fullbody = $matches[0]; if($fullbody == '<body>'){ $body = '<body class="' . $bodyclass . '">'; } elseif(strpos($fullbody, 'class=') === false){ // Almost as easy, other elements but no class. $body = substr($fullbody, 0, -1) . ' class="' . $bodyclass . '">'; } else{ // parsing HTML is far easier with XML objects. $node = new SimpleXMLElement($fullbody . '</body>'); $body = '<body'; foreach($node->attributes() as $k => $v){ if($k == 'class'){ $body .= ' ' . $k . '="' . $bodyclass . ' ' . $v . '"'; } else{ $body .= ' ' . $k . '="' . $v . '"'; } } $body .= '>'; } // And replace! $data = preg_replace('#<body[^>]*>#', $body, $data, 1); } */ } $this->_fetchCache = $data; return $data; }
public function getFormAttributes(){ $opts = []; $formOptions = $this->get('form_attributes'); if($formOptions != ''){ // Explode them by a semicolon $formOptions = array_map('trim', explode(';', $formOptions)); foreach($formOptions as $o){ if(($cpos = strpos($o, ':')) !== false){ $k = substr($o, 0, $cpos); $v = substr($o, $cpos+1); $opts[$k] = $v; } } } if(!isset($opts['type'])){ // Determine this automatically by the config data type. switch ($this->get('type')) { case 'string': case 'int': $opts['type'] = 'text'; break; case 'text': $opts['type'] = 'textarea'; break; case 'enum': $opts['type'] = 'select'; break; case 'boolean': $opts['type'] = 'radio'; break; case 'set': $opts['type'] ='checkboxes'; break; default: $opts['type'] = 'text'; break; } } // SELECT if(($opts['type'] == 'select' || $opts['type'] == 'checkboxes') && trim($this->get('options'))){ // This is set from the main option set. $opts['options'] = array_map('trim', explode('|', $this->get('options'))); } // RADIO if($opts['type'] == 'radio'){ $opts['options'] = ['false' => t('STRING_NO'), 'true' => t('STRING_YES')]; } $key = $this->get('key'); $gname = substr($key, 1); $gname = ucwords(substr($gname, 0, strpos($gname, '/'))); // NEW i18n support for config options! $i18nKey = \Core\i18n\I18NLoader::KeyifyString($key); $opts['title'] = t('STRING_CONFIG_' . $i18nKey); $opts['description'] = t('MESSAGE_CONFIG_' . $i18nKey); // Generate the title dynamically from either the title attribute or the key attribute. if(!isset($opts['title'])){ // If the title is set, use that. Otherwise pull it from the key name less the group. if($this->get('title')){ $opts['title'] = $this->get('title'); } else{ $title = substr($key, strlen($gname) + 2); // Split the title on '/' and capitalize it to make it more user-friendly. $title = str_replace('/', ' ', $title); // Same thing for underscores '_', remove them and capitalize the words. $title = str_replace('_', ' ', $title); $title = ucwords($title); $opts['title'] = $title; } } // Description can be set dynamically or pulled from the attributes. if(!isset($opts['description'])){ $desc = $this->get('description'); if ($this->get('default_value') && $desc){ $desc .= ' (' . t('MESSAGE_DEFAULT_VALUE_IS_S_', $this->get('default_value')) . ')'; } elseif($this->get('default_value')) { $desc = t('MESSAGE_DEFAULT_VALUE_IS_S_', $this->get('default_value')); } $opts['description'] = $desc; } if(!isset($opts['group'])){ $opts['group'] = $gname; } // The name can't be set by the XML metadata, but it is based on the type of form element, slightly. if($opts['type'] == 'checkboxes'){ // Append "[]" to the name as there are many checkboxes! $opts['name'] = 'config[' . $key . '][]'; } else{ $opts['name'] = 'config[' . $key . ']'; } return $opts; }