/** * Page to display the currently installed themes and shortcuts to various operations therein. */ public function index() { $view = $this->getView(); $selected = ConfigHandler::Get('/theme/selected'); $themes = ThemeHandler::GetAllThemes(); $current = ThemeHandler::GetTheme($selected); // Set to true if multisite is enabled AND the page is currently on a child site. $multisite = Core::IsLibraryAvailable('multisite') && MultiSiteHelper::IsEnabled() && MultiSiteHelper::GetCurrentSiteID() != 0; $configDefault = ConfigHandler::GetConfig('/theme/default_template'); $configSelected = ConfigHandler::GetConfig('/theme/selected'); $configEmailDefault = ConfigHandler::GetConfig('/theme/default_email_template'); // Only allow changing the theme if it's on the root site OR both config options are overrideable. $themeSelectionEnabled = !$multisite || $configDefault->get('overrideable') && $configSelected->get('overrideable'); $emailSelectionEnabled = !$multisite || $configEmailDefault->get('overrideable'); $configOptions = $current->getConfigs(); if (!sizeof($configOptions)) { $optionForm = null; } else { $optionForm = new Form(); $optionForm->set('callsmethod', 'AdminController::_ConfigSubmit'); foreach ($configOptions as $c) { /** @var $c ConfigModel */ if ($multisite) { // Only pull the config options that are enabled for this specific site. if ($c->get('overrideable')) { $optionForm->addElement($c->getAsFormElement()); } } else { // Sites that either // do NOT have multisite installed // nor have multisite enabled // or on the root site, get all options. $optionForm->addElement($c->getAsFormElement()); } } if (sizeof($optionForm->getElements()) > 0) { // There is at least one element in the option forms! $optionForm->addElement('submit', ['value' => 'Save Configurable Options']); } else { // Reset the form back to null so that the section doesn't display. $optionForm = null; } } // The source objects to look for assets in. // Set initially to all the installed components. $assetsources = Core::GetComponents(); // And add on the current theme. $assetsources[] = $current; // Load in all asset files available from the installed components and current theme. // these are assembled into a virtual directory listing. $assets = array(); // Give me the current theme! foreach ($assetsources as $source) { /** @var Component_2_1 $source */ $dir = $source->getAssetDir(); if (!$dir) { continue; } $dirlen = strlen($dir); $name = $source->getName(); $dh = \Core\Filestore\Factory::Directory($dir); $ls = $dh->ls(null, true); foreach ($ls as $obj) { // Skip directories. if (!$obj instanceof \Core\Filestore\File) { continue; } /** @var $obj \Core\Filestore\File */ $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); $assets[$file] = array('file' => $file, 'obj' => $newobj, 'component' => $name); } } // Now that the asset files have been loaded into a flat array, I need to convert that to the properly nested version. ksort($assets); $nestedassets = array(); foreach ($assets as $k => $obj) { $parts = explode('/', $k); $lastkey = sizeof($parts) - 1; $thistarget =& $nestedassets; foreach ($parts as $i => $bit) { if ($i == $lastkey) { $thistarget[$bit] = $obj; } else { if (!isset($thistarget[$bit])) { $thistarget[$bit] = []; } $thistarget =& $thistarget[$bit]; } } } // Get the templates throughout the site. These can include pages, emails, form elements, etc. $components = Core::GetComponents(); $templates = 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); $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); $resolved = Core\Templates\Template::ResolveFile($file); $newobj = \Core\Filestore\Factory::File($resolved); $templates[$file] = array('file' => $file, 'resolved' => $resolved, 'obj' => $newobj, 'haswidgets' => $tpl->hasWidgetAreas(), 'component' => $component, 'has_stylesheets' => $tpl->hasOptionalStylesheets()); } } // Now that the template files have been loaded into a flat array, I need to convert that to the properly nested version. ksort($templates); $nestedtemplates = array(); foreach ($templates as $k => $obj) { $parts = explode('/', $k); $lastkey = sizeof($parts) - 1; $thistarget =& $nestedtemplates; foreach ($parts as $i => $bit) { if ($i == $lastkey) { $thistarget[$bit] = $obj; } else { if (!isset($thistarget[$bit])) { $thistarget[$bit] = []; } $thistarget =& $thistarget[$bit]; } } } $siteskinform = new Form(); $siteskinform->set('callsmethod', 'ThemeController::SaveSiteSkins'); $opts = ['' => '-- Public Default --']; foreach ($current->getSkins() as $skin) { $opts[$skin['file']] = $skin['title']; } foreach (ConfigHandler::FindConfigs('/theme/siteskin/') as $k => $config) { $siteskinform->addElement('select', ['name' => 'config[' . $k . ']', 'title' => $config->get('description'), 'value' => $config->getValue(), 'options' => $opts]); } $siteskinform->addElement('submit', ['value' => t('STRING_SAVE')]); $customdest = \Core\directory('themes/custom'); $cssform = false; $cssprintform = false; if ($customdest->isWritable()) { $sets = [['file' => 'css/custom.css', 'form' => null], ['file' => 'css/custom_print.css', 'form' => null]]; foreach ($sets as $k => $set) { // Load the editor for the custom CSS file, as this is a very common thing to do! $file = $set['file']; // And try to look up and find this damn file... $srcdirs = array(); $srcdirs[] = ROOT_PDIR . 'themes/custom/assets/'; $srcdirs[] = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/assets/'; foreach (Core::GetComponents() as $c) { if ($c->getAssetDir()) { $srcdirs[] = $c->getAssetDir(); } } foreach ($srcdirs as $dir) { if (file_exists($dir . $file)) { $file = $dir . $file; break; } } $fh = \Core\Filestore\Factory::File($file); $content = $fh->getContents(); $m = new ThemeTemplateChangeModel(); $m->set('content', $content); $m->set('filename', 'assets/css/custom.css'); $form = Form::BuildFromModel($m); $form->set('callsmethod', 'ThemeController::_SaveEditorHandler'); // I need to add the file as a system element so core doesn't try to reuse the same forms on concurrent edits. //$form->addElement('system', array('name' => 'revision', 'value' => $revision)); $form->addElement('system', array('name' => 'file', 'value' => 'assets/' . $set['file'])); $form->addElement('system', array('name' => 'filetype', 'value' => 'file')); // No one uses this anyways! $form->switchElementType('model[comment]', 'hidden'); $form->getElement('model[content]')->set('id', 'custom_content_' . $k); $form->addElement('submit', array('value' => 'Save Custom CSS')); // Save it back down to the original array $sets[$k]['form'] = $form; } $cssform = $sets[0]['form']; $cssprintform = $sets[1]['form']; } $view->title = 'Theme Manager'; $view->assign('themes', $themes); $view->assign('current', $current); $view->assign('options_form', $optionForm); $view->assign('assets', $nestedassets); $view->assign('templates', $nestedtemplates); $view->assign('url_themeeditor', \Core\resolve_link('/theme/editor')); $view->assign('url_themewidgets', \Core\resolve_link('/theme/widgets')); $view->assign('url_themestylesheets', \Core\resolve_link('/theme/selectstylesheets')); $view->assign('site_skins_form', $siteskinform); $view->assign('cssform', $cssform); $view->assign('cssprintform', $cssprintform); $view->assign('multisite', $multisite); $view->assign('theme_selection_enabled', $themeSelectionEnabled); $view->assign('email_selection_enabled', $emailSelectionEnabled); }
/** * @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, ); }
/** * 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); }