Fixes #255 - Adds a code editor settings page
Email layouts now work Form fields now support context in their names
This commit is contained in:
parent
12a7e7776b
commit
8b9eb52afd
|
|
@ -1,3 +1,7 @@
|
|||
* **Build x** (2014-06-10)
|
||||
- Form fields can now pass context via their name definnition using syntax `field@context`.
|
||||
- Added a code editor preferences page.
|
||||
|
||||
* **Build 101** (2014-06-06)
|
||||
- Added a global traceLog() helper for help with debugging.
|
||||
- New settings area added to manage Email templates and layouts.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use BackendAuth;
|
|||
use Backend\Classes\WidgetManager;
|
||||
use October\Rain\Support\ModuleServiceProvider;
|
||||
use System\Models\EmailTemplate;
|
||||
use System\Classes\SettingsManager;
|
||||
|
||||
class ServiceProvider extends ModuleServiceProvider
|
||||
{
|
||||
|
|
@ -62,6 +63,22 @@ class ServiceProvider extends ModuleServiceProvider
|
|||
]);
|
||||
});
|
||||
|
||||
/*
|
||||
* Register settings
|
||||
*/
|
||||
SettingsManager::instance()->registerCallback(function($manager){
|
||||
$manager->registerSettingItems('October.Backend', [
|
||||
'editor' => [
|
||||
'label' => 'backend::lang.editor.menu_label',
|
||||
'description' => 'backend::lang.editor.menu_description',
|
||||
'category' => 'System',
|
||||
'icon' => 'icon-code',
|
||||
'class' => 'Backend\Models\EditorSettings',
|
||||
'sort' => 200
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
/*
|
||||
* Register permissions
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
<?php namespace Backend\Behaviors;
|
||||
|
||||
use System\Behaviors\SettingsModel;
|
||||
use Backend\Models\UserPreferences;
|
||||
|
||||
/**
|
||||
* User Settings model extension, identical to System.Behaviors.SettingsModel
|
||||
* except values are set against the logged in user's preferences via Backend\Models\UserPreferences.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* In the model class definition:
|
||||
*
|
||||
* public $implement = ['Backend.Behaviors.UserSettingsModel'];
|
||||
* public $settingsCode = 'author.plugin::code';
|
||||
* public $settingsFields = 'fields.yaml';
|
||||
*
|
||||
*/
|
||||
class UserSettingsModel extends SettingsModel
|
||||
{
|
||||
private static $instances = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($model)
|
||||
{
|
||||
parent::__construct($model);
|
||||
|
||||
$this->model->table = 'backend_user_preferences';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the settings model, intended as a static method
|
||||
*/
|
||||
public function instance()
|
||||
{
|
||||
if (isset(self::$instances[$this->recordCode]))
|
||||
return self::$instances[$this->recordCode];
|
||||
|
||||
$item = UserPreferences::forUser();
|
||||
$item = $item->scopeFindRecord($this->model, $this->recordCode, $item->userContext)->first();
|
||||
|
||||
if (!$item) {
|
||||
$this->model->initSettingsData();
|
||||
$this->model->forceSave();
|
||||
$this->model->reload();
|
||||
$item = $this->model;
|
||||
}
|
||||
|
||||
return self::$instances[$this->recordCode] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the model has been set up previously, intended as a static method
|
||||
*/
|
||||
public function isConfigured()
|
||||
{
|
||||
return UserPreferences::forUser()->findRecord($this->recordCode, $item->userContext)->count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before the model is saved, ensure the record code is set
|
||||
* and the jsonable field values
|
||||
*/
|
||||
public function beforeModelSave()
|
||||
{
|
||||
$preferences = UserPreferences::forUser();
|
||||
|
||||
list($namespace, $group, $item) = $preferences->parseKey($this->recordCode);
|
||||
$this->model->item = $item;
|
||||
$this->model->group = $group;
|
||||
$this->model->namespace = $namespace;
|
||||
$this->model->user_id = $preferences->userContext->id;
|
||||
|
||||
if ($this->fieldValues)
|
||||
$this->model->value = $this->fieldValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a key is legitimate or should be added to
|
||||
* the field value collection
|
||||
*/
|
||||
private function isKeyAllowed($key)
|
||||
{
|
||||
/*
|
||||
* Let the core columns through
|
||||
*/
|
||||
if ($key == 'namespace' || $key == 'group')
|
||||
return true;
|
||||
|
||||
return parent::isKeyAllowed($key);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?php namespace Backend\FormWidgets;
|
||||
|
||||
use Backend\Models\EditorSettings;
|
||||
use Backend\Classes\FormWidgetBase;
|
||||
|
||||
/**
|
||||
|
|
@ -31,6 +32,16 @@ class CodeEditor extends FormWidgetBase
|
|||
*/
|
||||
public $wrapWords = true;
|
||||
|
||||
/**
|
||||
* @var boolean Indicates whether the the editor uses spaces for indentation
|
||||
*/
|
||||
public $useSoftTabs = true;
|
||||
|
||||
/**
|
||||
* @var boolean Sets the size of the indentation
|
||||
*/
|
||||
public $tabSize = 4;
|
||||
|
||||
/**
|
||||
* @var integer Sets the font size
|
||||
*/
|
||||
|
|
@ -51,11 +62,16 @@ class CodeEditor extends FormWidgetBase
|
|||
*/
|
||||
public function init()
|
||||
{
|
||||
// Load the editor system settings
|
||||
$editorSettings = EditorSettings::instance();
|
||||
|
||||
$this->language = $this->getConfig('language', 'php');
|
||||
$this->showGutter = $this->getConfig('showGutter', true);
|
||||
$this->theme = $this->getConfig('theme', 'twilight');
|
||||
$this->wrapWords = $this->getConfig('wrapWords', false);
|
||||
$this->fontSize = $this->getConfig('fontSize', false);
|
||||
$this->theme = $this->getConfig('theme', $editorSettings->theme);
|
||||
$this->wrapWords = $this->getConfig('wrapWords', $editorSettings->use_wrap);
|
||||
$this->fontSize = $this->getConfig('fontSize', $editorSettings->font_size);
|
||||
$this->tabSize = $this->getConfig('tabSize', $editorSettings->tab_size);
|
||||
$this->useSoftTabs = $this->getConfig('useSoftTabs', !$editorSettings->use_hard_tabs);
|
||||
$this->margin = $this->getConfig('margin', 0);
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +95,8 @@ class CodeEditor extends FormWidgetBase
|
|||
$this->vars['showGutter'] = $this->showGutter;
|
||||
$this->vars['wrapWords'] = $this->wrapWords;
|
||||
$this->vars['fontSize'] = $this->fontSize;
|
||||
$this->vars['tabSize'] = $this->tabSize;
|
||||
$this->vars['useSoftTabs'] = $this->useSoftTabs;
|
||||
$this->vars['theme'] = $this->theme;
|
||||
$this->vars['name'] = $this->formField->getName();
|
||||
$this->vars['value'] = $this->model->{$this->columnName};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
data-theme="<?= $theme ?>"
|
||||
data-margin="<?= $margin ?>"
|
||||
data-font-size="<?= $fontSize ?>"
|
||||
data-tab-size="<?= $tabSize ?>"
|
||||
data-use-soft-tabs="<?= $useSoftTabs ?>"
|
||||
data-vendor-path="<?= URL::to('/modules/backend/formwidgets/codeeditor/assets/vendor/ace') ?>/">
|
||||
<div class="editor-toolbar">
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -145,4 +145,15 @@ return [
|
|||
'permissions' => 'Directory :name or its subdirectories is not writable for PHP. Please set corresponding permissions for the webserver on this directory.',
|
||||
'extension' => 'The PHP extension :name is not installed. Please install this library and activate the extension.'
|
||||
],
|
||||
'editor' => [
|
||||
'menu_label' => 'Editor Configuration',
|
||||
'menu_description' => 'Manage editor configuration.',
|
||||
'font_size' => 'Font Size',
|
||||
'tab_size' => 'Indentation Width',
|
||||
'use_hard_tabs' => 'Indent Using Tabs',
|
||||
'use_hard_tabs_comment' => 'Use this checkbox if you would like to use hard tabs instead of spaces.',
|
||||
'use_wrap' => 'Enable Word Wrap',
|
||||
'use_wrap_comment' => 'Use this checkbox if you want your text to wrap instead of overflowing.',
|
||||
'theme' => 'Text Color Scheme',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
<?php namespace Backend\Models;
|
||||
|
||||
use App;
|
||||
use Model;
|
||||
use DirectoryIterator;
|
||||
|
||||
class EditorSettings extends Model
|
||||
{
|
||||
public $implement = ['Backend.Behaviors.UserSettingsModel'];
|
||||
public $settingsCode = 'system::editor.settings';
|
||||
public $settingsFields = 'fields.yaml';
|
||||
|
||||
const DEFAULT_THEME = 'twilight';
|
||||
|
||||
public function initSettingsData()
|
||||
{
|
||||
$config = App::make('config');
|
||||
$this->font_size = $config->get('editor.font.size', 12);
|
||||
$this->tab_size = $config->get('editor.tab.size', 4);
|
||||
$this->use_hard_tabs = $config->get('editor.tab.usehard', false);
|
||||
$this->use_wrap = $config->get('editor.wrap.enable', false);
|
||||
$this->theme = $config->get('editor.theme', static::DEFAULT_THEME);
|
||||
}
|
||||
|
||||
public static function applyConfigValues()
|
||||
{
|
||||
$config = App::make('config');
|
||||
$settings = self::instance();
|
||||
$config->set('editor.font.size', $settings->font_size);
|
||||
$config->set('editor.tab.size', $settings->tab_size);
|
||||
$config->set('editor.tab.usehard', $settings->use_hard_tabs);
|
||||
$config->set('editor.wrap.enable', $settings->use_wrap);
|
||||
$config->set('editor.theme', $settings->theme);
|
||||
}
|
||||
|
||||
public function getThemeOptions()
|
||||
{
|
||||
$themeDir = new DirectoryIterator("modules/backend/formwidgets/codeeditor/assets/vendor/ace/");
|
||||
$themes = [];
|
||||
|
||||
// Iterate through the themes
|
||||
foreach ($themeDir as $node) {
|
||||
|
||||
// If this file is a theme (starting by "theme-")
|
||||
if (!$node->isDir() && substr($node->getFileName(), 0, 6) == 'theme-') {
|
||||
// Remove the theme- prefix and the .js suffix, create an user friendly and capitalized name
|
||||
$themeId = substr($node->getFileName(), 6, -3);
|
||||
$themeName = ucwords(str_replace("_", " ", $themeId));
|
||||
|
||||
// Add the values to the themes array
|
||||
if ($themeId != static::DEFAULT_THEME) {
|
||||
$themes[$themeId] = $themeName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sort the theme alphabetically, and push the default theme
|
||||
asort($themes);
|
||||
return [static::DEFAULT_THEME => 'Twilight'] + $themes;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# ===================================
|
||||
# Field Definitions
|
||||
# ===================================
|
||||
|
||||
fields:
|
||||
font_size:
|
||||
label: backend::lang.editor.font_size
|
||||
span: left
|
||||
|
||||
tab_size:
|
||||
label: backend::lang.editor.tab_size
|
||||
span: right
|
||||
|
||||
theme:
|
||||
label: backend::lang.editor.theme
|
||||
type: dropdown
|
||||
span: full
|
||||
|
||||
use_hard_tabs:
|
||||
label: backend::lang.editor.use_hard_tabs
|
||||
type: checkbox
|
||||
span: full
|
||||
comment: backend::lang.editor.use_hard_tabs_comment
|
||||
|
||||
use_wrap:
|
||||
label: backend::lang.editor.use_wrap
|
||||
type: checkbox
|
||||
span: full
|
||||
comment: backend::lang.editor.use_wrap_comment
|
||||
|
|
@ -16,10 +16,6 @@ After signing in you should change your password by clicking your name on the to
|
|||
You can use the following link to sign in:
|
||||
{{ link }}
|
||||
|
||||
|
||||
---
|
||||
This is an automatic message. Do not reply to it.
|
||||
|
||||
==
|
||||
|
||||
<p>Hi {{ name }},</p>
|
||||
|
|
@ -37,6 +33,3 @@ This is an automatic message. Do not reply to it.
|
|||
You can use the following link to sign in:<br />
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
<strong>This is an automatic message. Do not reply to it.</strong>
|
||||
|
|
@ -9,10 +9,6 @@ Somebody has requested a password reset for your account, if this was not you, p
|
|||
You can use the following link to restore your password:
|
||||
{{ link }}
|
||||
|
||||
|
||||
---
|
||||
This is an automatic message. Do not reply to it.
|
||||
|
||||
==
|
||||
|
||||
<p>Hello {{ name }},</p>
|
||||
|
|
@ -23,6 +19,3 @@ This is an automatic message. Do not reply to it.
|
|||
You can use the following link to restore your password:<br />
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
<strong>This is an automatic message. Do not reply to it.</strong>
|
||||
|
|
@ -353,7 +353,10 @@ class Form extends WidgetBase
|
|||
protected function makeFormField($name, $config)
|
||||
{
|
||||
$label = (isset($config['label'])) ? $config['label'] : null;
|
||||
$field = new FormField($name, $label);
|
||||
list($fieldName, $fieldContext) = $this->getFieldName($name);
|
||||
|
||||
$field = new FormField($fieldName, $label);
|
||||
if ($fieldContext) $field->context = $fieldContext;
|
||||
$field->arrayName = $this->arrayName;
|
||||
$field->idPrefix = $this->getId();
|
||||
|
||||
|
|
@ -473,6 +476,19 @@ class Form extends WidgetBase
|
|||
return $this->formWidgets[$field->columnName] = $widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a field's name
|
||||
* @param stirng $field Field name
|
||||
* @return array [columnName, context]
|
||||
*/
|
||||
public function getFieldName($field)
|
||||
{
|
||||
if (strpos($field, '@') === false)
|
||||
return [$field, null];
|
||||
|
||||
return explode('@', $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the column
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -27,15 +27,15 @@ p {
|
|||
$html = '<html>
|
||||
<head>
|
||||
<style type="text/css" media="screen">
|
||||
{{ css }}
|
||||
{{ css|raw }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{ message }}
|
||||
{{ message|raw }}
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$text = '{{message}}';
|
||||
$text = '{{ message|raw }}';
|
||||
|
||||
EmailLayout::create([
|
||||
'is_locked' => true,
|
||||
|
|
@ -49,17 +49,17 @@ $text = '{{message}}';
|
|||
$html = '<html>
|
||||
<head>
|
||||
<style type="text/css" media="screen">
|
||||
{{ css }}
|
||||
{{ css|raw }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{ message }}
|
||||
{{ message|raw }}
|
||||
<hr />
|
||||
<p>This is an automatic message. Please do not reply to it.</p>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$text = '{{message}}
|
||||
$text = '{{ message|raw }}
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class EmailTemplate extends Model
|
|||
public static function addContentToMailer($message, $code, $data)
|
||||
{
|
||||
if (!isset(self::$cache[$code])) {
|
||||
if (!$template = self::where('is_custom', true)->whereCode($code)->first())
|
||||
if (!$template = self::whereCode($code)->first())
|
||||
return false;
|
||||
|
||||
self::$cache[$code] = $template;
|
||||
|
|
@ -107,9 +107,31 @@ class EmailTemplate extends Model
|
|||
$twig->setLoader(new \Twig_Loader_String);
|
||||
|
||||
$message->subject($twig->render($template->subject, $data));
|
||||
$message->setBody($twig->render($template->content_html, $data), 'text/html');
|
||||
if (strlen($template->content_text))
|
||||
$message->addPart($twig->render($template->content_text, $data), 'text/plain');
|
||||
|
||||
/*
|
||||
* HTML contents
|
||||
*/
|
||||
$html = $twig->render($template->content_html, $data);
|
||||
if ($template->layout) {
|
||||
$html = $twig->render($template->layout->content_html, [
|
||||
'message' => $html,
|
||||
'css' => $template->layout->content_css
|
||||
]);
|
||||
}
|
||||
|
||||
$message->setBody($html, 'text/html');
|
||||
|
||||
/*
|
||||
* Text contents
|
||||
*/
|
||||
if (strlen($template->content_text)) {
|
||||
$text = $twig->render($template->content_text, $data);
|
||||
if ($template->layout) {
|
||||
$text = $twig->render($template->layout->content_text, ['message' => $text]);
|
||||
}
|
||||
|
||||
$message->addPart($text, 'text/plain');
|
||||
}
|
||||
|
||||
$twig->setLoader($oldLoader);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -10,15 +10,12 @@ fields:
|
|||
span: left
|
||||
context: create
|
||||
|
||||
name:
|
||||
name@create:
|
||||
label: system::lang.email_templates.name
|
||||
span: right
|
||||
# context: create
|
||||
|
||||
# @todo Fix duplicate key problem
|
||||
# name:
|
||||
# label: system::lang.email_templates.name
|
||||
# context: update
|
||||
name@update:
|
||||
label: system::lang.email_templates.name
|
||||
|
||||
secondaryTabs:
|
||||
fields:
|
||||
|
|
|
|||
|
|
@ -16,16 +16,13 @@ fields:
|
|||
span: left
|
||||
context: create
|
||||
|
||||
subject:
|
||||
subject@create:
|
||||
label: system::lang.email_templates.subject
|
||||
comment: system::lang.email_templates.subject_comment
|
||||
span: right
|
||||
# context: create
|
||||
|
||||
# @todo Fix duplicate key problem
|
||||
# subject:
|
||||
# label: system::lang.email_templates.subject
|
||||
# context: update
|
||||
subject@update:
|
||||
label: system::lang.email_templates.subject
|
||||
|
||||
description:
|
||||
label: system::lang.email_templates.description
|
||||
|
|
|
|||
Loading…
Reference in New Issue