Adds Theme customization feature
Adds reset button to settings pages authorUrl -> homepage
This commit is contained in:
parent
58b7ee5f7e
commit
70eb7eaf51
|
|
@ -1,3 +1,8 @@
|
|||
* **Build 16x** (2014-12-xx)
|
||||
- Settings pages now have a *Reset to default* button.
|
||||
- The field `authorUrl` has been renamed to `homepage` in theme.yaml files.
|
||||
- Adds Theme customization feature (see Themes > Development docs).
|
||||
|
||||
* **Build 166** (2014-11-27)
|
||||
- Plugin details method now support "homepage" property (see Plugins > Registration & Versions docs).
|
||||
- Fixes a bug in the Datepicker using `time` mode.
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ class FormController extends ControllerBehavior
|
|||
$this->controller->formBeforeSave($model);
|
||||
$this->controller->formBeforeUpdate($model);
|
||||
|
||||
$modelsToSave =$this->prepareModelsToSave($model, $this->formWidget->getSaveData());
|
||||
$modelsToSave = $this->prepareModelsToSave($model, $this->formWidget->getSaveData());
|
||||
foreach ($modelsToSave as $modelToSave) {
|
||||
$modelToSave->save(null, $this->formWidget->getSessionKey());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,6 +155,9 @@ return [
|
|||
'delete' => 'Delete',
|
||||
'deleting' => 'Deleting...',
|
||||
'deleting_name' => 'Deleting :name...',
|
||||
'reset_default' => 'Reset to default',
|
||||
'resetting' => 'Resetting',
|
||||
'resetting_name' => 'Resetting :name',
|
||||
'undefined_tab' => 'Misc',
|
||||
'field_off' => 'Off',
|
||||
'field_on' => 'On',
|
||||
|
|
|
|||
|
|
@ -257,12 +257,7 @@ class Theme
|
|||
*/
|
||||
public function getConfigValue($name, $default = null)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
if (isset($config[$name])) {
|
||||
return $config[$name];
|
||||
}
|
||||
|
||||
return $default;
|
||||
return array_get($this->getConfig(), $name, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
<?php namespace Cms\Controllers;
|
||||
|
||||
use Config;
|
||||
use BackendMenu;
|
||||
use Lang;
|
||||
use Input;
|
||||
use Config;
|
||||
use Backend;
|
||||
use Redirect;
|
||||
use BackendMenu;
|
||||
use Backend\Classes\Controller;
|
||||
use System\Classes\SettingsManager;
|
||||
use Cms\Models\ThemeData;
|
||||
use Cms\Classes\Theme as CmsTheme;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Theme selector controller
|
||||
|
|
@ -16,9 +21,13 @@ use Cms\Classes\Theme as CmsTheme;
|
|||
*/
|
||||
class Themes extends Controller
|
||||
{
|
||||
public $requiredPermissions = ['cms.manage_themes'];
|
||||
public $implement = [
|
||||
'Backend.Behaviors.FormController'
|
||||
];
|
||||
|
||||
public $bodyClass = 'compact-container';
|
||||
public $formConfig = 'config_form.yaml';
|
||||
|
||||
public $requiredPermissions = ['cms.manage_themes'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
|
@ -36,6 +45,7 @@ class Themes extends Controller
|
|||
|
||||
public function index()
|
||||
{
|
||||
$this->bodyClass = 'compact-container';
|
||||
}
|
||||
|
||||
public function index_onSetActiveTheme()
|
||||
|
|
@ -46,4 +56,67 @@ class Themes extends Controller
|
|||
'#theme-list' => $this->makePartial('theme_list')
|
||||
];
|
||||
}
|
||||
|
||||
//
|
||||
// Theme customization
|
||||
//
|
||||
|
||||
public function update($dirName)
|
||||
{
|
||||
try {
|
||||
$model = $this->getThemeData($dirName);
|
||||
$this->asExtension('FormController')->update($model->id);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
$this->handleError($ex);
|
||||
}
|
||||
}
|
||||
|
||||
public function update_onSave($dirName)
|
||||
{
|
||||
$model = $this->getThemeData($dirName);
|
||||
$this->asExtension('FormController')->update_onSave($model->id);
|
||||
}
|
||||
|
||||
public function update_onResetDefault($dirName)
|
||||
{
|
||||
$model = $this->getThemeData($dirName);
|
||||
$model->delete();
|
||||
|
||||
$redirectUrl = Backend::url('cms/themes/update/'.$dirName);
|
||||
return Redirect::to($redirectUrl);
|
||||
}
|
||||
|
||||
protected function getThemeData($dirName)
|
||||
{
|
||||
if (!$theme = CmsTheme::load($dirName))
|
||||
throw new Exception(Lang::get('Unable to find theme with name :name', $dirName));
|
||||
|
||||
$model = ThemeData::firstOrCreate(['theme' => $theme->getDirName()]);
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add form fields defined in theme.yaml
|
||||
*/
|
||||
protected function formExtendFields($form)
|
||||
{
|
||||
$model = $form->model;
|
||||
|
||||
if (!$theme = CmsTheme::load($model->theme))
|
||||
throw new Exception(Lang::get('Unable to find theme with name :name', $dirName));
|
||||
|
||||
if ($fields = $theme->getConfigValue('form.fields')) {
|
||||
$form->addFields($fields);
|
||||
}
|
||||
|
||||
if ($fields = $theme->getConfigValue('form.tabs.fields')) {
|
||||
$form->addTabFields($fields);
|
||||
}
|
||||
|
||||
if ($fields = $theme->getConfigValue('form.secondaryTabs.fields')) {
|
||||
$form->addSecondaryTabFields($fields);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
<?php
|
||||
$isLast = $index == $cnt-1;
|
||||
$isActive = $activeTheme && $activeTheme->getDirName() == $theme->getDirName();
|
||||
$hasForm = $theme->getConfigValue('form');
|
||||
$author = $theme->getConfigValue('author');
|
||||
?>
|
||||
<div class="layout-row <?= $isLast ? 'last' : null ?> min-size <?= $isActive ? 'active' : null ?>">
|
||||
|
|
@ -16,7 +17,7 @@
|
|||
<div class="layout-cell min-height theme-description">
|
||||
<h3><?= e($theme->getConfigValue('name', $theme->getDirName())) ?></h3>
|
||||
<?php if (strlen($author)): ?>
|
||||
<p class="author">by <a href="<?= e($theme->getConfigValue('authorUrl', '#')) ?>"><?= e($author) ?></a></p>
|
||||
<p class="author">by <a href="<?= e($theme->getConfigValue('homepage', '#')) ?>"><?= e($author) ?></a></p>
|
||||
<?php endif ?>
|
||||
<p class="description"><?= e($theme->getConfigValue('description', 'The theme description is not provided.')) ?></p>
|
||||
<div class="controls">
|
||||
|
|
@ -35,9 +36,18 @@
|
|||
data-request-data="theme: '<?= e($theme->getDirName()) ?>'"
|
||||
data-stripe-load-indicator
|
||||
class="btn btn-primary">
|
||||
<i class="icon-check"></i>
|
||||
<?= e(trans('cms::lang.theme.activate_button')) ?>
|
||||
</button>
|
||||
<?php endif ?>
|
||||
<?php if ($hasForm): ?>
|
||||
<a
|
||||
href="<?= Backend::url('cms/themes/update/'.$theme->getDirName()) ?>"
|
||||
class="btn btn-default">
|
||||
<i class="icon-pencil"></i>
|
||||
<?= e(trans('cms::lang.theme.customize_button')) ?>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
# ===================================
|
||||
# Form Behavior Config
|
||||
# ===================================
|
||||
|
||||
# Record name
|
||||
name: Theme
|
||||
|
||||
# Fields are defined by extension
|
||||
form: []
|
||||
|
||||
# Model Class name
|
||||
modelClass: Cms\Models\ThemeData
|
||||
|
||||
# Default redirect location
|
||||
defaultRedirect: cms/themes
|
||||
|
||||
# Update page
|
||||
update:
|
||||
title: Customize Theme
|
||||
redirect: cms/themes
|
||||
redirectClose: cms/themes
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('cms/themes') ?>">Themes</a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class'=>'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="Saving theme..."
|
||||
class="btn btn-primary">
|
||||
<u>S</u>ave
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="Saving theme..."
|
||||
class="btn btn-default">
|
||||
Save and Close
|
||||
</button>
|
||||
|
||||
<span class="btn-text">
|
||||
or <a href="<?= Backend::url('cms/themes') ?>">Cancel</a>
|
||||
</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger pull-right"
|
||||
data-request="onResetDefault"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.resetting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
|
||||
<?= e(trans('backend::lang.form.reset_default')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
<p><a href="<?= Backend::url('cms/themes') ?>" class="btn btn-default">Return to themes list</a></p>
|
||||
|
||||
<?php endif ?>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class DbCmsThemeData extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('cms_theme_data', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('theme')->nullable()->index();
|
||||
$table->mediumtext('data')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('cms_theme_data');
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ return [
|
|||
'find_more_themes' => 'Find more themes on OctoberCMS Theme Marketplace.',
|
||||
'activate_button' => 'Activate',
|
||||
'active_button' => 'Activate',
|
||||
'customize_button' => 'Customize',
|
||||
],
|
||||
'maintenance' => [
|
||||
'settings_menu' => 'Maintenance mode',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
<?php namespace Cms\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Customization data used by a theme
|
||||
*
|
||||
* @package october\cms
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class ThemeData extends Model
|
||||
{
|
||||
// use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'cms_theme_data';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array List of attribute names which are json encoded and decoded from the database.
|
||||
*/
|
||||
protected $jsonable = ['data'];
|
||||
|
||||
public function beforeSave()
|
||||
{
|
||||
/*
|
||||
* Dynamic attributes are stored in the jsonable attribute 'data'.
|
||||
*/
|
||||
$staticAttributes = ['id', 'theme', 'data'];
|
||||
$dynamicAttributes = array_except($this->getAttributes(), $staticAttributes);
|
||||
|
||||
$this->data = $dynamicAttributes;
|
||||
$this->setRawAttributes(array_only($this->getAttributes(), $staticAttributes));
|
||||
}
|
||||
|
||||
public function afterFetch()
|
||||
{
|
||||
/*
|
||||
* Fill this model with the jsonable attributes kept in 'data'.
|
||||
*/
|
||||
$this->setRawAttributes((array) $this->getAttributes() + (array) $this->data, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +83,18 @@ class SettingsModel extends ModelBehavior
|
|||
return self::$instances[$this->recordCode] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the settings to their defaults, this will delete the record model
|
||||
*/
|
||||
public function resetDefault()
|
||||
{
|
||||
if ($record = $this->getSettingsRecord()) {
|
||||
$record->delete();
|
||||
unset(self::$instances[$this->recordCode]);
|
||||
Cache::forget($this->getCacheKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the model has been set up previously, intended as a static method
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -111,6 +111,16 @@ class Settings extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
public function update_onResetDefault($author, $plugin, $code = null)
|
||||
{
|
||||
$item = $this->findSettingItem($author, $plugin, $code);
|
||||
$model = $this->createModel($item);
|
||||
$model->resetDefault();
|
||||
|
||||
$redirectUrl = Backend::url('system/settings/update/'.$author.'/'.$plugin.'/'.$code);
|
||||
return Redirect::to($redirectUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the form.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,15 @@
|
|||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('system/settings') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger pull-right"
|
||||
data-request="onResetDefault"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.resetting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
|
||||
<?= e(trans('backend::lang.form.reset_default')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
|
|
|||
Loading…
Reference in New Issue