/** * @return null|int */ public function pageinsertables_update(){ $request = $this->getPageRequest(); $view = $this->getView(); $view->mode = View::MODE_AJAX; $view->contenttype = View::CTYPE_JSON; $view->record = false; // This is an ajax-only request. if(!$request->isAjax()){ return View::ERROR_BADREQUEST; } $formid = $request->getPost('___formid'); if(!$formid){ return View::ERROR_NOTFOUND; } // Lookup that form! if(\Core\Session::Get('FormData/' . $formid) === null){ return View::ERROR_NOTFOUND; } /** @var $form Form */ $form = unserialize(\Core\Session::Get('FormData/' . $formid)); if(!$form){ return View::ERROR_NOTFOUND; } // Run though each element submitted and try to validate it. if (strtoupper($form->get('method')) == 'POST') $src =& $_POST; else $src =& $_GET; $form->loadFrom($src, true); // Now that the form has been loaded with the data, reinitialize the page's insertable elements. foreach($form->getModels() as $prefix => $model){ if($model instanceof PageModel && $form->getElement($prefix . '[page_template]')){ $pagetemplate = $form->getElement($prefix . '[page_template]'); // Get all insertables currently present and remove them from the form. // (They will be added back shortly) foreach($form->getElements(true, false) as $el){ $name = $el->get('name'); if(strpos($name, $prefix . '[insertables]') === 0){ $form->removeElement($name); } } // Now that the previous insertables are removed, update the value on the model and add the new insertables. // This block of logic is required because the template systems look at the last template set in the database. // Since what's in the databse isn't what we want here, we need to spoof it so the correct template is // used for retrieving form elements. $model->set('page_template', $pagetemplate->get('value')); // Set the last_template so that the traditional queries to getTemplate work without reverting back to the default template. $t = $model->getBaseTemplateName(); // Allow the specific template to be overridden. if (($override = $model->get('page_template'))){ $t = substr($t, 0, -4) . '/' . $override; $model->set('last_template', $t); } else{ $model->set('last_template', null); } $tpl = Core\Templates\Template::Factory($model->getTemplateName()); if($tpl){ // My counter for which element was added last... I need this because I have "addElementAfter"... // so if I just kept adding the stack after a single element, they'd be in reverse order. // ie: stack: [a, b, c] -> {ref_el}, c, b, a $lastelementadded = $pagetemplate; $insertables = $tpl->getInsertables(); foreach($insertables as $key => $dat){ $type = $dat['type']; $dat['name'] = $prefix . '[insertables][' . $key . ']'; // This insertable may already have content from the database... if so I want to pull that! $i = InsertableModel::Construct($model->get('baseurl'), $key); if ($i->get('value') !== null){ $dat['value'] = $i->get('value'); } $dat['class'] = 'insertable'; $insertableelement = FormElement::Factory($type, $dat); $form->addElementAfter($insertableelement, $lastelementadded); $lastelementadded = $insertableelement; } } // Since there are new elements here, there may be old values that correspond to the new elements too. $form->loadFrom($src, true); // Don't forget to re-save these form updates back to the session! $form->persistent = true; $form->saveToSession(); $view->jsondata = array( 'status' => '1', 'message' => 'Switched templatename successfully', 'formid' => $form->get('uniqueid'), ); return null; } // if($model instanceof PageModel && $form->getElement($prefix . '[page_template]')) } // foreach($form->getModels() as $prefix => $model) // Ummmm..... $view->jsondata = array( 'status' => '0', 'message' => 'No page found :/', 'formid' => null, ); }
public function setTemplateName($templatename){ $prefix = $this->get('name'); if($templatename === null) $templatename = ''; // Reset back to default. // First of all, check and see if this is already set. // This will work initially because the initial value is null, and the incoming string will be "". if($this->_selector->get('value') === $templatename) return; $this->_selector->set('value', $templatename); // Ok, it's not.... guess I should remove any existing elements then. foreach($this->_elements as $k => $el){ if($el == $this->_selector) continue; // I suppose I shouldn't remove the selector itself... unset($this->_elements[$k]); } if($templatename){ // Don't forget to prepend the base template! $templatename = substr($this->_selector->get('templatename'), 0, -4) . '/' . $templatename; } else{ // Default! I still need to transpose "" to the default template afterall. $templatename = $this->_selector->get('templatename'); } // Translate the filename to an absolute path. $tpl = Core\Templates\Template::ResolveFile($templatename); if (!$tpl) return null; // Scan through $tpl and find any {insertable} tag. $tplcontents = file_get_contents($tpl); preg_match_all('/\{insertable(.*)\}(.*)\{\/insertable\}/isU', $tplcontents, $matches); // Guess this page had no insertables. if (!sizeof($matches[0])){ return; } foreach ($matches[0] as $k => $v) { // The contents of the {insertable ...} tag. $tag = trim($matches[1][$k]); // The contents inside of the tags. $content = trim($matches[2][$k]); $default = $content; // To make this tag searchable easily, convert it to an xml element and get the attributes from that. $simple = new SimpleXMLElement('<insertable ' . $tag . '/>'); $attributes = array(); foreach($simple->attributes() as $k => $v){ $attributes[$k] = (string)$v; } $name = $attributes['name']; $title = isset($attributes['title']) ? $attributes['title'] : $name; $type = isset($attributes['type']) ? $attributes['type'] : null; // null means an automatic type. if(isset($attributes['default'])) $default = $attributes['default']; // This insertable may already have content from the database... if so I want to pull that! $i = new InsertableModel($this->get('baseurl'), $name); if ($i->get('value') !== null) $content = $i->get('value'); // These will be the default options for creating form elements, extend them as necessary. $elementoptions = array( 'name' => $prefix . "[$name]", 'title' => $title, 'value' => $content, ); if(isset($attributes['description'])) $elementoptions['description'] = $attributes['description']; // If the type is null, try to determine the form type based on the content. if($type === null){ if (strpos($default, "\n") === false && strpos($default, "<") === false) { $type = 'text'; } elseif (preg_match('/<img(.*?)>/i', $default)) { $type = 'image'; } else { $type = 'wysiwyg'; } } // Some elements have specific options that need to be set. switch($type){ case 'image': $type = 'file'; $elementoptions['accept'] = 'image/*'; $elementoptions['basedir'] = 'public/insertable'; break; case 'file': $elementoptions['basedir'] = 'public/insertable'; break; case 'select': $elementoptions['options'] = array_map('trim', explode('|', $attributes['options'])); break; } // Add the actual elements now! $this->addElement($type, $elementoptions); } }
/** * View to display a list of currently installed themes, their templates, and be able to manage * their templates and set them as default. * * @todo Implement an Add/Upload Theme link on this page. */ public function index2() { $view = $this->getView(); $default = ConfigHandler::Get('/theme/selected'); $themes = array(); $dir = ROOT_PDIR . 'themes'; $dh = opendir($dir); if ($dh) { while (($file = readdir($dh)) !== false) { if ($file[0] == '.') { continue; } if (!is_dir($dir . '/' . $file)) { continue; } // Load up the templates for this theme. $templates = ThemeHandler::GetTheme($file)->getTemplates(); $themes[] = array('name' => $file, 'default' => $default == $file, 'templates' => $templates); } closedir($dh); } // Get the page templates that have widgetareas defined within. $components = Core::GetComponents(); $pagetemplates = array(); foreach ($components as $c) { /** @var $c Component_2_1 */ $dir = $c->getViewSearchDir(); if (!$dir) { continue; } $dirlen = strlen($dir); $component = $c->getName(); $dh = \Core\Filestore\Factory::Directory($dir); $pagetplfiles = $dh->ls('tpl', true); // not sure why getFilename(path) isn't working as expected, but this works too. foreach ($pagetplfiles as $obj) { /** @var $obj \Core\Filestore\File */ $file = substr($obj->getFilename(), $dirlen); // Since this is a template, it may actually be in a different location than where the package maintainer put it. // ie: user template user/templates/pages/user/view.tpl may be installed to themes/myawesometheme/pages/user/view.tpl instead. $resolved = Core\Templates\Template::ResolveFile($file); $newobj = \Core\Filestore\Factory::File($resolved); // Check the contents of the file and see if there is a {widgetarea...} here. $contents = $newobj->getContents(); if (strpos($contents, '{widgetarea') !== false) { $haswidgets = true; } else { $haswidgets = false; } $pagetemplates[] = array('file' => $file, 'resolved' => $resolved, 'obj' => $newobj, 'haswidgets' => $haswidgets, 'component' => $component); } } // The CSS files for the current theme and every component. // This is keyed by the filename so that duplicate entries don't show up more than once, // ie: if an asset exists in both the component and the theme. $cssfiles = array(); // Give me the current theme! $dir = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/assets'; $dirlen = strlen($dir); $component = 'Theme/' . ConfigHandler::Get('/theme/selected'); $dh = \Core\Filestore\Factory::Directory($dir); $cssls = $dh->ls('css', true); foreach ($cssls as $obj) { /** @var $obj \Core\Filestore\Backends\FileLocal */ $file = 'assets' . substr($obj->getFilename(), $dirlen); // Since this is a template, it may actually be in a different location than where the package maintainer put it. // ie: user template user/templates/pages/user/view.tpl may be installed to themes/myawesometheme/pages/user/view.tpl instead. $newobj = \Core\Filestore\Factory::File($file); $cssfiles[$file] = array('file' => $file, 'obj' => $newobj, 'component' => $component); } // And the rest of the components... I suppose foreach ($components as $c) { // Now, give me all this component's CSS files! $dir = $c->getAssetDir(); if (!$dir) { continue; } $dirlen = strlen($dir); $component = $c->getName(); $dh = \Core\Filestore\Factory::Directory($dir); $cssls = $dh->ls('css', true); // not sure why getFilename(path) isn't working as expected, but this works too. foreach ($cssls as $obj) { /** @var $obj \Core\Filestore\Backends\FileLocal */ $file = 'assets' . substr($obj->getFilename(), $dirlen); // Since this is a template, it may actually be in a different location than where the package maintainer put it. // ie: user template user/templates/pages/user/view.tpl may be installed to themes/myawesometheme/pages/user/view.tpl instead. $newobj = \Core\Filestore\Factory::File($file); $cssfiles[$file] = array('file' => $file, 'obj' => $newobj, 'component' => $component); } } $view->assign('pages', $pagetemplates); $view->assign('css', $cssfiles); $view->assign('themes', $themes); $view->title = 'Theme Manager'; }
/** * @todo Finish documentation of smarty_function_widgetarea * @param array $params Associative (and/or indexed) array of smarty parameters passed in from the template * @param Smarty_Internal_Template $smarty Parent Smarty template object * * @return string|void */ function smarty_function_widgetarea($params, $smarty) { // Get all widgets set to load in this area. $body = ''; $baseurl = PageRequest::GetSystemRequest()->getBaseURL(); $template = $smarty->template_resource; $tmpl = $smarty->getTemplateVars('__core_template'); $topview = ($tmpl instanceof \Core\Templates\TemplateInterface) ? $tmpl->getView() : \Core\view(); $parameters = []; $name = null; $installable = null; $assign = null; foreach($params as $k => $v){ switch($k){ case 'name': $name = $v; break; case 'installable': $installable = $v; break; case 'assign': $assign = $v; break; default: $parameters[$k] = $v; break; } } // I need to resolve the page template down to the base version in order for the lookup to work. foreach(Core\Templates\Template::GetPaths() as $base){ if(strpos($template, $base) === 0){ $template = substr($template, strlen($base)); break; } } // Given support for page-level widgets, this logic gets slightly more difficult... $factory = new ModelFactory('WidgetInstanceModel'); $factory->order('weight'); if(Core::IsComponentAvailable('multisite') && MultiSiteHelper::IsEnabled()){ $factory->whereGroup('or', ['site = -1', 'site = ' . MultiSiteHelper::GetCurrentSiteID()]); } $subwhere = new Core\Datamodel\DatasetWhereClause(); $subwhere->setSeparator('OR'); // First, the skin-level where clause. $skinwhere = new Core\Datamodel\DatasetWhereClause(); $skinwhere->setSeparator('AND'); $skinwhere->addWhere('template = ' . $template); $skinwhere->addWhere('widgetarea = ' . $name); $subwhere->addWhere($skinwhere); // And second, the page-level where clause. if($baseurl){ $pagewhere = new Core\Datamodel\DatasetWhereClause(); $pagewhere->setSeparator('AND'); $pagewhere->addWhere('page_baseurl = ' . $baseurl); $pagewhere->addWhere('widgetarea = ' . $name); $subwhere->addWhere($pagewhere); } $factory->where($subwhere); $widgetcount = 0; try{ $widgets = $factory->get(); } catch(Exception $e){ if(DEVELOPMENT_MODE){ $body .= '<p class="message-error">Exception while trying to load widget area ' . $name . '!</p>'; $body .= '<pre class="xdebug-var-dump">' . $e->getMessage() . '</pre>'; } else{ \Core\ErrorManagement\exception_handler($e, false); } $widgets = []; ++$widgetcount; } foreach ($widgets as $wi) { /** @var $wi WidgetInstanceModel */ // User cannot access this widget? Don't display it... if(!\Core\user()){ continue; } if (!\Core\user()->checkAccess($wi->get('access'))){ continue; } if($installable){ $wi->set('installable', $installable); } $view = $wi->execute($parameters); // Some widgets may return simply a blank string. Those should just be ignored. if ($view == ''){ continue; } // If it's just a string, return that. if (is_string($view)) { $contents = $view; } elseif($view->error == View::ERROR_NOERROR){ // Ensure that the widget's View knows it's linked to a parent! $view->parent = $topview; $contents = $view->fetch(); } else{ $contents = 'Error displaying widget [' . $wi->get('baseurl') . '], returned error [' . $view->error . ']'; } ++$widgetcount; // Does this widget have controls attached to it? $widget = $wi->getWidget(); if($widget->controls instanceof ViewControls && $widget->controls->hasLinks()){ $contents = '<div class="widget-controls-wrapper">' . '<menu id="widget-controls-' . $wi->get('id') . '">' . $widget->controls->fetch() . '</menu>' . '</div>' . $contents; } $body .= '<div class="widget">' . $contents . '</div>'; } // Do some sanitizing for the css data $class = 'widgetarea-' . strtolower(str_replace(' ', '', $name)); $html = '<div class="widgetarea ' . $class . '" widgetarea="' . $name . '">' . $body . '</div>'; // No widgets, no inner content! if($widgetcount == 0){ $html = ''; } if($assign){ $smarty->assign($assign, $html); } else{ return $html; } }
/** * Display a listing of all widgets registered in the system. */ public function admin(){ $view = $this->getView(); $request = $this->getPageRequest(); $viewer = \Core\user()->checkAccess('p:/core/widgets/manage'); $manager = \Core\user()->checkAccess('p:/core/widgets/manage'); if(!($viewer || $manager)){ return View::ERROR_ACCESSDENIED; } // Build a list of create pages for all registered components. $components = Core::GetComponents(); $pages = []; $skins = []; $selected = null; $selectedtype = null; $baseurl = null; $selectoptions = []; $links = []; $theme = ThemeHandler::GetTheme(); $formtheme = null; $formskin = null; $formtemplate = null; foreach($components as $c){ /** @var Component_2_1 $c */ $viewdir = $c->getViewSearchDir(); if($viewdir){ $dirlen = strlen($viewdir); $component = $c->getName(); $dh = \Core\Filestore\Factory::Directory($viewdir); //$pagetplfiles = $dh->ls('tpl', true); $pagetplfiles = $dh->ls(null, true); // not sure why getFilename(path) isn't working as expected, but this works too. foreach($pagetplfiles as $obj){ // I don't want directories. if($obj instanceof \Core\Filestore\Directory) continue; /** @var $obj \Core\Filestore\File */ $file = substr($obj->getFilename(), $dirlen); // Since this is a template, it may actually be in a different location than where the package maintainer put it. // ie: user template user/templates/pages/user/view.tpl may be installed to themes/myawesometheme/pages/user/view.tpl instead. $tpl = Core\Templates\Template::Factory($file); if($tpl->hasWidgetAreas()){ $pagetitle = $file; if(strpos($pagetitle, 'pages/') === 0){ $pagetitle = substr($pagetitle, 6); } // Replace directory slashes with a space $pagetitle = str_replace(['/', '-'], ' ', $pagetitle); // Capitalize them $pagetitle = ucwords($pagetitle); // And trim off the ".tpl" suffix. $pagetitle = substr($pagetitle, 0, -4); $pages[$file] = $pagetitle; } } } foreach($c->getXML()->getElements('/widgets/widgetcreate') as $node){ /** @var DOMElement $node */ if($node->getAttribute('baseurl')){ $nodebaseurl = $node->getAttribute('baseurl'); $image = ''; } elseif($node->getAttribute('class')){ /** @var Widget_2_1 $obj */ $obj = Widget_2_1::Factory($node->getAttribute('class')); $nodebaseurl = '/widget/create?class=' . $node->getAttribute('class'); if($obj){ $image = $obj->getPreviewImage(); } else{ \Core\set_message('Invalid "widgetcreate" found in ' .$node->getAttribute('class') . ', ' . $node->getAttribute('title'), 'error'); $image = ''; } } else{ \Core\set_message('Invalid "widgetcreate" found in ' . $c->getName() . ', ' . $node->getAttribute('title'), 'error'); continue; } $links[] = [ 'baseurl' => $nodebaseurl, 'title' => $node->getAttribute('title'), 'preview' => $image, ]; } } // Build the array of skins for the current theme $themeskins = $theme->getSkins(); $defaultskin = null; foreach($themeskins as $dat){ $skins[ 'skins/' . $dat['file'] ] = $dat['title']; if($dat['default']){ $defaultskin = 'skins/' . $dat['file']; } } // Now that the various templates have been loaded into a flat array, I need to sort them. asort($pages); asort($skins); foreach($skins as $k => $v){ $selectoptions[ $k ] = 'Skin: ' . $v; } foreach($pages as $k => $v){ $selectoptions[ $k ] = 'Page: ' . $v; } if($request->getParameter('baseurl')){ // It's a URL-specific request, lookup which template that page used last. $baseurl = $request->getParameter('baseurl'); $page = PageModel::Construct($baseurl); if(!isset($pages[ $page->get('last_template') ])){ \Core\set_message('Requested page template does not seem to contain any widget areas.', 'error'); \Core\go_back(); } $selected = $page->get('last_template'); $selectedtype = 'url'; $formtemplate = $selected; } elseif($request->getParameter('template')){ $selected = $request->getParameter('template'); if(isset($pages[ $selected ])){ $selectedtype = 'page'; $formtemplate = $selected; } else{ $selectedtype = 'skin'; $formtheme = $theme->getKeyName(); $formskin = $selected; } } else{ // Just use the default theme skin. $selected = $defaultskin; $selectedtype = 'skin';$formtheme = $theme->getKeyName(); $formskin = $selected; } $template = \Core\Templates\Template::Factory($selected); $areas = $template->getWidgetAreas(); $installables = [0 => '']; foreach($areas as $k => $dat){ // Ensure that each area has a widgets array, (even if it's empty) $areas[$k]['widgets'] = []; $installables[] = $dat['installable']; } $installables = array_unique($installables); $factory = new ModelFactory('WidgetInstanceModel'); $factory->order('weight'); if(Core::IsComponentAvailable('multisite') && MultiSiteHelper::IsEnabled()){ $factory->whereGroup('or', ['site = -1', 'site = ' . MultiSiteHelper::GetCurrentSiteID()]); } if($selectedtype == 'skin'){ // First, the skin-level where clause. $skinwhere = new Core\Datamodel\DatasetWhereClause(); $skinwhere->setSeparator('AND'); //$skinwhere->addWhere('theme = ' . $theme->getKeyName()); $skinwhere->addWhere('template = ' . $selected); $factory->where($skinwhere); } elseif($selectedtype == 'page'){ $factory->where('template = ' . $selected); } elseif($selectedtype == 'url'){ $factory->where('page_baseurl = ' . $baseurl); } else{ \Core\set_message('Invalid/unknown template type', 'error'); \Core\go_back(); } foreach($factory->get() as $wi){ /** @var $wi WidgetInstanceModel */ $a = $wi->get('widgetarea'); $areas[$a]['widgets'][] = $wi; } $available = WidgetModel::Find(['installable IN ' . implode(', ', $installables)]); /* $table = new Core\ListingTable\Table(); $table->setName('/admin/widgets'); $table->setModelName('WidgetModel'); // Add in all the columns for this listing table. $table->addColumn('Title', 'title'); if(Core::IsComponentAvailable('enterprise') && MultiSiteHelper::IsEnabled() && \Core\user()->checkAccess('g:admin')){ $table->addColumn('Site', 'site', false); $ms = true; } else{ $ms = false; } $table->getModelFactory()->where('installable IN ' . implode(', ', $installables)); $table->addColumn('Base URL', 'baseurl'); $table->addColumn('Installable', 'installable'); $table->addColumn('Created', 'created'); $table->loadFiltersFromRequest(); */ $view->mastertemplate = 'admin'; $view->title = 'All Widgets'; //$view->assign('table', $table); $view->assign('available_widgets', $available); $view->assign('links', $links); $view->assign('manager', $manager); $view->assign('theme', $formtheme); $view->assign('skin', $formskin); $view->assign('template', $selected); $view->assign('page_template', $formtemplate); $view->assign('page_baseurl', $baseurl); $view->assign('options', $selectoptions); $view->assign('selected', $selected); $view->assign('areas', $areas); //$view->assign('multisite', $ms); }
/** * 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; }