/**
  * 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,
		);
	}
Esempio n. 3
0
	/**
	 * 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);
	}